diff --git a/lichat.html b/lichat.html index a2a1fa0..d42c2e1 100644 --- a/lichat.html +++ b/lichat.html @@ -161,7 +161,7 @@ (message t) (permissions (+ registrant)) (pull t) - (users t))

3. General Interaction

The client and the server communicate through update objects over a connection. Each such object that is issued from the client must contain a unique id. This is important as the ID is reused by the server in order to communicate replies. The client can then compare the ID of the incoming updates to find the response to an earlier request, as responses may be reordered or delayed. The server does not check the ID in any way– uniqueness and avoidance of clashing is the responsibility of the client. Each update should also contain a clock slot that specifies the time of sending. This is used to calculate latency and potential connection problems. If no clock is specified, the server must substitute the current time. Finally, each update may contain a from slot to identify the sending user. If the from slot is not given, the server automatically substitutes the known username for the connection the update is coming from.

When an update is sent to a channel, it is distributed to all the users currently in the channel. When an update is sent to a user, it is distributed to all the connections of the user. When an update is sent to a connection, it is serialised to the wire according to the above wire format specification. The actual underlying mechanism that transfers the characters of the wire format to the remote host is implementation-dependant.

3.1 Null Termination of Updates

At the end of each update there has to be a single null character (U+0000). This character can be used to distinguish individual updates on the wire and may serve as a marker to attempt and stabilise the stream in case of malformed updates or other problems that might occur on the lower level.

3.2 Failures

If an update cannot be performed for some reason, the server will respond with a failure update. If the client's update was successfully parsed, this failure must be a subclass of update-failure, which will reference the failed update's id in the update-id slot, so that the client can reconstruct which of the requests failed.

3.3 Warnings

In addition to the normal reply of an update – whether successful or failed – the server may also send an update that is a subclass of warning. This update must be from the primary user, and must reference the original update in its update-id slot. The client may use the warning to inform the user or adjust future behaviour in response to the server's notice.

Note that a warning may only be issued if the request is processed otherwise. The server must not only reply with a warning. The server further must reply with the warning before replying with the response to the original update.

4. Connection

4.1 Connection Establishment

After the connection between a client and a server has been established through some implementation-dependant means, the client must send a connect update. The update will attempt to register the user on the server, as follows:

  1. If the server cannot sustain more connections, a too-many-connections update is returned and the connection is closed.

  2. If the update's version denotes a version that is not compatible to the version of the protocol on the server, an incompatible-version update is returned and the connection is closed.

  3. If the update's from field is missing or NIL, the server substitutes a random name that is not currently used by any other user or registered profile.

  4. If the update's from field contains an invalid name, a bad-name update is returned and the connection is closed.

  5. If the update does not contain a password, and the from field denotes a username that is already taken by an active user or a registered user, an username-taken update is returned and the connection is closed.

  6. If the update does contain a password, and the from field denotes a username that is not registered, a no-such-profile update is returned and the connection is closed.

  7. If the update does contain a password, and the from field denotes a username that is registered, but whose password does not match the given one, an invalid-password update is returned and the connection is closed.

  8. If the server cannot sustain more connections for the requested user, a too-many-connections update is returned and the connection is closed.

  9. A user corresponding in name to the from field is created if it does not yet exist.

  10. The connection is tied to its corresponding user object.

  11. The server responds with a connect update of the same id as the one the client sent. The from field must correspond to the user's actual name.

  12. If the user already existed, the server responds with join updates for each of the channels the user is currently inhabiting, with the primary channel always being the first.

  13. If the user did not already exist, it is joined to the primary channel.

  14. The server sends a message update for the primary channel from the primary user. The message contents are up to the server, and should typically be some kind of welcome banner.

Should the user send a connect update after already having completed the connection handshake above, the server must drop the update and respond with an already-connected update.

4.2 Connection Maintenance

If the clock of an update diverges too much, the server may respond with a clock-skewed update and correct the timestamp. If the skew varies a lot, the server may drop the connection after replying with a connection-unstable update.

