= KtIrc {version} Chris Smith :version: 1.1.1 :toc: left :toc-position: left :toclevels: 5 == About KtIrc KtIrc is a Kotlin JVM library for connecting to and interacting with IRC servers. It is still in an early stage of development. Its main features: .Built for Kotlin KtIrc is written in and designed for use in Kotlin; it uses extension methods, DSLs, sealed classes, and so on, to make it much easier to use than an equivalent Java library. .Coroutine-powered KtIrc uses co-routines for all of its input/output which lets it deal with IRC messages in the background while your app does other things, without the overhead of creating a new thread per IRC client. .Modern IRC standards KtIrc supports many IRCv3 features such as SASL authentication, message IDs, server timestamps, replies, reactions, account tags, and more. These features (where server support is available) make it easier to develop bots and clients, and enhance IRC with new user-facing functionality. == Getting started === Installing All you need to do to start using KtIrc is add a single dependency. KtIrc is published to JCenter, making it quick and easy to pull in to almost any project. The examples below show how to add the JCenter repository and then the KtIrc dependency; you may already be using JCenter for other dependencies -- in that case just skip the repository configuration! [TIP] ==== KtIrc adheres to semantic versioning: you can expect to upgrade between minor versions without problems (e.g. from `0.1.2` to `0.13.7`); major version changes may include breaking changes such as the removal of deprecated methods. You should check the changelog before updating to a new major version. ==== .Gradle (using Kotlin DSL) [source,kotlin,subs="attributes"] ---- repositories { jcenter() } dependencies { implementation("com.dmdirc:ktirc:{version}") } ---- .Gradle (using Groovy DSL) [source,groovy,subs="attributes"] ---- buildscript { repositories { jcenter() } } implementation 'com.dmdirc:ktirc:{version}' ---- .Maven [source,xml,subs="attributes"] ---- <repositories> <repository> <id>jcenter</id> <url>https://jcenter.bintray.com</url> </repository> </repositories> <dependencies> <dependency> <groupId>com.dmdirc</groupId> <artifactId>ktirc</artifactId> <version>{version}</version> </dependency> </dependencies> ---- === Creating your first client KtIrc provides a DSL ("domain specific language") for configuring a client that allows you to set the connection details, the user's details, and configure the behaviour of KtIrc itself. The DSL is accessed through the `IrcClient` function. For full details of all supported options, see the <> reference. A basic client will look like this: [source,kotlin] ---- val client = IrcClient { server { host = "my.server.com" } profile { nickname = "nick" username = "username" realName = "Hi there" } } ---- === Connecting and handling events Getting KtIrc to start connecting is as simple as calling the `connect()` method, but before that we probably want to add an event listener to deal with incoming messages: [source,kotlin] ---- client.onEvent { event -> <1> when (event) { <2> is ServerReady -> client.sendJoin("#ktirc") <3> is ServerDisconnected -> client.connect() is MessageReceived -> if (event.message == "!test") <4> client.reply(event, "Test successful!") <5> } } client.connect() <6> ---- <1> An event listener is registered using the `onEvent` method. It receives a single IrcEvent. <2> A Kotlin `when` statement provides a convenient way to switch on the type of event received. <3> Most common IRC commands have `send` methods defined to quickly and safely send the message with the right formatting. <4> Kotlin smart-casts the event, so you can access the properties specific to the matched event class, such as `message`. <5> The IrcClient class provides useful methods to react and respond to events. <6> The connect() method starts connecting and returns immediately. You'll receive events updating you on the progress. In this example, we're waiting for three events: `ServerReady`, which occurs after we have connected and the server has sent us all of the pre-amble such as its configuration and capabilities; `ServerDisconnected` which is raised whenever KtIrc gets disconnected from (or fails to connect to) the IRC server; and `MessageReceived` which occurs, unsuprisingly, whenever a message is received. KtIrc has many events: for more information, see the <> reference. [CAUTION] ==== With this code, KtIrc will immediately try to reconnect as soon as it is disconnected. If the server closes the connection early (due to, for example, a bad password or the user being banned) this will result in a huge number of connection attempts in a short time. In real code you should always delay reconnections -- preferably with a backoff -- to avoid excessive connection attempts. ==== You can see that KtIrc provides a number of useful methods for sending requests to the server, and reacting and responding to events. IRC commands that KtIrc supports can be invoked using the `send*` methods, which are documented in the <> reference. Other useful methods such as `reply` can be found in the <> reference. === Mandatory event handling In order to properly connect to IRC, stay connected, and handle incoming messages properly, the following events MUST be handled: .<> The nickname change required event occurs when connecting to a server if our initial nickname is taken. A new nickname must be supplied to continue connecting. .<> When KtIrc becomes disconnected from a server, or fails a connection attempt, it will raise this event. If you wish to stay connected to IRC you must call the `connect()` method to start a reconnection attempt after an appropriate delay. .<> On servers that support the IRCv3 batch capability, some incoming messages may be sent inside a batch. These could include join or quit messages during a netsplit, or other important messages you may need to process. At minimum, when receiving a BatchReceived event you should apply your normal processing to all the events contained within. == IrcClient DSL The DSL for creating a new `IrcClient` allows you to set a number of options relating to how KtIrc connects, what user details it provides, and how it behaves. The full range of options available in the DSL is shown below: [source,kotlin] ---- server { host = "irc.example.com" port = 6667 useTls = true password = "H4ckTh3Pl4n3t" } profile { nickname = "MyBot" username = "bot" realName = "Botomatic v1.2" } behaviour { requestModesOnJoin = true alwaysEchoMessages = true } sasl { mechanisms += "PLAIN" username = "botaccount" password = "s3cur3" } ---- === Server settings The server block allows you to specify the details of the IRC server you wish to connect to: * `host` - the hostname or IP address of the server *(required)* * `port` - the port to connect on _(default: 6697)_ * `useTls` - whether to use a secure connection or not _(default: true)_ * `password` - the password to provide to the server _(default: null)_ An alternative more compact syntax is available for configuring server details: [source,kotlin] ---- server("irc.example.com", 6667, true, "H4ckTh3Pl4n3t") ---- You can, if you wish, combine the two or use named parameters: [source,kotlin] ---- server(useTls = true, port = 6697) { host = "irc.example.com" password = "H4ckTh3Pl4n3t" } ---- === User profile The user profile controls how KtIrc will present itself to the IRC server, and how other users on that server will see the KtIrc user: * `nickname` - the initial nickname you wish to use *(required)* * `username` - the "username" to provide to the server _(default: KtIrc)_ * `realName` - the "real name" that will be seen by other clients _(default: KtIrc User)_ [TIP] ==== The "username" is sometimes called the "ident" or "gecos". Some IRC servers will check for an ident reply from your host and use that in place of the username provided if it gets a response. The username (or ident reply) becomes part of your client's hostmask, and is visible to other users. It is unrelated to nickserv or other account usernames. ==== As with the <> you can use a more compact syntax: [source,kotlin] ---- profile("nickname", "username", "real name") ---- === Behaviour The behaviour block allows you to tweak how KtIrc itself operates. These options allow you perform common operations automatically, or enjoy more advanced IRC features even if the server doesn't support them: * `requestModesOnJoin` - if enabled, automatically requests channel modes when the client joins a new channel _(default: false)_ * `alwaysEchoMessages` - if enabled, every message you send will result in a `MessageReceived` event being returned. Servers that support the IRCv3 `echo-message` capability will do this automatically; enabling the behaviour will make all servers act the same way _(default: false)_ * `preferIPv6` - if enabled, KtIrc will prefer to connect over IPv6 if the server publishes AAAA DNS records. If disabled, KtIrc will prefer IPv4. If the server is available exclusively on IPv4 or IPv6 then this option has no effect. _(default: true)_ The behaviour block is optional in its entirety. === SASL configuration SASL ("Simple Authentication and Security Layer") is a standard mechanism for securely authenticating to a service that has recently been adopted for use in IRC. SASL supports a number of 'mechanisms' that describe how the data will be exchanged between the client and server. KtIrc supports the following mechanisms: * `EXTERNAL` - the server uses some external means to authenticate the client, instead of a username and password. On most servers this means checking the client certificate against one registered with the user's account. _(disabled by default)_ * `PLAIN` - the client sends the username and password in plain text during the connection phase. This offers slightly more security than calling `nickserv identify` (for example) after connecting. * `SCRAM-SHA-1` - this mechanism involves a "salted challenge" being completed which results in both the server and the client proving that they know the user's password, but without it every being transmitted. This is based on the `SHA-1` algorithm which has known issues, but is more than sufficient when used in this manner. * `SCRAM-SHA-256` - the same as `SCRAM-SHA-1` but using the `SHA-256` algorithm instead, which is more modern and secure. To use `PLAIN`, `SCRAM-SHA-1` or `SCRAM-SHA-256`, you must supply a username and password in the configuration: [source,kotlin] ---- sasl { username = "botaccount" password = "s3cur3" } ---- KtIrc enables `SCRAM-SHA-256`, `SCRAM-SHA-1` and `PLAIN` by default, and will use them in that order of preference if the server supports more than one. You can modify the `mechanisms` parameter if you wish to disable one: [source,kotlin] ---- sasl { mechanisms -= "PLAIN" username = "botaccount" password = "s3cur3" } ---- You can also clear all the default mechanisms and provide your own list: [source,kotlin] ---- sasl { mechanisms("SCRAM-SHA-256", "PLAIN") username = "botaccount" password = "s3cur3" } ---- If you wish to enable the `EXTERNAL` mechanism, you do not need to provide a username or password: [source,kotlin] ---- sasl { mechanisms("EXTERNAL") } ---- Alternatively, if you wish to enable `EXTERNAL` but fall back to other mechanisms if it doesn't work: [source,kotlin] ---- sasl { mechanisms += "EXTERNAL" username = "botaccount" password = "s3cur3" } ---- The SASL block is optional in its entirety. == State KtIrc attempts to track all reasonable state of the IRC network. This includes details about the server, channels the client is joined to, and users that are also in those channels. The state is exposed in a several fields accessible from the `IrcClient`: === ServerState The server state provides information about the server, and our connection to it. [IMPORTANT] ==== The server state will be updated frequently while KtIrc is connecting to a server. The values within it should not be relied upon until a `ServerReady` event is received, as they may be incomplete or estimates before then. ==== .serverState.status (ServerStatus) Provides an enum containing the current server state. One of: * `Disconnected` - the server is not connected * `Connecting` - we are attempting to establish a connection * `Negotiating` - we are logging in, negotiating capabilities, etc * `Ready` - we are connected and commands may be sent .serverState.localNickname (String) [DEPRECATED] The current nickname we are using on the IRC server. While connecting this will default to the nickname from the <>, but it may be updated if e.g. the nick is in use or not allowed. [WARNING] ==== This property is deprecated in favour of the <> property of `IrcClient`. You should migrate to using `localUser.nickname` in place of `serverSate.localNickname`. ==== .serverState.serverName (String) The name the server uses for itself. While connecting this defaults to the hostname given in the <>, but it will be updated to the value provided by the server. For example, you may connect to `irc.example.com` and during the negotiation phase KtIrc will see that it is actually talking to `server3.uk.irc.example.com` and update the serverName to reflect that. [TIP] ==== For a user-friendly identifier most servers provide a `NETWORK` token in the ISUPPORT reply, which is available via the <> property. ==== .serverState.channelModePrefix (ModePrefixMapping) Provides a mapping from channel user modes (such as "o" for op, "v" for voice) to the prefixes used before nicknames (such as "@" and "+"). To map prefixes to modes, you can use the `getMode()` or `getModes()` functions: [source,kotlin] ---- getMode('@') == 'o' getModes("@+") == "ov" ---- .serverState.channelTypes (String) Contains the types of channels that are allowed by the server, such as `\#&` for normal channels ("#") and local channels ("&"). ==== Capabilities The IRCv3 specifications introduce the concept of 'capability negotiation'. This allows the client and server to negotiate and enable new capabilities that are mutually supported. The capabilities state contains the following properties: .serverState.capabilities.negotiationState (CapabilitiesNegotiationState) The current state of negotiating with the server. One of: * `AWAITING_LIST` - we have requested a list of capabitilies and are awaiting a reply * `AWAITING_ACK` - we have sent the capabilities we want to enable, and are waitin for the server to acknowledge them * `AUTHENTICATING` - we are attempting to authenticate with SASL * `FINISHED` - we have completed negotiation Where a server does not support IRCv3 capability negotiation, the state will remain at `AWAITING_LIST`. .serverState.capabilities.advertisedCapabilities (Map) Contains a map of capability names to values that the server offered. This should only be required for advance use cases, such as looking up the languages offered by a server when providing the user with a choice of translations. .serverState.capabilities.enabledCapabilities (Map) Contains a map of capabilities that KtIrc has successfully negotiated with the server. ===== Supported capabilities * `sasl` - used to perform SASL authentication during connection * `message-tags` - allows arbitrary tags on messages * `server-time` - the server adds a timestamp tag to each incoming message * `account-tag` - the server adds an account tag to incoming user messages * `userhost-in-names` - the NAMES reply includes users hosts not just nicknames * `multi-prefix` - all modes are included in nick prefixes (e.g. `@+nick`) * `extended-join` - more information is sent when a user joins a channel * `batch` - allows multi-line responses to be batched together * `echo-message` - echos the client's own messages back to it * `draft/labeled-responses` - responses are labeled so the client knows which incoming message corresponds to which command it sent * `account-notify` - the server sends a message when a user's account changes * `away-notify` - the server sends a message when a user's away state changes * `chghost` - the server sends a message when a user's host changes ==== Features Features are KtIrc's way of exposing the information the server declares in its ISUPPORT messages. These describe how the server is configured, and what limits are placed on clients. You access features using the `features` map in the server state: [source,kotlin] ---- ircClient.serverState.features[ServerFeature.Network] ---- The following features are available: * `Network` - the name of the network the server belongs to __(String?)__ * `ServerCaseMapping` - the current case mapping of the server __(CaseMapping!)__ * `Modeprefixes` - the user mode prefix mapping (e.g. ov to @+) __(ModePrefixMapping!)__ * `MaximumChannels` - the maximum number of channels a user can join __(Int?)__ * `ChannelModes` - the modes supported in channels __(Array?)__ * `ChannelTypes` - the types of channel supported (e.g. "#&") __(String!)__ * `MaximumChannelNameLength` - how long channel names may be __(Int!)__ * `WhoxSupport` - whether the server supports extended whos ("WHOX") __(Boolean!)__ [NOTE] ==== If the server does not define a feature, KtIrc will either fall back to a default value based on the IRC RFCs or common practice (for those features identified with a non-null type such as `Int!` or `String!`); otherwise the value of the feature will be `null` (such as for those identified as `Int?` or `String?` types). ==== === UserState The client's UserState object tracks the details of all users in common channels. It can be used to find the most up-to-date and comprehensive information for those users, as well as the set of channels that we share with them. The UserState is accessed via the `userState` property of IrcClient and acts as a map, accessible using either a nickname or a `User` object: [source,kotlin] ---- ircClient.userState["acidBurn"] val user: User = myIrcEvent.user ircClient.userState[user] ---- The UserState returns a `KnownUser` object which exposes a `details` property containing the <> details, and a `channels` property containing the common channel names. You can also use the `in` operator to check if the user is in a channel: [source,kotlin] ---- ircClient.userState["acidBurn"]?.let { knownUser -> <1> val accountName = knownUser.account val inChannel = "#channel" in knownUser <2> val allChannels = knownUser.channels <3> } ---- <1> If the user isn't known, the call to `get` (using the `[]` operator) returns null, so we use a `let` statement to deal only with the case that the user is found. <2> Check if the user is present on the common channel `#channel`. If the KtIrc client is not joined to that channel, it will always return false. You can also use the `contains("#channel")` method instead of the `in` operator. <3> Returns all common channels we share with the user; will never include channels that the KtIrc client is not joined to. ==== User User objects have the following properties: * `nickname` - the current nickname of the user, always set * `ident` - the ident (username/"gecos") of the user, if known (null otherwise) * `hostname` - the hostname of the user, if known (null otherwise) * `account` - the account of the user, if known (null if account unknown, or user not registered) * `realName` - the real name of the user, if known (null otherwise) * `awayMessage` - the away message of the user, if known (null if away state unknown, or user not away) === LocalUser Contains a <> instance corresponding to our own details on the IRC network. This is the same instance that would be returned from `ircClient.userState[nickname]` for the current nickname. While connecting this will default to a User with only a nickname, which will be taken from the <>. It will be updated as more information is received from the IRC server. === ChannelState The ChannelState keeps track of the state for all channels that the client is joined to. It is indexed by channel name: [source,kotlin] ---- ircClient.channelState["#ktirc"] ---- Each channel's state contains the following properties: * `receivingUserList` - boolean value indicating whether we are in the process of receiving the list of users for the channel. If we are, the `users` property will be incomplete. * `modesDiscovered` - boolean value indicating whether we have received the full set of modes set on the channel. The `requestModesOnJoin` <> allows you to make KtIrc request these automatically. * `topic` - a ChannelTopic object representing the current channel topic. If no topic is set, then a ChannelTopic with `null` properties will be provided. * `users` - a map of all known users in the channel, see <> for more information * `modes` - A map of the current channel modes and their values. Only complete if `modesDiscovered` is true. ==== Channel users Channel users are accessed using the `users` property, which provides an iterable map of nickname to `ChannelUser`. Each `ChannelUser` contains the nickname and current modes for that user. To get further details about a user, such as their hostmask or real name, you should query the <> with the given nickname. [source,kotlin] ---- ircClient.channelState["#ktirc"]?.users?.forEach { user -> println("${user.nickname} has modes ${user.modes}") } ---- == Events Incoming lines from the IRC server are converted by KtIrc to subclasses of `IrcEvent`. These, along with other more advance events, are then published to users of the client using the `onEvent` method in `IrcClient`. All events extend `IrcEvent`, which offers a single `metadata` property. This contains details related to the event: * `time` - the time at which the message occurred (if the server supports the `server-time` capability), or the time at which we received it. Always present. * `batchId` - an opaque string identifier for the batch the message is part of (if the server supports the `batch` capability). Null for messages not in a batch. * `messageId` - a unique, opaque string identifier for the message if the server supports the `msgid` tag. Null otherwise. * `label` - a unique, opaque string identifier that ties a message to a labelled command that was sent by KtIrc, if the server supports the `labelled-replies` capability. Null otherwise. Several specialised versions of `IrcEvent` are used which allow for easier processing: .TargetedEvent A `TargetedEvent` is one that is targeted at either a user or a channel. `TargetedEvent` exposes a string `target` property that identifies the target of the message. This allows you to direct messages to the right handler or UI component more easily: [source,kotlin] ---- ircClient.onEvent { event -> when (event) { is TargetedEvent -> dispatchEvent(event.target, event) } } ---- .SourcedEvent A large number of events come from a remote IRC user, and it can be useful to handle these in the same way. KtIrc offers a `SourcedEvent` interface for all events that originate from a user, and it exposes a single `user` property: [source,kotlin] ---- ircClient.onEvent { event -> when (event) { is SourcedEvent -> notifyAboutUserActivity(event.user) } } ---- .ChannelMembershipAdjustment A number of events describe how the membership of a channel changes -- namely, joins, parts, quits, kicks, names replies, and nick changes. All of these events implement the `ChannelMembershipAdjustment` interface which reduces the amount of logic you need to do if you wish to maintain a membership list (for example in a UI). The interface exposes three properties: * `addedUser` - a single nickname to be added _(String)_ * `removedUser` - a single nickname to be removed _(String)_ * `replacedUsers` - a list of nicknames to replace any existing ones with _(Array)_ All the properties are nullable, and most events will only populate one of the three. === Server events ==== ServerConnecting * Type: IrcEvent * Properties: _(none)_ This event is raised by KtIrc as soon as it starts attempting to connect to a server. It will be followed by either a <> or a <> event at some point. ==== ServerConnected * Type: IrcEvent * Properties: _(none)_ This event is raised by KtIrc when it has connected to the server, and is starting the process of registering, negotiating capabilities, etc. The server will *not* yet be ready for use - a <> event will follow once all of the initial setup has completed. ==== ServerConnectionError * Type: IrcEvent * Properties: ** `error`: `ConnectionError` - the type of error that occurred ** `details`: `String?` - information about the error, if available This event is raised by KtIrc when a problem occurred while connecting to the server. The `ConnectionError` enum will provide the cause of the error, if known: * `UnresolvableAddress` - the hostname provided could not be resolved to an IP address * `ConnectionRefused` - the server did not answer a connection request on the given port * `BadTlsCertificate` - there was an issue with the TLS certificate the server presented (e.g. it was out of date, for the wrong domain, etc) * `Unknown` - the exact cause of the error isn't known This event will be followed by a <> event. ==== ServerWelcome * Type: IrcEvent * Properties: ** `server`: `String` - the name the server supplied for itself ** `localNick`: `String` - the nickname the server says we are using This event is raised in response to the server sending a 001 WELCOME message. It contains the name that the server supplied for itself (for example, KtIrc may connect to a round-robin address like `irc.example.com` and the server it actually connects to then identifies itself as `node3.uk.irc.example.com`), and the nickname that the server says we are using. ==== ServerReady * Type: IrcEvent * Properties: _(none)_ This event is raised by KtIrc when it has connected to a server, registered with the IRC network, and received all of the server's initial data describing its configurations and its features. At this point it is safe to start issuing commands, checking state, joining channels, etc. ==== ServerDisconnected * Type: IrcEvent * Properties: _(none)_ Raised in all cases where KtIrc has attempted to connect to an IRC server and has now been disconnected. KtIrc will not automatically attempt to reconnect; the `connect()` method should be called again after an appropriate delay. NOTE: All of KtIrc's internal state, such as details about users and channels, will be reset when disconnected from the server. State should not be queried until a new <> event has been received, at which point it will have been recreated. ==== MotdLineReceived * Type: IrcEvent * Properties: ** `line`: `String` - the line of the message of the day that was received ** `first`: `Boolean` - true if the line is the first one received The MotdLineReceived event is raised whenever the server sends a single line of its Message of the Day. The `first` parameter is set on the first line of the MOTD so that special formatting or UI handling can be applied. When the MOTD is finished, a <> event is raised. ==== MotdFinished * Type: IrcEvent * Properties: ** `missing`: `Boolean` - indicates the MOTD was missing This event occurs in two circumstances: when the server has sent a series of <> events and has reached the end of the Message of the Day; or when the server has no MOTD to send and informs the client that the MOTD is missing. === Channel events NOTE: Many events such as <> apply to both channels and users. These are documented in the <> category. ==== ChannelJoined * Type: IrcEvent, TargetedEvent, SourcedEvent, ChannelMembershipAdjustment * Properties: ** `user`: `User` - the user that joined the channel ** `target`: `String` - the channel that was joined Raised whenever a user joins a channel, including the KtIrc client. You can determine whether the join applies to another user or the local client using the <> utility method. When the local client joins a new channel, this event will typically be followed by one or more <> events, then <>, <> and if the `requestModesOnJoin` <> is enabled a <> event. ==== ChannelJoinFailed * Type: IrcEvent, TargetedEvent * Properties: ** `target`: `String` - the channel that we tried to join ** `reason`: `JoinError` - the error that prevented us from joining The ChannelJoinFailed event is raised when we attempt to join a channel but the server doesn't allow us to do so. The reason parameter enumerates the possible problems: * `TooManyChannels` - we are already in the maximum number of channels allowed by the server. * `NoHiding` - the channel is no-hiding (+H), but we have invisible join/parts enabled. * `NeedKey` - the channel is keyed (+k) and a valid key was not provided * `NeedInvite` - the channel is invite only (+i) and no invite was received. * `NeedRegisteredNick` - the channel is limited to registered users only, and we are not registered. * `NeedTls` - the channel is secure-only, and we're not using TLS. * `NeedAdmin` - the channel is limited to server admins and we are not one. * `NeedOper` - the channel is limited to ircops and we are not one. * `Banned` - we are banned from the channel. * `ChannelFull` - the channel is limited (+l) and currently full. * `BadChannelName` - the channel name is disallowed by the server. * `Throttled` - we're trying to joiin too many channels and have been throttled. * `Unknown` - we don't know why. [WARNING] ==== ChannelJoinFailed events are generated on a _best-effort_ basis by KtIrc. Error handling on IRC is very poorly standardised, and varies wildly between server implementations. For example, trying to join a secure-only channel on an ircd-seven server will send a NOTICE to the user instead of an error response, so no `ChannelJoinFailed` event will be raised. When tracking whether a join suceeded or failed you should combine monitoring for the response with a reasonable timeout, and assume failure if the timeout lapses without a <> or <> event occurring. ==== ==== ChannelParted * Type: IrcEvent, TargetedEvent, SourcedEvent, ChannelMembershipAdjustment * Properties: ** `user`: `User` - the user that parted the channel ** `target`: `String` - the channel that was parted ** `reason`: `String` - the user-supplied reason for parting Raised when any user parts a channel that we are on. Users can supply a reason when parting a channel; if they have done so the `reason` property will be non-empty. ==== ChannelUserKicked * Type: IrcEvent, TargetedEvent, SourcedEvent, ChannelMembershipAdjustment * Properties: ** `user`: `User` - the user that performed the kick ** `victim`: `String` - the nickname of the user that was kicked ** `target`: `String` - the channel that the victim was kicked from ** `reason`: `String` - the user-supplied reason for kicking This event occurs when a user is kicked (forcibly removed) from a channel. NOTE: The `user` is the one performing the kick, and will remain in the channel. The `victim` is the one being forcibly ejected. ==== ChannelQuit * Type: IrcEvent, TargetedEvent, SourcedEvent, ChannelMembershipAdjustment * Properties: ** `user`: `User` - the user that quit ** `target`: `String` - the channel that the user was in ** `reason`: `String` - the user-supplied reason for quitting After a <> event, KtIrc will "fan out" the event to all of the channels that we share with the user and raise a `ChannelQuit` event for each channel. This is designed to make implementing certain features easier; if you fully handle a UserQuit event there is no need to also handle the ChannelQuit events, and vice-versa. Users and servers can supply a reason when a user quits; if supplied then the `reason` parameter will be non-empty. ==== ChannelNickChanged * Type: IrcEvent, TargetedEvent, SourcedEvent, ChannelMembershipAdjustment * Properties: ** `user`: `User` - the user who has changed their nickname ** `target`: `String` - the channel that the user is in ** `newNick`: `String` - the user's new nickname After a <> event, KtIrc will "fan out" the event to all of the channels that we share with the user and raise a `ChannelNickChanged` event for each channel. This is designed to make implementing certain features easier; if you fully handle a UserNickChanged event there is no need to also handle the ChannelNickChanged events, and vice-versa. TIP: The user property will contain the user's old details, but you will not be able to access additional information from the <> using these details as KtIrc will have internally renamed the user to use the new nickname. ==== ChannelNamesReceived * Type: IrcEvent, TargetedEvent * Properties: ** `target`: `String` - the channel that the user is in ** `names`: `List` - the partial list of names that are in the channel When we join a channel (or manually request it) the IRC server sends the list of channel members in a sequence of NAMES messages. KtIrc raises a `ChannelNamesReceived` event for each of these messages. WARNING: The given names may not be a complete list of members of the channel, as more names could follow. The format of the names varies between IRC servers and depending on the IRCv3 <> that KtIrc negotiated. Most implementations should simply wait for <> and then request the complete list of names from KtIrc's <>. ==== ChannelNamesFinished * Type: IrcEvent, TargetedEvent, ChannelMembershipAdjustment * Properties: ** `target`: `String` - the channel whose names response has finished Raised when the IRC server has finished receiving all of the names of users that are currently in a channel. At this point you can query the channel's <> to get a detailed list of members. ==== ChannelTopicDiscovered * Type: IrcEvent, TargetedEvent * Properties: ** `target`: `String` - the channel whose topic was discovered ** `topic`: `String?` - the topic in the channel, if any `ChannelTopicDiscovered` occurs when we join a channel (or manually request that the server repeats the current topic) and contains the current channel topic. If there is no topic set, the `topic` parameter will be `null`. Metadata about the topic, such as who set it and when, is contained in the <> event which should follow this one, if the topic was set. ==== ChannelTopicMetadataDiscovered * Type: IrcEvent, TargetedEvent * Properties: ** `target`: `String` - the channel whose topic metadata was discovered ** `user`: `User` - the user who set the topic ** `setTime`: `LocalDateTime` - the time at which the topic was set Provides meta-data relating to a topic that was previously set on the channel. NOTE: The given user may not exist on the network any more, or may have changed details since the topic was set. You should not expect to be able to look up the user's details in the <>, or interact with them directly on IRC. ==== ChannelTopicChanged * Type: IrcEvent, TargetedEvent, SourcedEvent * Properties: ** `user`: `User` - the user who has changed the topic ** `target`: `String` - the channel that the topic was changed in ** `topic`: `String?` - the channel's new topic Raised when a user changes the topic of a channel we are joined to. If the topic was cleared/removed, the `topic` parameter will be `null`. ==== ChannelAway * Type: IrcEvent, TargetedEvent, SourcedEvent * Properties: ** `user`: `User` - the user whose away state has changed ** `target`: `String` - the channel that the user is in ** `message`: `String?` - the away message, or `null` if the user is back After a <> event, KtIrc will "fan out" the event to all of the channels that we share with the user and raise a `ChannelAway` event for each channel. This is designed to make implementing certain features easier; if you fully handle a UserAway event there is no need to also handle the ChannelAway events, and vice-versa. === Channel/User events TODO ==== MessageReceived TODO ==== NoticeReceived TODO ==== ActionReceived TODO ==== CtcpReceived TODO ==== CtcpReplyReceived TODO ==== UserAway * Type: IrcEvent, SourcedEvent * Properties: ** `user`: `User` - the user who has changed their away state ** `message`: `String?` - the away message, or `null` if the user is back Raised when we are informed that a user has changed away states. If the server supports the `away-notify` capability we will receive notifications for all users in our common channels; otherwise, we will only receive notifications for our own user. If the user is away but we don't know the reason for it, the `message` property will be empty. ==== UserQuit TODO ==== UserNickChanged TODO ==== UserHostChanged TODO ==== UserAccountChanged TODO ==== ModeChanged TODO === Other events ==== PingReceived * Type: IrcEvent * Properties: ** `nonce`: `ByteArray` - the unique data that must be included in the reply Raised when the IRC server sends a PING message to the client. KtIrc will automatically reply with an appropriate PONG. ==== ServerFeaturesUpdated * Type: IrcEvent * Properties: ** `serverFeatures`: `ServerFeatureMap` - the features supplied by the server Corresponds to the server sending a single 005 ISUPPORT line. Multiple events of this type may be raised in quick succession when features are split over multiple lines. In general, you should wait for a <> event and then query the <> instead of relying on this event. ==== ServerCapabilitiesReceived TODO ==== ServerCapabilitiesAcknowledged TODO ==== ServerCapabilitiesFinished TODO ==== AuthenticationMessage TODO ==== SaslFinished TODO ==== SaslMechanismNotAvailableError TODO ==== BatchStarted TODO ==== BatchFinished TODO ==== BatchReceived TODO ==== NicknameChangeFailed * Type: IrcEvent * Properties: ** `cause`: `NicknameChangeError` - the reason the nickname must be changed Raised when the server informs us that our desired nickname is not available for some reason. The `cause` parameter will contain a specific reason given by the server: * `ErroneousNickname` - the nickname is not allowed by the server (e.g. it used restricted characters) * `AlreadyInUse` - the nickname is already in use * `Collision` - the nickname has collided with another somehow * `NoNicknameGiven` - no nickname was provided ==== NicknameChangeRequired * Type: IrcEvent, NicknameChangeFailed * Properties: ** `cause`: `NicknameChangeError` - the reason the nickname must be changed Raised during a connection attempt when there is a problem with the nickname that KtIrc was told to use. The exact problem will be detailed in the `cause` parameter, and has the same options as the <> event. Upon receiving this event, a new nickname MUST be chosen and sent to the server with the <> method. Failure to do so will result in the IRC server terminating the connection. WARNING: `NicknameChangeRequired` currently extends `NicknameChangeFailed` for backwards compatibility. This will be removed in KtIrc 2.0.0, and both events will need to be handled separately. == Messages TODO === sendNickChange TODO == Utility methods TODO === IsLocalClient TODO === React TODO === Reply TODO == IRCv3 support The following table shows KtIrc's IRCv3 support as of this release: [cols=3,options="header,autowidth"] |=== | Feature | Status | Notes 3+h| Capability negotiation | https://ircv3.net/specs/core/capability-negotiation.html[CAP] | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} See <> for the caps KtIrc will negotiate | https://ircv3.net/specs/core/capability-negotiation.html#cap-ls-version[CAP 302] | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} See <> for the caps KtIrc will negotiate | https://ircv3.net/specs/core/capability-negotiation.html#cap-notify[cap-notify] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} 3+h| Published specifications | https://ircv3.net/specs/extensions/account-notify-3.1.html[account-notify] v3.1 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} See <> | https://ircv3.net/specs/extensions/account-tag-3.2.html[account-tag] v3.2 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} Accounts are automatically added to `User` properties in events | https://ircv3.net/specs/extensions/away-notify-3.1.html[away-notify] v3.1 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} See <>. | https://ircv3.net/specs/extensions/batch-3.2.html[batch] v3.2 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} See <> | https://ircv3.net/specs/extensions/chghost-3.2.html[chghost] v3.2 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} See <> | https://ircv3.net/specs/extensions/echo-message-3.2.html[echo-message] v3.2 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} See also the `alwaysEchoMessages` <> | https://ircv3.net/specs/extensions/extended-join-3.1.html[extended-join] v3.1 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} Additional details are automatically added to `User` properties in events | https://ircv3.net/specs/extensions/invite-notify-3.2.html[invite-notify] v3.2 | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://ircv3.net/specs/extensions/message-tags.html[message-tags] | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} Exposed in the metadata property of <> | https://ircv3.net/specs/core/monitor-3.2.html[monitor] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://ircv3.net/specs/extensions/multi-prefix-3.1.html[multi-prefix] v3.1 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} Automatically included in <> | https://ircv3.net/specs/extensions/sasl-3.1.html[SASL] v3.1 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} See <> | https://ircv3.net/specs/extensions/sasl-3.2.html[SASL] v3.2 | {set:cellbgcolor:#eeeeaa} Partial support | {set:cellbgcolor!} Notifications via `cap-notify` not yet supported. See <> | https://ircv3.net/specs/extensions/server-time-3.2.html[server-time] v3.2 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} Exposed in the metadata property of <> | https://ircv3.net/specs/extensions/sts.html[sts] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://ircv3.net/specs/extensions/userhost-in-names-3.2.html[userhost-in-names] v3.2 | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} Automatically included in <> | https://ircv3.net/specs/extensions/webirc.html[webirc] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} 3+h| Draft specifications | https://github.com/ircv3/ircv3-specifications/pull/363[brb] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/308[channel renaming] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/349[chathistory] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/346[delivered] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/304[editmsg] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://ircv3.net/specs/extensions/labeled-response.html[labeled-response] | {set:cellbgcolor:#a7eeaa} Supported | {set:cellbgcolor!} Exposed in the metadata property of <> | https://ircv3.net/specs/extensions/message-ids.html[message-ids] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/330[migrate] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://ircv3.net/specs/client-tags/react.html[react] | {set:cellbgcolor:#eeeeaa} Partial support | {set:cellbgcolor!} Sending via <> method, no events generated | https://github.com/ircv3/ircv3-specifications/pull/347[read] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/276[register] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://ircv3.net/specs/client-tags/reply.html[reply] | {set:cellbgcolor:#eeeeaa} Partial support | {set:cellbgcolor!} Sending via <> method, not processed on incoming messages | https://github.com/ircv3/ircv3-specifications/pull/306[resume] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/361[setname] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/357[standard replies] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} | https://github.com/ircv3/ircv3-specifications/pull/348[typing] | {set:cellbgcolor:#f7d5d3} No support | {set:cellbgcolor!} 3+h|Vendor specifications |===