16 KiB
Executable File
nirc-rs 0.10.2 — Status Report
Version: 0.10.2 Release date: 2026-07 Codename: nirc-rs License: GPL-3.0-or-later Rust edition: 2021 Source: https://git.dcos.net/dcosnet/nirc-rs
Protocol Status
| Protocol | Implementation | Testing | Notes |
|---|---|---|---|
| IRC | ✅ Complete | ✅ Tested & Working | TLS, SASL PLAIN, CTCP, ISUPPORT, oper commands, IRCv3 away-notify |
| ADC/DC++ | ✅ Complete | ✅ Tested & Working | Hub connect, search, file transfers, guard pipeline |
| Matrix | ✅ Complete | ❌ Untested | Megolm E2EE, SQLite store, dedicated OS thread |
| Discord | ✅ Complete | ❌ Untested | Gateway WebSocket, REST API |
| Stout | ✅ Complete | ❌ Untested | REST + WebSocket (Revolt fork) |
| Spacebar | ✅ Complete | ❌ Untested | REST + WebSocket (Revolt fork) |
| Nerimity | ✅ Complete | ❌ Untested | REST + WebSocket (custom platform) |
| ❌ Withdrawn | N/A | Removed in 0.10.2 — see NOTICES.md for the rationale (Jack Dorsey BitChat / India courts legal uncertainty) |
What's New in 0.10.2
BitChat Protocol Module Withdrawn
The BitChat protocol module (src/protocols/bitchat.rs) and all of its
integrations have been removed from the codebase. The libp2p dependency
in Cargo.toml was dropped at the same time — BitChat was the only
consumer. The Noise primitive in src/engine/crypto.rs uses
x25519-dalek + aes-gcm directly (not libp2p), so ADC's encrypted
client-client connections are unaffected.
Why: The BitChat project (Jack Dorsey's recently-announced P2P messaging protocol) is the subject of active litigation in the Indian courts. The legal status of the protocol specification, the reference implementation, and downstream reimplementations is currently unclear. Pending clarity, we have removed the module entirely rather than ship an encumbered protocol backend. See NOTICES.md for the full rationale and re-evaluation criteria.
User impact: Existing config entries with protocol = "bitchat" are
silently ignored. Old history files tagged P2P:<name> are silently
reassigned to the Status tab. No data is lost; IRC / Matrix / ADC /
Discord / Stout / Spacebar / Nerimity configs and history are unaffected.
Removed code surface:
src/protocols/bitchat.rs(deleted)ProtocolType::BitChatenum variant + all match armsCommand::BitChatPeers,BitChatDm,BitChatSendFilevariantsProtocolCommand::BitChat(BitChatCommand)dispatcher variantDispatcher::connect_bitchat()method- F1 menu "Connect → BitChat…" entry
libp2pCargo dependency (only consumer was bitchat.rs)
Help text updated
The /help output now mentions the new 0.10.1 media commands (/url,
/video, /image) and explicitly notes the BitChat removal with a
pointer to NOTICES.md.
What's New in 0.10.1
IRC Protocol Fixes
- CTCP spec compliance — Outgoing CTCP requests (
/ctcp,/ctcp version, etc.) are now sent asPRIVMSGper the IRCv3 CTCP spec. The previous code usedNOTICE, which strict servers ignore (NOTICE must never trigger an automated reply per RFC 1459). This was the root cause of/ctcp <nick> VERSIONbeing silently ignored by some networks. - Self-targeted CTCP visible — Running
/ctcp mynick VERSION(targeting yourself) now displays the CTCP request in the relevant tab. The previous code skipped the entire CTCP block when the sender was the local nick, silently swallowing self-targeted queries. /awayproperly tracked — The connection state now tracksis_awayandaway_message. The/away [msg]command optimistically marks the local state and posts a confirmation notice; the server confirms viaRPL_NOWAWAY(306) /RPL_UNAWAY(305), both of which now have explicit handlers instead of falling through to the generic numeric dump.- IRCv3
away-notifyhandler — When theaway-notifycapability is active, the server forwards other users' AWAY commands as:nick AWAY :msg. These now have a dedicated handler that caches the away reason per nick instate.nick_awayand posts a notice. Previously the capability was negotiated but the messages fell into the "Unhandled command" notice path. /whohardening —RPL_WHOREPLY(352) now correctly splits the trailing field into hopcount and realname (per RFC 1459), displays the here/away flag (H/G) from the flags field, marks self-entries with(you), and has an explicitRPL_ENDOFWHO(315) terminator handler instead of dumping as a raw numeric. This addresses the historical/who <self>crash./melocal echo —/meactions are now echoed locally in the active tab immediately, so the user sees their action even on servers that don't echo own PRIVMSGs (bouncers, mock servers, etc.). The server's echo (if any) lands withis_own=trueand is naturally deduplicated by the user's perception./noticelocal echo — Same local-echo treatment for/notice, so sent notices are visible in the target tab immediately.
Input Rate Throttle + Line Guard
- Per-send line cap — A single input submission is now capped at 4
lines (configurable via
MAX_LINES_PER_SEND). Pasting a 50-line file no longer dumps 50 lines into the channel — only the first 4 are sent and a notice explains the truncation. - Sliding-window rate limit — At most 8 outgoing lines per 3 seconds
(configurable via
MAX_LINES_PER_WINDOW/WINDOW_SECS). A stuck Enter key or rapid-fire paste that would otherwise flood the channel is rejected after the cap, with a single warning notice per burst (subsequent rejections in the same burst are silent to avoid flooding the user's own tab with throttle notices). - New module:
src/core/throttle.rs—InputThrottlestruct withcheck()returningAllow { lines_sent }orReject { lines_sent, dropped, reason }. 7 unit tests covering paste truncation, rate window sliding, burst-warning suppression, and CRLF/empty-input edge cases.
Channel Rotation Revert
- Static insertion-order cycling —
next_tab_by_priorityandprev_tab_by_priorityincore/app.rsnow walk tabs in the order they were created, instead of ranking them into Unread/Conversed/Inert tiers sorted by recent activity. The activity-based reordering made Ctrl-N feel non-deterministic: the same keypress could land on a different tab each time depending on which channel received a message most recently. The new plain round-robin preserves muscle memory — "Ctrl-N three times gets me to #sourcemage" works every time. Tabs that failis_cyclable()(unjoined IRC channels, hidden server tabs) are still skipped. - Tests updated — The four tests that asserted priority-tier behavior now document the new insertion-order behavior.
URL Detection + Inline Photo + External Video
- URL detection in chat view — Message bodies are now scanned for
URLs (
http://,https://,ftp://,www.prefixes). Detected URLs are rendered underlined and in cyan so they're visually distinct. Trailing sentence punctuation (.,,,;,!,?) is stripped from the URL itself. URLs wrapped in<...>or(...)are extracted cleanly without the surrounding punctuation. - New module:
src/tui/media.rs—detect_urls(),classify_url()(image / video / other by file extension),open_external()(xdg-open / open / start with http-scheme safety check),detect_image_protocol()(Kitty / iTerm2 / Sixel / None),try_render_inline_image()(stub returningUnsupportedfor now — graceful fallback to text placeholder),image_placeholder_text(). 20+ unit tests covering URL extraction edge cases, media classification, and external-launch safety. - New commands:
/url <url>,/video <url>,/image <url>— open URLs externally, launch video in the OS default player, or attempt inline image rendering (falls back to/urlif the terminal doesn't support inline images). - Inline photo support is graceful — If the terminal doesn't support
an inline-image protocol, the user sees a text placeholder
[image: <url>]and can still open the image externally via/url. No garbage escape sequences are dumped on unsupported terminals.
Top-Right Bandwidth Monitor
- Live transfer stats in the top status bar — The static
nirclabel in the top-right corner is now replaced with a live bandwidth monitor when transfers are active. Format:↓1.2MiB/s ↑0.5MiB/s file.zip 45%. Shows aggregate download/upload rates and the most-active file's progress percentage. Falls back tonircwhen no transfers are active. TransferManager::summary()— New method that samples each active transfer'sbytes_transferredagainst the previous frame's sample to compute instantaneous bytes/sec. Tracks the top transfer by bandwidth (most active file). Rate-sampling state is cleaned up when transfers complete.- New struct:
TransferSummary— Compact bandwidth + active-file summary withis_empty(),fmt_dl_rate(),fmt_ul_rate()helpers.
Line Wrapping Fix
- Word-wrap for long lines — Extremely long IRC lines (and any
message body) now wrap to the next display line instead of being
truncated at the right margin. The previous code dropped all text
past the visible width; the new
wrap_text()helper breaks on word boundaries when possible and falls back to hard character breaks for words longer than the available width (e.g. long URLs). 5 unit tests covering word-boundary wrapping, long-URL hard-breaking, and empty-input edge cases. - Fixes: "extremely long lines from IRC doesn't wrap lines and text is lost if resolution is small" — long messages are now fully readable even on 80-column terminals.
What's New in 0.10.0
IRC Hardening
- SASL EXTERNAL with client certificates — Full TLS client certificate support via the identity vault. Loads combined PEM files (cert+key) or separate cert/key files. Configurable per-server via
sasl_client_certin the server entry'sextramap. - MONITOR (watch list) support — IRCv3 MONITOR capability for tracking online/offline status of specific users. New
/watch + <nick>,/watch - <nick>,/watch l,/watch c,/watch scommands. Handles RPL_MONONLINE (730), RPL_MONOFFLINE (731), RPL_MONLIST (732), RPL_ENDOFMONLIST (733), RPL_MONLISTFULL (734). - User mode tracking — Local tracking of user modes (+i, +w, etc.) via MODE handler and RPL_UMODEIS (221). Modes displayed in status bar.
- DCC SEND/ACCEPT framework — Parsed incoming DCC SEND CTCP messages with IP/port/size extraction. Outbound DCC SEND with listening socket and local IP discovery. CTCP DCC ACCEPT handling for resume support. 8 new unit tests for DCC parsing.
Security & Configuration
- Config file hot-reload — Background task polls
~/.nirc/config.tomlmtime every 5 seconds. On change, reloads config, updates palette/theme, and syncs nickname changes without dropping active connections. - Custom keybindings from config — Users can remap keys in
config.tomlvia[keybindings]section. Supports compound modifiers (ctrl-alt-x), F-keys, and all crossterm key names. Custom bindings checked before hardcoded defaults. - Plugin management commands —
/plugins,/plugin-load <name>,/plugin-unload <name>,/plugin-enable <name>,/plugin-disable <name>now wired up in the command dispatcher. - Scrollback persistence to disk — Per-tab message history saved as JSONL files in
~/.nirc/history/. Loaded on startup, saved every 30 seconds and on clean exit. Respectsmax_scrollbacklimit. - Terminal title (XTITLE) — OSC 0 escape sequences set the terminal window title to
nirc - <protocol> <channel> (N unread). Updated on tab switch. Reset to "nirc" on exit.
ADC Protocol
- Proper CID generation — Replaced
NIRC{SID}placeholder with SHA-256 (first 24 bytes) + RFC 4648 Base32 encoding. Produces spec-compliant 39-character CIDs. - I4/U4 BINF fields — ADC client-client connections now include proper I4 (IPv4) and U4 (UDP4 port) in BINF messages for inbound peer connections.
Code Quality & Hardening
#![deny(unsafe_code)]at crate root.#[allow(unsafe_code)]scoped to only the plugin loader (libloading) and yamux integration that require it.- Atomic config save —
save_config()now uses hard-link + rename strategy for atomic file replacement on POSIX. - Vault key zeroization — Verified
derive_key()in the vault wipes the stack copy of derived keys viazeroize. - Lightgray color fix —
lightgray/lightgreynow correctly maps toColor::Indexed(252)(75% brightness) instead ofColor::Gray(40%). - Removed unused dependencies — Dropped
irc,nucleo-matcher,nom, andbytescrates from Cargo.toml.
What's New in 0.9.0
Keybindings
Ctrl-P— jump to previous buffer in the window listCtrl-A— jump to next active (connected) bufferCtrl-Z— cycle through highlight words for notification filteringInsert— scroll chat view to the bottom and re-enable auto-scrollDelete— now deletes the character after the cursor only (no longer cycles connections; useHome/Endfor window switching)
F1 Dropdown Menu
The F1 key now opens a QBasic 4.5 / aptitude-style dropdown menu bar at the top of the screen. Navigate with arrow keys, select with Enter, dismiss with Esc or F1. All slash-commands are accessible through the menu for discoverability.
Transfer Ticker
A transfer progress ticker now appears in the footer bar, showing real-time transfer speed and ETA for all active file transfers — no need to toggle the transfer panel.
UI Fixes
/nickUI update — changing your nickname now immediately updates all tab titles and status bar displays- Local IP footer — the status bar now shows your local network IP address
- Window list badges — protocol badges and unread indicators in the winlist sidebar
Under the Hood
- Ratatui 0.29 migration
- Crossterm 0.28
- libp2p 0.54 (with
macrosfeature, not the removedswarm-derive) - matrix-sdk 0.18
- tokio-rustls 0.26 with webpki-roots
Known Issues
-
Matrix crypto types are not
Send— the matrix-sdk crypto types require running on a dedicated OS thread with a single-threaded tokio runtime. This is handled correctly but adds architectural complexity. -
4 protocol stubs — Discord, Stout, Spacebar, and Nerimity have full type definitions but their
run_*()functions log "not yet implemented" and return. These contribute dead-code warnings. -
DCC transfers need async I/O integration — DCC SEND/ACCEPT parsing and socket setup is implemented, but the actual file data transfer loop needs to be wired into the transfer engine's async I/O pipeline.
Build & Test Status
- Build:
cargo build --releasesucceeds - Tests: All 313 tests pass
- Binary size (release): ~834 MB debug, optimized release binary significantly smaller
- Rust version required: 1.75+
Roadmap / Next Steps
0.10.x (Stabilization)
- Test Matrix protocol against matrix.org
- Test Discord protocol
- Test remaining protocols (Stout, Spacebar, Nerimity, BitChat)
- Integrate transfer widget into main draw loop as split view
1.0.0 (Release)
- All 8 protocols tested and working
- Full plugin API stability guarantee
- Man page and completion scripts finalized
- Packaging for major distributions
- Scrollback persistence to disk
- SASL SCRAM-SHA-256 support
- Matrix SSO login