The server must receive an update on a connection within at least a certain implementation-dependant interval that must be larger than 100 seconds. If this does not happen, the server may assume a disconnection and drop the client after replying with a connection-unstable update. If the server does not receive an update from the client within an interval of up to 60 seconds, the server must send a ping update to the client, to which the client must respond with a pong update. This is to ensure the stability of the connection.

If the client sends too many updates in too short a time interval, the server may start dropping updates, as long as it responds with a too-many-updates update when it starts doing so. This throttling may be sustained for an implementation-dependant length of time. The client might send occasional ping requests to figure out if the throttling has been lifted. The server may also close the connection if it deems the flooding too severe.

Instead of a hard-throttle as described in the previous paragraph, the server may also implement a soft throttle by queueing updates and processing them after a delay. Should the client become throttled in this way, the server must send an updates-throttled warning once updates begin to be queued.

4.3 Connection Closure

A connection may be closed either due to a disconnect update request from the client, or due to problems on the server side. When the connection is closed, the server must act as follows:

  1. The server responds with a disconnect update, if it still can.

  2. The underlying connection between the client and the server is closed.

  3. The connection object is removed from the associated user object.

  4. If the user does not have any remaining connections, the user leaves all channels it inhabited.

The exceptional situation being during connection establishment. If the server decides to close the connection then, it may do so without responding with a disconnect update and may immediately close the underlying connection.

5. Client Interaction

5.1 General Update Checks

An update is always checked as follows:

  1. If the update is not at all recognisable and cannot be parsed, a malformed-update update is sent back and the request is dropped.

  2. If the update is too long (contains too many characters), a update-too-long update is sent back and the request is dropped.

  3. If the class of the update is not known or not a subclass of update, an invalid-update update is sent back and the request is dropped.

  4. If the from, channel, or target fields contain an invalid name, a bad-name update is sent back and the request is dropped.

  5. If the from field does not match the name known to the server by the user associated to the connection, a username-mismatch update is sent back and the request is dropped.

  6. If the channel field denotes a channel that does not exist, but must, a no-such-channel update is sent back and the request is dropped.

  7. If the target field denotes a user that does not exist, a no-such-user update is sent back and the request is dropped.

  8. If the update is an operation that is not permitted on its target channel, or the primary channel if no target channel is applicable, an insufficient-permissions update is sent back and the request is dropped.

5.2 Profile Registration

When a user sends a register update, the server must act as follows:

  1. If the server disagrees with the attempted registration, a registration-rejected update is sent back and the request is dropped.

  2. If the profile does not yet exist, it is created.

  3. The password of the profile associated to the user is changed to match the one from the update.

  4. The profile must stay live until at least 30 days after the user associated with the profile has existed on the server.

  5. The server responds by sending back the original register update.

Note that the server does not need to store the password verbatim, and is instead advised to only store and compare a hash of it.

5.3 Channel Creation & Management

Since a channel has only two bits of information associated with it, the management of channels is rather simple.

5.3.1 Creating a Channel

Creating a new channel happens with the create update:

  1. The update is checked for permissions by the primary channel.

  2. If a channel of the channel name in the update already exists, the server responds with a channelname-taken update and drops the request.

  3. If the user already inhabits the maximum amount of channels, the server responds with a too-many-channels update and drops the request.

  4. If the channel field is NIL, an anonymous channel is created, otherwise a regular channel is created.

  5. The user is automatically joined to the channel.

  6. The server responds with a join update to the user with the id being the same as the id of the create update.

5.3.2 Updating a Channel

The channel's permissions can be viewed or changed with the permissions update, if the channel allows you to do so.

  1. The permissions for the channel are updated with the ones specified in the update's permissions field as follows:
    1. For each rule in the specified permissions set in the update:
    2. If the rule should be malformed or unacceptable, the server responds with a invalid-permissions update and disregards the rule.
    3. Otherwise, set the rule with the same type in the channel's rule set to the given rule.

  2. The server responds with a permissions update with the permissions field set to the full permissions set of the channel, and the id being the same as the id of the update the user sent.

