nirc-rs/STATUS.md

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)
BitChat 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::BitChat enum variant + all match arms
  • Command::BitChatPeers, BitChatDm, BitChatSendFile variants
  • ProtocolCommand::BitChat(BitChatCommand) dispatcher variant
  • Dispatcher::connect_bitchat() method
  • F1 menu "Connect → BitChat…" entry
  • libp2p Cargo 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 as PRIVMSG per the IRCv3 CTCP spec. The previous code used NOTICE, which strict servers ignore (NOTICE must never trigger an automated reply per RFC 1459). This was the root cause of /ctcp <nick> VERSION being 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.
  • /away properly tracked — The connection state now tracks is_away and away_message. The /away [msg] command optimistically marks the local state and posts a confirmation notice; the server confirms via RPL_NOWAWAY (306) / RPL_UNAWAY (305), both of which now have explicit handlers instead of falling through to the generic numeric dump.
  • IRCv3 away-notify handler — When the away-notify capability 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 in state.nick_away and posts a notice. Previously the capability was negotiated but the messages fell into the "Unhandled command" notice path.
  • /who hardeningRPL_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 explicit RPL_ENDOFWHO (315) terminator handler instead of dumping as a raw numeric. This addresses the historical /who <self> crash.
  • /me local echo/me actions 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 with is_own=true and is naturally deduplicated by the user's perception.
  • /notice local 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.rsInputThrottle struct with check() returning Allow { lines_sent } or Reject { 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 cyclingnext_tab_by_priority and prev_tab_by_priority in core/app.rs now 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 fail is_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.rsdetect_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 returning Unsupported for 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 /url if 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 nirc label 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 to nirc when no transfers are active.
  • TransferManager::summary() — New method that samples each active transfer's bytes_transferred against 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 with is_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_cert in the server entry's extra map.
  • 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 s commands. 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.toml mtime 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.toml via [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. Respects max_scrollback limit.
  • 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 savesave_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 via zeroize.
  • Lightgray color fixlightgray/lightgrey now correctly maps to Color::Indexed(252) (75% brightness) instead of Color::Gray (40%).
  • Removed unused dependencies — Dropped irc, nucleo-matcher, nom, and bytes crates from Cargo.toml.

What's New in 0.9.0

Keybindings

  • Ctrl-P — jump to previous buffer in the window list
  • Ctrl-A — jump to next active (connected) buffer
  • Ctrl-Z — cycle through highlight words for notification filtering
  • Insert — scroll chat view to the bottom and re-enable auto-scroll
  • Delete — now deletes the character after the cursor only (no longer cycles connections; use Home/End for 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

  • /nick UI 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 macros feature, not the removed swarm-derive)
  • matrix-sdk 0.18
  • tokio-rustls 0.26 with webpki-roots

Known Issues

  1. 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.

  2. 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.

  3. 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 --release succeeds
  • 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