IRCv3 3.1 base extensions + away-notify #27
This is an implementation of IRCv3 with capability negotiation support + base extensions + away-notify.
irc-api is modified to allow for providing capability negotiators and there are a number of negotiators implemented by default.
The CompositeNegotiator may be provided with a list of capabilities, which will all be negotiated, and a host interface to which will be called back with the negotiation result.
This implementation assumes that the client application is the primary user of IRCv3's features and therefore irc-api does not do the actual negotiation. This way you can add capabilities to negotiate for even if irc-api does not support these. If these capabilities extend existing IRC commands, you may need to add support to irc-api, however for any new commands and features, you can just handle those in the client application itself. (In a previous commit, an UnknownMessage message type was added, so you are able to handle messages not known by irc-api.)
Additionally, irc-api is modified to handle multiple prefixes in NAMES / WHO messages. Therefore, if 'multi-prefix' extension is enabled, irc-api will be able to make use of the extra information. Most notably, by providing all relevant IRC user modes, instead of just the one that was communicated.
Lastly, an AwayMessage type is created and handling of these messages is provided. If 'away-notify' is negotiated and supported by IRC server, then enabling this, will allow irc-api to transparently handle Away-messages and notify listeners via the onAwayMessage event. For irc-api there is nothing to do apart from routing the message to listeners via the correct event.
With this PR, there is support for IRCv3 3.1 base extensions + away-notify at the very least. Other extensions may work out-of-the-box as most of them need to be handled by the client application anyway, but the lower bound is IRCv3 3.1 so far.
Let me know what you think. Any feedback is welcome.
A basic implementation of CAP (capability) negotiation. This implementation adds a mechanism for providing an "external" negotiator. The negotiator will be called before registering with the IRC server in order to query the desired CAP init command. Then, if a negotiator is provided, it will be registered as a general message handler, such that it can keep track of messages that are communicated. As irc-api itself does not support CAP messages, it is expected that the CapabilityNegotiator instance will then take over and handle CAP negotiations. Once CAP END is sent, normal registration procedure will take over and the server will send msg 001 and continue with normal registration procedure.
… of the states. A simplistic implementation that tries to keep strict states by implementing each state in its own subclass and throwing IllegalStateExceptions for all operations that are not allowed in the current state. Improvements are pending that make the state machine in itself more intelligent such that the logic is in the state itself. This will make error handling easier as knowledge of the current state is available.
States now communicate themselves. Not sure how to handle fail() messages: do nothing, abort, retry with preconstructed prepare message, ...? Plus some other outstanding TODOs/FIXMEs.
While looking into other authentication mechanisms for IRC sasl extension, there appear to be a number of other options available. These mechanisms provide additional security in some kind or another. But there's still some discussion going on about what is most reliable, so for now I'll leave some notes only.
… capabilities. An initial implementation of a composite negotiator that can do the negotiation for a list of basic capabilities. Basic capabilities are capabilities which can only be turned on or off and do not require additional conversation with the IRC server itself. The implementation supports acked capabilities and will automatically send the client ACK in case this is required by the IRC server.
Lots of changes: * Support for capability conversations. * New SimpleCapability for simple binary (enable/disable) capabilities. * New SASL capability for use in CompositeNegotiator with other capabilities. * Migrated SASL state machine to separate class SaslStateMachine. * Simplified SASL state machine: dropped intermediate state that really belonged to the CAP negotiation not SASL negotiation. * Introduced Relay type for limited access to IRC server for capabilities * Fixed bug where requestedCapabilities would use wrong collection for deriving requestable capabilities.
…edback of connection failure in case of connection cut off during IRC registration process.
IRCv3 3.1 defines the capability away-notify. This capability provides a switch to enable away notifications for all channel members that you share a channel with. irc-api is modified to be able to handle this message in its message handling infrastructure. A new event 'onUserAway' is defined for handling away notifications.
1. Clean up a number of FIXMEs. 2. Fine tuning of SASL capability for various server responses. Be more specific in waiting for server message after fail() call and stop converstaion after ERR_SASLABORTED, ERR_SASLALREADY 3. End capability negotiation if ServerNumericMessage 001 is encountered. (And log encounter.) 4. Make better use of logging API to prevent unnecessary string concat. 5. Created RawMessageUtils for some basic utility methods on raw IRC messages. 6. Now mutates this.requested in CompositeNegotiator in order to detect whether all requested capabilities have been acknowledged. Until this list is empty, assume that server will send additional messages containing the remaining this.requested capabilities. 7. Added warning in case CAP REQ message is too large. Multiple request are not supported yet, but at least it does not go unnoticed. 8. Removed use case of "lost" capability, instead assume that another CAP ACK messages is coming which contains this capability. 9. Added TODO for special exception that would signal aborting IRC registration process. This can be used (among others) by SASL capability to signal aborting in case of failed SASL authentication and authentication is a prerequisite for IRC connection.
…nes. The previous method for encoding to base64 would automatically include newlines for readability. Now using the byte variant which only does "raw" encoding.
1. SaslContext is more strict: does not allow fail() abort() before init() is called. 2. Moved information on SASL authentication choices to SaslContext class, as it is more appropriate there. 3. Modified behaviour in SaslNegotiator in some error handling cases. 4. Added more tests.
Restored the original connect(...) method to not break backwards compatibility. Also added a significant amount of documentation to refer to the various negotiators that can be used upon connecting and explained the semantics of a null negotiator.