See §2.5 for an explanation of the proper syntax of the permissions. Note that the server may reduce the set of rules to a simpler set that is semantically equivalent.

As a shortcut, permissions can also be managed with the grant and deny updates, which change an individual rule. When a server receives a grant update, it must update the corresponding rule as follows:

  1. If the rule is T, nothing is done.

  2. If the rule is NIL, it is changed to (+ user).

  3. If the rule is an exclusion mask, user is removed from the mask.

  4. If the rule is an inclusion mask, user is added to the mask if they are not already on it.

When the server receives a deny update, it must update the corresponding rule as follows:

  1. If the rule is T, it is changed to (- user).

  2. If the rule is NIL, nothing is done.

  3. If the rule is an exclusion mask, user is added to the mask if they are not already on it.

  4. If the rule is an inclusion mask, user is removed from the mask.

After processing either a grant or deny update successfully, the update is sent back to the user.

5.4 Channel Interaction

A user can interact with a channel in several ways.

5.4.1 Joining a Channel

Joining a channel happens with the join update, after which the server acts as follows:

  1. If the user is already in the named channel, an already-in-channel update is sent back and the request is dropped.

  2. If the user already inhabits the maximum amount of channels, the server responds with a too-many-channels update and drops the request.

  3. The user is added to the channel's list of users.

  4. The user's join update is distributed to all users in the channel.

5.4.2 Leaving a Channel

Leaving a channel again happens with the leave update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. The user's leave update is distributed to all users in the channel.

  3. The user is removed from the channel's list of users.

5.4.3 Pulling a User

Another user can be pulled into the channel by the pull update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. If the target user is already in the named channel, an already-in-channel update is sent back and the request is dropped.

  3. If the target already inhabits the maximum amount of channels, the server responds with a too-many-channels update and drops the request.

  4. The target user is added to the channel's list of users.

  5. A join update for the target user with the same id as the pull update is distributed to all users in the channel.

5.4.4 Kicking a User

Another user can be kicked from a channel by the kick update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. If the target user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  3. The user's kick update is distributed to all users in the channel.

  4. A leave update for the target user is distributed to all users in the channel.

  5. The target user is removed from the channel's list of users.

5.4.5 Sending a Message

Finally, a user can send a message to all other users in a channel with the message update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. The user's message update is distributed to all users in the channel.

5.5 Server Information Retrieval

The server can provide a client with several pieces of information about its current state.

5.5.1 Listing Public Channels

Retrieving a list of channels can be done with the channels update, after which the server acts as follows:

  1. For each channel known to the server, the server checks the update against the channel's permissions.

  2. If the permissions allow the update, the channel's name is recorded.

  3. A channels update with the same id as the request is sent back with the channels field set to the list of names of channels that were recorded.

5.5.2 Listing All Users of a Channel

The list of users currently in a channel can be retrieved by the users update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. A list of the users in the channel is recorded.

  3. A users update with the same id as the request is sent back with the users field set to the list of names of users that were recorded.

5.5.3 Requesting Information About a User

Information about a particular user can be retrieved by the user-info update, after which the server acts as follows:

  1. If the user is not connected and no profile for the user exists, a no-such-user update is sent back and the request is dropped.

  2. A user-info update with the same id as the request is sent back with the connections field set to the number of connections the user object has associated with it and with the registered field set to T if the user has a profile associated with it.

5.5.4 Requesting Capabilities

A user can request a list of updates they are allowed to send to a particular channel using the capabilities update. The server must act as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. For every update type known to the server, the server checks whether the user is permitted according to the channel's permission rule for the update. If permitted, the update type is added to a list.

  3. A capabilities update with the same id as the request is sent back with the permitted field set to the list of updates gathered in step 2.

5.5.5 Requesting Private Information

Servers may store additional information about a user, such as statistics, IP addresses, and so forth. Such information can be requested through the server-info update. After receiving such an update, the server must act as follows:

  1. If the user is not connected and no profile for the user exists, a no-such-user update is sent back and the request is dropped.

  2. A server-info update with the same id as the request is sent back with the attributes field set to an "association list", and the connections field set to a list of "association lists", one such "association list" per connection the user has. An association list is a list where each element has the following structure:

