Sometimes, doing a LIST on a single upstream can be useful: if a user is
already connected to Rizon and freenode, sending a LIST will contain
tens of thousands of LIST replies that may not be useful if the user is
interested in another upstream.
This adds support for sending `LIST */network`, which follows the ELIST
M mask extension, that will only send LIST to that specific network. No
other masks are supported by this commit.
Users often have different nicks on different upstreams, and we should
support changing the user nick on a single upstream.
This adds support for a new trivial extension, `NICK nick/network`,
which will change the nick on the specified network, and do nothing for
the other networks.
Previously, the downstream nick was never changed, even when the
downstream sent a NICK message or was in single-server mode with a
different nick.
This adds support for updating the downstream nick in the following
cases:
- when a downstream sends NICK
- additionally, in single-server mode:
- when a downstream connects and its single network is connected
- when an upstream connects
- when an upstream sends NICK
When SASL is not used, we should only send CAP END after we send a CAP
REQ. Previously CAP END was sent both after a CAP REQ and a CAP ACK,
resulting in two CAP END messages.
Sending a CAP END right after the CAP REQ rather than waiting for the
CAP ACK/NAK saves 1 RTT.
Even though the memberships map has type map[string]*memberships
(with memberships being defined as []membership), the default value for
that map should not be `nil` but a pointer to a nil slice.
This fixes a segfault on some servers before user channel prefixes are
sent.
Previously, we only considered channel modes in the modes of a MODE
messages, which means channel membership changes were ignored. This
resulted in bugs where users channel memberships would not be properly
updated and cached with wrong values. Further, mode arguments
representing entities were not properly marshaled.
This adds support for correctly parsing and updating channel memberships
when processing MODE messages. Mode arguments corresponding to channel
memberships updates are now also properly marshaled.
MODE messages can't be easily sent from history because marshaling these
messages require knowing about the upstream available channel types and
channel membership types, which is currently only possible when
connected. For now this is not an issue since we do not send MODE
messages in history.
User channel memberships are actually a set of memberships, not a single
value. This introduces memberships, a type representing a set of
memberships, stored as an array of memberships ordered by descending
rank.
This also adds multi-prefix to the permanent downstream and upstream
capabilities, so that we try to get all possible channel memberships.
Channels can now be detached by leaving them with the reason "detach",
and re-attached by joining them again. Upon detaching the channel is
no longer forwarded to downstream connections. Upon re-attaching the
history buffer is sent.
This fixes a serious bug added in 276ce12e, where in newNetwork all
channels point to the same channel, which causes soju to only join a
single channel when connecting to an upstream network.
This also adds the same kind of reassignment of a for loop variable in
user.run(), even though that function currently works correctly, as a
sanity improvement in case this function is changed in the future.
Unfortunately, I don't think there's a good way to implement net.Conn
semantics on top of channels. The Close and SendMessage methods should
gracefully fail without panicking if the connection is already closed.
Using only channels leads to race conditions.
We could remove the lock if Close and SendMessage are only called from a
single goroutine. However that's not the case right now.
Closes: https://todo.sr.ht/~emersion/soju/55
This makes use of cap-notify to dynamically advertise support for
away-notify. away-notify is advertised to downstream connections if all
upstreams support it.
Some servers do not support TLS, or have invalid, expired or self-signed
TLS certificates. While the right fix would be toi contact each server
owner to add support for valid TLS, supporting plaintext upstream
connections is sometimes necessary.
This adds support for the irc+insecure address scheme, which connects to
a network in plain-text over TCP.
This is preparatory work for adding other connection types to upstream
servers. The service command `network create` now accepts a scheme in
the address flag, which specifies how to connect to the upstream server.
The only supported scheme for now is ircs, which is also the default if
no scheme is specified. ircs connects to a network over a TLS TCP
connection.
When writing a PRIVMSG or NOTICE on a channel, it is very common to use
autocompletion to mention other users on that channel. When using soju
in multi-network mode, all users will have their nicked suffixed by
`/network`. This suffix should be removed before sending it upstream.
This adds support for removing all `/network` suffixes in messages sent
to a channel of that network.
Store the list of configured channels in the network data structure.
This removes the need for a database lookup and will be useful for
detached channels.
Some servers use custom IRC bots with custom commands for registering to
specific services after connection.
This adds support for setting custom raw IRC messages, that will be
sent after registering to a network.
It also adds support for a custom flag.Value type for string
slice flags (flags taking several string values).
The database is now initialized automatically on first run. The schema
version is stored in SQLite's user_version special field. Migrations are
stored in an array and applied based on the schema version.
Instead of having one ring buffer per network, each network has one ring
buffer per entity (channel or nick). This allows history to be more
fair: if there's a lot of activity in a channel, it won't prune activity
in other channels.
We now track history sequence numbers per client and per network in
networkHistory. The overall list of offline clients is still tracked in
network.offlineClients.
When all clients have received history, the ring buffer can be released.
In the future, we should get rid of too-old offline clients to avoid
having to maintain history for them forever. We should also add a
per-user limit on the number of ring buffers.