| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
| |
The welcome burst grew to three RPL_005 lines a while back, but
test_replies-for! / test_sasl / test_memoserv still asserted the
old counts (7/7/8). Update them to 8/8/9 to match what the server
actually emits.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
papod no longer pre-creates a "default network" at boot. Instead,
each accepted connection is expected to begin with a PROXY protocol
v2 header (RFC: haproxy.org proxy-protocol.txt) carrying the SNI in
a PP2_TYPE_AUTHORITY (0x02) TLV — exactly what untls now injects.
The authority is used to look up (or create) a network by name, and
the resulting network-id is bound to the client at connect time
rather than at registration time. Connections that arrive without
a header and without the PAPOD_NETWORK_NAME fallback set are refused
with "ERROR :Closing link: (No network)".
PAPOD_NETWORK_NAME exists for environments where untls is not in
the path (notably the integration test harness, where binder/wscat
speak raw bytes); production deployments should leave it unset and
let untls supply the SNI.
Unit tests cover the parser: a valid header returns the AUTHORITY
and leaves trailing bytes intact; non-PROXY input returns nil and
preserves the stream; PROXY without an AUTHORITY TLV returns "".
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- WHOX %a now returns the user's :account (was hardcoded "0").
- INVITE accepts the RFC1459 "INVITE <channel> <nick>" param order in
addition to Modern's "INVITE <nick> <channel>", and the relayed line
preserves the input order. When the channel does not exist the inviter
also receives an INVITE echo (RFC1459 deprecated, but tested).
- AUTHENTICATE PLAIN is now allowed after registration and after a prior
successful auth, matching SASL 3.2's "any time" rule. Removed the
trailing "NOTICE Session ID:" line so it doesn't leak in front of the
next AUTHENTICATE +.
- PRIVMSG delivery splits client capabilities: clients with message-tags
see the full tagged line (msgid + time + client-only +tags); clients
with only server-time see just msgid + time, no client-only tags;
clients with neither see the raw line. Same split applies to the
echo-message reply.
- deliver-to-client\! truncates only the body (post-tag) to 510 bytes so
IRCv3 message-tag payloads up to 4094 bytes survive the wire.
- +b ban check on JOIN is bypassed when an INVITE is pending for the
user, mirroring Ergo's +I-style invite-exception. The invite is still
consumed on successful JOIN.
Unit test for the post-success AUTHENTICATE PLAIN path is updated to
expect "AUTHENTICATE +" rather than 907.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds the missing CHATHISTORY TARGETS subcommand returning channels and
DM peers the user has activity in within an exclusive timestamp window,
sorted by latest message time.
REDACT now accepts DM targets: a sender can redact their own DM, and
both sides receive the REDACT line if they have draft/message-redaction.
DM events now record source-account and target-account at storage time.
Chathistory queries filter to events whose stored account matches the
requesting client's current SASL account, so a freshly-registered user
who reuses a previously-anonymous nick does not see the prior identity's
DMs (regression test for issue #833).
DM history fetch is also case-insensitive on nick comparisons, and
format-history-event renders DMs with the original target nick rather
than the conversation peer, fixing replays where a self→peer reply was
shown as peer→peer.
The join-one\! refactor (returns echo + topic + markread + names lines
in the reply vector) is retained from prior work; unit tests assert the
returned replies instead of inspecting the writer bytestream so JOIN
echoes can be wrapped in a labeled-response BATCH.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Major chathistory work:
- Add CHATHISTORY BEFORE/AFTER/BETWEEN/AROUND with msgid/timestamp anchors
- Filter redacted messages from history per spec
- Persist TOPIC events for event-playback support
- Use historical timestamps in CHATHISTORY responses
- Support DM history queries (msg-to-self and between users)
- Add draft/event-playback capability
REDACT improvements:
- Only deliver REDACT to clients with draft/message-redaction cap
- Add msgid/time tags to generic TAGMSG handler
- FAIL responses include subcommand context per spec
Tag-line refactoring:
- Add tag-line-at helper for stored event timestamps
- Share msg-at between event store and broadcast in PRIVMSG/TOPIC
- Use ISO time with explicit Date instead of double iso-time call
|
| |
|
|
|
|
|
|
|
|
|
| |
Add :n-unreg counter on the components map: incremented when a
client connects, decremented when it registers or disconnects.
LUSERS now reports the real unregistered count from this counter
(previously always 0 because unregistered clients are not in
:clients).
Also handle the 'o' character in user-mode setting so MODE <self>
-o actually clears :oper?, fixing the LuserOpers oper-count test.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Move label tag insertion into existing tag prefix instead of
emitting two separate @-prefixed sections.
- Echo of PRIVMSG to sender now omits msgid/time tags unless the
sender has message-tags or server-time capability.
- Generic TAGMSG: forward to direct recipients (with message-tags
cap), echo back to sender (with echo-message + message-tags),
filter the label tag from the recipient copy.
- Empty replies for labeled commands now produce a labeled ACK
(without server prefix), matching IRCv3 labeled-response.
- Accept silent PONG and parse loose command tokens (allow any
non-space char) so labeled NONEXISTENT_COMMAND yields a
labeled 421 instead of crashing the connection.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
LUSERS now reports oper / unknown / channel counts derived from
live state, and emits RPL_LOCALUSERS (265) / RPL_GLOBALUSERS
(266) with current and peak (:max-users atom, refreshed at
registration). Channel count only includes non-empty channels.
WHOWAS accepts an optional <count> argument and limits replies
accordingly. WHOWAS recording also moved into the QUIT path
exclusively (the finally-block now skips when :quit? is set), so
each disconnect produces a single history entry instead of two.
KICK now treats a stale empty channel as nonexistent (403).
|
| |
|
|
|
|
|
|
|
|
| |
QUIT and socket cleanup paths push a small (last 32) ring of
{nick, username, realname, host, ts} entries into a new :whowas
atom on the components map. WHOWAS reads that ring case-
insensitively and answers with RPL_WHOWASUSER (314) +
RPL_WHOISSERVER (312) for each match, terminated with
RPL_ENDOFWHOWAS (369), or falls back to ERR_WASNOSUCHNICK (406)
when nothing is found.
|
| |
|
|
|
|
|
| |
End-to-end coverage for the recently added features:
- +i mode rejects JOIN with 473 and INVITE clears the gate
- the welcome 005 line carries PREFIX/CHANTYPES/CASEMAPPING
- OPER answers with 381 plus the explicit MODE +o line
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
JOIN now respects the channel modes that gate access:
- +i (invite-only): rejects with 473 unless the user is in the
per-channel invite list, which INVITE now populates
- +k <key>: rejects with 475 unless the JOIN key argument matches
the value tracked alongside +k in :chan-keys
- +l <n>: rejects with 471 once :chan-limits is at capacity
NAMES (and the burst sent on JOIN) now picks the channel symbol
based on chan-modes — '@' for +s, '*' for +p, '=' otherwise — so
secret/private channels are reported correctly.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The 005 reply now advertises CASEMAPPING, CHANMODES, CHANTYPES,
PREFIX, NETWORK, NICKLEN, CHANNELLEN, TOPICLEN, KICKLEN, MAXLIST,
MODES, TARGMAX, USERLEN, STATUSMSG, AWAYLEN and UTF8ONLY across
two 005 lines. This satisfies what irctest's isupport/multi_prefix
tests look for.
OPER now follows RFC convention by sending an explicit
":server MODE <nick> :+o" line after RPL_YOUREOPER so clients
learn about their new mode without a separate query.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
NICK now rejects invalid characters with 432, does
case-insensitive collision detection, and broadcasts NICK
changes to all clients sharing a channel after registration.
Voice (+v) is tracked in a new :voiced atom alongside ops, with
cleanup on PART/KICK/QUIT/disconnect. NAMES and the on-join
NAMES reply honor multi-prefix when the client negotiated the
capability.
Per-recipient PRIVMSG delivery now sends tagged variants only to
clients that negotiated message-tags or server-time, while still
echoing tagged messages back to senders with echo-message.
TOPIC enforces +t against non-ops with 482. WHO marks opers with
*, MODE <nick> reports +o, and WHOIS adds the 313 oper line.
OPER and TIME commands are now implemented (381/464 and 391).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Channel modes (MODE command):
- +o/-o: grant/revoke operator, broadcast to channel
- +v/-v: voice mode, broadcast to channel
- +n/+t/+m/+i/+s: simple flag modes, tracked in :chan-modes atom
- +l: channel limit mode
- +k: channel key mode
- +b (no arg): ban list query returns 368
- Mode changes require channel operator status (482)
- MODE query returns tracked modes (324) + creation time (329)
Labeled-response (IRCv3):
- Commands with @label=X tag get responses wrapped:
- Single reply: label tag added directly
- No replies: ACK with label
- Multiple replies: BATCH labeled-response wrapper
Chathistory (IRCv3 draft/chathistory):
- Rewritten to use BATCH wrapping (BATCH +id chathistory #chan)
- Messages inside batch have batch=id tag
- Supports LATEST, BEFORE, AFTER, BETWEEN, AROUND subcommands
- Advertised via draft/chathistory capability
Other:
- Auto-op triggers for first joiner to empty channel (not just
new channels), fixing stale-Datomic-state issue
- Added userhost-in-names, multi-prefix, draft/chathistory to CAP
irctest: 232 passed, 410 failed, 218 skipped (up from 223).
Unit: 261 assertions, Integration: 38 assertions — all pass.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Channel operators:
- Auto-op channel creator on JOIN (first user to join gets @)
- Track ops in :ops atom, clean up on PART/QUIT/KICK
- KICK now requires channel operator status (482)
- NAMES shows @ prefix for operators
- WHO shows @ in flags for operators
- Add is-op? and names-for helpers
WHO improvements:
- Include realname (not nick) in trailing field of 352
- Support WHO * (list all visible users)
- Case-insensitive nick lookup for WHO <nick>
- Show G (gone/away) or H (here) + @ for ops in flags
WHOIS improvements:
- Add RPL_WHOISSERVER (312)
- Support WHOIS <target> <nick> two-param form
- Case-insensitive nick lookup
CAP improvements:
- NAK preserves exact requested string (no reordering)
- Add multi-prefix to supported capabilities
NAMES improvements:
- NAMES without args lists all channels with members
- Use names-for helper for consistent @ prefix rendering
TOPIC: return 403 for nonexistent channel (was 442)
irctest: 220 passed, 426 failed, 218 skipped (up from 214).
Unit: 260 assertions, Integration: 38 assertions — all pass.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
NOTICE, NAMES, LIST, PRIVMSG edge cases, and comma-separated JOIN
Unit tests (8 new test groups, 53 new assertions):
- test_whois-who-mode: WHOIS user info, WHOIS away status, WHOIS
missing user, WHO channel members, WHO nonexistent nick, MODE
user (221), MODE channel (324+329), USERHOST with away indicator
- test_topic: query with no topic (331), set+query+broadcast (332),
not-on-channel (442), missing params (461)
- test_kick-irc: removes user + notifies all, default reason is
kicker's nick, nonexistent channel (403), not on channel (442),
target not on channel (441), missing params (461)
- test_away-rpl: RPL_AWAY (301) on PRIVMSG to away user, no
RPL_AWAY for non-away user
- test_notice-dm: NOTICE delivers to user DM
- test_privmsg-empty-trailing: PRIVMSG #chan : returns 412
- test_join-comma-separated: JOIN #a,#b creates both, invalid
channel in comma list gets 403
- test_names-list: NAMES nonexistent (366), LIST returns 323
Integration tests (6 new tests, 17 new assertions):
- test_kick-irc-command: KICK notifies kicker, kicked, and observers
- test_topic-broadcast: TOPIC set broadcasts + query returns 332
- test_part-broadcast: PART with message delivered to members
- test_whois-between-clients: WHOIS from one client about another
- test_who-channel: WHO #channel lists all members
- test_nick-collision: second client with same nick gets 433
Also fixes:
- PRIVMSG #chan : (lone colon) now correctly returns 412
- Ghost check only triggers when socket is present (fixes
integration test false ghosting via piped streams)
Totals: 23 unit tests (260 assertions), 16 integration tests
(38 assertions), 205 irctest acceptance tests pass.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
IRC commands:
- MODE: return RPL_UMODEIS (221) for user mode queries,
RPL_CHANNELMODEIS (324) + RPL_CREATIONTIME (329) for channel
mode queries
- WHO: return RPL_WHOREPLY (352) + RPL_ENDOFWHO (315) for
channels and nicks
- TOPIC: query returns RPL_TOPIC (332) or RPL_NOTOPIC (331);
set broadcasts to all channel members
- KICK: removes target from channel, notifies all members
- NAMES: returns RPL_NAMREPLY (353) + RPL_ENDOFNAMES (366)
- LIST: returns RPL_LISTEND (323)
Test infrastructure:
- Ghost stale connections on pre-registration nick collision:
when a new client sends NICK during registration and the nick
is held by an existing connection, close the old connection.
This prevents irctest hangs where setUp() raises SkipTest
without calling tearDown(), leaving ghost connections.
- Add PAPOD_IDLE_TIMEOUT env var with SO_TIMEOUT on client
sockets (default 5min, acceptance tests use 1.5s)
- Store socket reference in client atom for ghost detection
Full irctest suite now completes without hanging:
167 passed, 576 failed, 197 skipped (up from 127 with hangs).
Unit: 207 assertions, Integration: 21 assertions — all pass.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- QUIT: notify channel members, clean up client/channel state, close
connection properly
- AWAY: set/clear away status with RPL_NOWAWAY/RPL_UNAWAY, send
RPL_AWAY on PRIVMSG to away users
- NOTICE: deliver to channels and users without error replies (per RFC)
- WHOIS: return RPL_WHOISUSER + RPL_AWAY + RPL_ENDOFWHOIS
- USERHOST: return RPL_USERHOST with away indicator
- PRIVMSG: return ERR_NOSUCHNICK (401) for nonexistent targets,
ERR_NOTEXTTOSEND (412) for empty messages
- USER: reject empty realname with ERR_NEEDMOREPARAMS (461)
- PING: handle empty token (PING :) as ERR_NOORIGIN (409)
- Add TCP listen support via PAPOD_TCP_PORT for direct irctest
compatibility (bypasses binder proxy)
- Fix member creation to handle reconnection with same nick (upsert)
- Fix client-loop! to check :quit? after process-input! returns
- Move AWAY, NOTICE, WHOIS, USERHOST, MODE, WHO before network check
(they don't require network context)
- Store client-atom reference in clients map for cross-client state
access
Tests: 207 unit assertions (15 tests), 21 integration assertions
(10 tests), 122 irctest acceptance tests pass.
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
| |
Many missing implementations or tests are marked with FIXME so I don't
loose track of holes in the code.
|
| |
|
|
| |
simplify network loop
|
| | |
|
| | |
|
| |
|
|
| |
implementing queriesT{}
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
There was some code that was being slowly tweaked as I'd work or related
things on other repositories that wasn't committed step by step, and
that now I'd rather include all as a single changeset, single there
weren't really separated stages on how it was developed.
Other than that, this commit includes adjustments on dependencies API
usage, as they changed during my work on them, and adjustments on the
build and test system, as I improved how they worked also during work on
other projects.
As of this commit, the code compiles and the tests pass. I can't recall
if this was true before this commit, but it is true now.
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
| |
Create and test simple code for handling migrations transactionally as
files.
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|