The attributes being returned are dependent on the server and the supported protocol extensions. The set of returned attributes may also differ depending on the user being requested, especially if the user is the server's user.

The following attributes are specified:

The following connection attributes are specified:

While these attributes are specified in their purpose, a server does not have to return them.

6. Protocol Extension

A server or client may provide extensions to the protocol in the following manners:

Each extension to the protocol should receive a unique name of the form producer-name where producer is an identifier for who wrote up the extension's protocol, and name should be a name for the extension itself. For each extension that a server and client support, they must include the unique name of it as a string in the connect update's extensions list. Each producer also owns a symbol package with the producer's name, in which they may freely specify new symbols.

6.1 Known Extensions

7. General Conventions

The following are general conventions for server and client implementors. However, they are not mandatory to follow, as they may only make sense for certain types of implementations.

The default port when served over TCP should be 1111, with 1112 being the default for SSL connections.

When specified in URLs, Lichat takes the lichat protocol and follows this general scheme:

URL     ::= 'lichat://' HOST (':' PORT)? '/' (CHANNEL ('#' MESSAGE)?)?
+ (users t))

3. General Interaction

The client and the server communicate through update objects over a connection. Each such object that is issued from the client must contain a unique id. This is important as the ID is reused by the server in order to communicate replies. The client can then compare the ID of the incoming updates to find the response to an earlier request, as responses may be reordered or delayed. The server does not check the ID in any way– uniqueness and avoidance of clashing is the responsibility of the client. Each update should also contain a clock slot that specifies the time of sending. This is used to calculate latency and potential connection problems. If no clock is specified, the server must substitute the current time. Finally, each update may contain a from slot to identify the sending user. If the from slot is not given, the server automatically substitutes the known username for the connection the update is coming from.

When an update is sent to a channel, it is distributed to all the users currently in the channel. When an update is sent to a user, it is distributed to all the connections of the user. When an update is sent to a connection, it is serialised to the wire according to the above wire format specification. The actual underlying mechanism that transfers the characters of the wire format to the remote host is implementation-dependant.

3.1 Null Termination of Updates

At the end of each update there has to be a single null character (U+0000). This character can be used to distinguish individual updates on the wire and may serve as a marker to attempt and stabilise the stream in case of malformed updates or other problems that might occur on the lower level.

3.2 Failures

If an update cannot be performed for some reason, the server will respond with a failure update. If the client's update was successfully parsed, this failure must be a subclass of update-failure, which will reference the failed update's id in the update-id slot, so that the client can reconstruct which of the requests failed.

3.3 Warnings

In addition to the normal reply of an update – whether successful or failed – the server may also send an update that is a subclass of warning. This update must be from the primary user, and must reference the original update in its update-id slot. The client may use the warning to inform the user or adjust future behaviour in response to the server's notice.

Note that a warning may only be issued if the request is processed otherwise. The server must not only reply with a warning. The server further must reply with the warning before replying with the response to the original update.

4. Connection

4.1 Connection Establishment

After the connection between a client and a server has been established through some implementation-dependant means, the client must send a connect update. The update will attempt to register the user on the server, as follows:

  1. If the server cannot sustain more connections, a too-many-connections update is returned and the connection is closed.

  2. If the update's version denotes a version that is not compatible to the version of the protocol on the server, an incompatible-version update is returned and the connection is closed.

  3. If the update's from field is missing or NIL, the server substitutes a random name that is not currently used by any other user or registered profile.

  4. If the update's from field contains an invalid name, a bad-name update is returned and the connection is closed.

  5. If the update does not contain a password, and the from field denotes a username that is already taken by an active user or a registered user, an username-taken update is returned and the connection is closed.

  6. If the update does contain a password, and the from field denotes a username that is not registered, a no-such-profile update is returned and the connection is closed.

  7. If the update does contain a password, and the from field denotes a username that is registered, but whose password does not match the given one, an invalid-password update is returned and the connection is closed.

  8. If the server cannot sustain more connections for the requested user, a too-many-connections update is returned and the connection is closed.

  9. A user corresponding in name to the from field is created if it does not yet exist.

  10. The connection is tied to its corresponding user object.

  11. The server responds with a connect update of the same id as the one the client sent. The from field must correspond to the user's actual name.

  12. If the user already existed, the server responds with join updates for each of the channels the user is currently inhabiting, with the primary channel always being the first.

  13. If the user did not already exist, it is joined to the primary channel.

  14. The server sends a message update for the primary channel from the primary user. The message contents are up to the server, and should typically be some kind of welcome banner.

Should the user send a connect update after already having completed the connection handshake above, the server must drop the update and respond with an already-connected update.

4.2 Connection Maintenance

If the clock of an update diverges too much, the server may respond with a clock-skewed update and correct the timestamp. If the skew varies a lot, the server may drop the connection after replying with a connection-unstable update.

The server must receive an update on a connection within at least a certain implementation-dependant interval that must be larger than 100 seconds. If this does not happen, the server may assume a disconnection and drop the client after replying with a connection-unstable update. If the server does not receive an update from the client within an interval of up to 60 seconds, the server must send a ping update to the client, to which the client must respond with a pong update. This is to ensure the stability of the connection.

If the client sends too many updates in too short a time interval, the server may start dropping updates, as long as it responds with a too-many-updates update when it starts doing so. This throttling may be sustained for an implementation-dependant length of time. The client might send occasional ping requests to figure out if the throttling has been lifted. The server may also close the connection if it deems the flooding too severe.

Instead of a hard-throttle as described in the previous paragraph, the server may also implement a soft throttle by queueing updates and processing them after a delay. Should the client become throttled in this way, the server must send an updates-throttled warning once updates begin to be queued.

4.3 Connection Closure

A connection may be closed either due to a disconnect update request from the client, or due to problems on the server side. When the connection is closed, the server must act as follows:

  1. The server responds with a disconnect update, if it still can.

  2. The underlying connection between the client and the server is closed.

  3. The connection object is removed from the associated user object.

  4. If the user does not have any remaining connections, the user leaves all channels it inhabited.

The exceptional situation being during connection establishment. If the server decides to close the connection then, it may do so without responding with a disconnect update and may immediately close the underlying connection.

5. Client Interaction

5.1 General Update Checks

An update is always checked as follows:

  1. If the update is not at all recognisable and cannot be parsed, a malformed-update update is sent back and the request is dropped.

  2. If the update is too long (contains too many characters), a update-too-long update is sent back and the request is dropped.

  3. If the class of the update is not known or not a subclass of update, an invalid-update update is sent back and the request is dropped.

  4. If the from, channel, or target fields contain an invalid name, a bad-name update is sent back and the request is dropped.

  5. If the from field does not match the name known to the server by the user associated to the connection, a username-mismatch update is sent back and the request is dropped.

  6. If the channel field denotes a channel that does not exist, but must, a no-such-channel update is sent back and the request is dropped.

  7. If the target field denotes a user that does not exist, a no-such-user update is sent back and the request is dropped.

  8. If the update is an operation that is not permitted on its target channel, or the primary channel if no target channel is applicable, an insufficient-permissions update is sent back and the request is dropped.

5.2 Profile Registration

When a user sends a register update, the server must act as follows:

  1. If the server disagrees with the attempted registration, a registration-rejected update is sent back and the request is dropped.

  2. If the profile does not yet exist, it is created.

  3. The password of the profile associated to the user is changed to match the one from the update.

  4. The profile must stay live until at least 30 days after the user associated with the profile has existed on the server.

  5. The server responds by sending back the original register update.

Note that the server does not need to store the password verbatim, and is instead advised to only store and compare a hash of it.

5.3 Channel Creation & Management

Since a channel has only two bits of information associated with it, the management of channels is rather simple.

5.3.1 Creating a Channel

Creating a new channel happens with the create update:

  1. The update is checked for permissions by the primary channel.

  2. If a channel of the channel name in the update already exists, the server responds with a channelname-taken update and drops the request.

  3. If the user already inhabits the maximum amount of channels, the server responds with a too-many-channels update and drops the request.

  4. If the channel field is NIL, an anonymous channel is created, otherwise a regular channel is created.

  5. The user is automatically joined to the channel.

  6. The server responds with a join update to the user with the id being the same as the id of the create update.

5.3.2 Updating a Channel

The channel's permissions can be viewed or changed with the permissions update, if the channel allows you to do so.

  1. The permissions for the channel are updated with the ones specified in the update's permissions field as follows:
    1. For each rule in the specified permissions set in the update:
    2. If the rule should be malformed or unacceptable, the server responds with a invalid-permissions update and disregards the rule.
    3. Otherwise, set the rule with the same type in the channel's rule set to the given rule.

  2. The server responds with a permissions update with the permissions field set to the full permissions set of the channel, and the id being the same as the id of the update the user sent.

See §2.5 for an explanation of the proper syntax of the permissions. Note that the server may reduce the set of rules to a simpler set that is semantically equivalent.

As a shortcut, permissions can also be managed with the grant and deny updates, which change an individual rule. When a server receives a grant update, it must update the corresponding rule as follows:

  1. If the rule is t, nothing is done.

  2. If the rule is nil, it is changed to (+ user).

  3. If the rule is an exclusion mask, user is removed from the mask.

  4. If the rule is an inclusion mask, user is added to the mask if they are not already on it.

When the server receives a deny update, it must update the corresponding rule as follows:

  1. If the rule is t, it is changed to (- user).

  2. If the rule is nil, nothing is done.

  3. If the rule is an exclusion mask, user is added to the mask if they are not already on it.

  4. If the rule is an inclusion mask, user is removed from the mask.

After processing either a grant or deny update successfully, the update is sent back to the user.

5.4 Channel Interaction

A user can interact with a channel in several ways.

5.4.1 Joining a Channel

Joining a channel happens with the join update, after which the server acts as follows:

  1. If the user is already in the named channel, an already-in-channel update is sent back and the request is dropped.

  2. If the user already inhabits the maximum amount of channels, the server responds with a too-many-channels update and drops the request.

  3. The user is added to the channel's list of users.

  4. The user's join update is distributed to all users in the channel.

5.4.2 Leaving a Channel

Leaving a channel again happens with the leave update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. The user's leave update is distributed to all users in the channel.

  3. The user is removed from the channel's list of users.

5.4.3 Pulling a User

Another user can be pulled into the channel by the pull update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. If the target user is already in the named channel, an already-in-channel update is sent back and the request is dropped.

  3. If the target already inhabits the maximum amount of channels, the server responds with a too-many-channels update and drops the request.

  4. The target user is added to the channel's list of users.

  5. A join update for the target user with the same id as the pull update is distributed to all users in the channel.

5.4.4 Kicking a User

Another user can be kicked from a channel by the kick update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. If the target user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  3. The user's kick update is distributed to all users in the channel.

  4. A leave update for the target user is distributed to all users in the channel.

  5. The target user is removed from the channel's list of users.

5.4.5 Sending a Message

Finally, a user can send a message to all other users in a channel with the message update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. The user's message update is distributed to all users in the channel.

5.5 Server Information Retrieval

The server can provide a client with several pieces of information about its current state.

5.5.1 Listing Public Channels

Retrieving a list of channels can be done with the channels update, after which the server acts as follows:

  1. For each channel known to the server, the server checks the update against the channel's permissions.

  2. If the permissions allow the update, the channel's name is recorded.

  3. A channels update with the same id as the request is sent back with the channels field set to the list of names of channels that were recorded.

5.5.2 Listing All Users of a Channel

The list of users currently in a channel can be retrieved by the users update, after which the server acts as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. A list of the users in the channel is recorded.

  3. A users update with the same id as the request is sent back with the users field set to the list of names of users that were recorded.

5.5.3 Requesting Information About a User

Information about a particular user can be retrieved by the user-info update, after which the server acts as follows:

  1. If the user is not connected and no profile for the user exists, a no-such-user update is sent back and the request is dropped.

  2. A user-info update with the same id as the request is sent back with the connections field set to the number of connections the user object has associated with it and with the registered field set to T if the user has a profile associated with it.

5.5.4 Requesting Capabilities

A user can request a list of updates they are allowed to send to a particular channel using the capabilities update. The server must act as follows:

  1. If the user is not in the named channel, a not-in-channel update is sent back and the request is dropped.

  2. For every update type known to the server, the server checks whether the user is permitted according to the channel's permission rule for the update. If permitted, the update type is added to a list.

  3. A capabilities update with the same id as the request is sent back with the permitted field set to the list of updates gathered in step 2.

5.5.5 Requesting Private Information

Servers may store additional information about a user, such as statistics, IP addresses, and so forth. Such information can be requested through the server-info update. After receiving such an update, the server must act as follows:

  1. If the user is not connected and no profile for the user exists, a no-such-user update is sent back and the request is dropped.

  2. A server-info update with the same id as the request is sent back with the attributes field set to an "association list", and the connections field set to a list of "association lists", one such "association list" per connection the user has. An association list is a list where each element has the following structure:

The attributes being returned are dependent on the server and the supported protocol extensions. The set of returned attributes may also differ depending on the user being requested, especially if the user is the server's user.

The following attributes are specified:

The following connection attributes are specified:

While these attributes are specified in their purpose, a server does not have to return them.

6. Protocol Extension

A server or client may provide extensions to the protocol in the following manners:

Each extension to the protocol should receive a unique name of the form producer-name where producer is an identifier for who wrote up the extension's protocol, and name should be a name for the extension itself. For each extension that a server and client support, they must include the unique name of it as a string in the connect update's extensions list. Each producer also owns a symbol package with the producer's name, in which they may freely specify new symbols.

6.1 Known Extensions

7. General Conventions

The following are general conventions for server and client implementors. However, they are not mandatory to follow, as they may only make sense for certain types of implementations.

The default port when served over TCP should be 1111, with 1112 being the default for SSL connections.

When specified in URLs, Lichat takes the lichat protocol and follows this general scheme:

URL     ::= 'lichat://' HOST (':' PORT)? '/' (CHANNEL ('#' MESSAGE)?)?
 HOST    --- The server hostname
 PORT    --- The server port. If unspecified defaults to 1111
 CHANNEL --- An URL-encoded version of the channel name
diff --git a/lichat.mess b/lichat.mess
index d44cc0e..9fce282 100644
--- a/lichat.mess
+++ b/lichat.mess
@@ -386,15 +386,15 @@ See §2.5 for an explanation of the proper syntax of the permissions. Note that
 
 As a shortcut, permissions can also be managed with the ``grant`` and ``deny`` updates, which change an individual rule. When a server receives a ``grant`` update, it must update the corresponding rule as follows:
 
-1. If the rule is ``T``, nothing is done.
-2. If the rule is ``NIL``, it is changed to ``(+ user)``.
+1. If the rule is ``t``, nothing is done.
+2. If the rule is ``nil``, it is changed to ``(+ user)``.
 3. If the rule is an exclusion mask, ``user`` is removed from the mask.
 4. If the rule is an inclusion mask, ``user`` is added to the mask if they are not already on it.
 
 When the server receives a ``deny`` update, it must update the corresponding rule as follows:
 
-1. If the rule is ``T``, it is changed to ``(- user)``.
-2. If the rule is ``NIL``, nothing is done.
+1. If the rule is ``t``, it is changed to ``(- user)``.
+2. If the rule is ``nil``, nothing is done.
 3. If the rule is an exclusion mask, ``user`` is added to the mask if they are not already on it.
 4. If the rule is an inclusion mask, ``user`` is removed from the mask.