# nirc-rs — Patch Summary This file summarizes the patch batches applied to nirc-rs, newest first. --- ## 0.10.2 — BitChat Module Withdrawn **Date:** 2026-07-29 The BitChat protocol module and all of its integrations have been removed from the codebase. See `NOTICES.md` for the full rationale. ### 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. ### Files Changed - **Deleted:** `src/protocols/bitchat.rs` - **`src/protocols/mod.rs`** — removed `pub mod bitchat;` and re-exports - **`src/core/protocol.rs`** — removed `ProtocolType::BitChat` variant and all of its match arms in `tag()`, `label()`, `badge()`, `naim_color()`; updated the four protocol unit tests - **`src/core/command.rs`** — removed `BitChatPeers`, `BitChatDm`, `BitChatSendFile` command variants; removed the `"bitchat" | "p2p"` parser arm and the `"bitchat" => ProtocolType::BitChat` FromStr arm; removed the `"bitchat" | "bc" | "p2p"` arm from `/xfer` protocol lookup - **`src/engine/dispatcher.rs`** — removed `ProtocolCommand::BitChat` variant; removed `connect_bitchat()` method; removed BitChat dispatch arms in `Msg`, `Me`, `Say`, `quit_for`, and the explicit `BitChatPeers`/`BitChatDm`/`BitChatSendFile` handler block; removed BitChat from the connect dispatch and the tag-map lookup table - **`src/tui/menubar.rs`** — removed the "Connect → BitChat…" menu entry - **`src/tui/chat_view.rs`** — removed BitChat from the protocol color lookup tables (both dim-color and NaimColor) - **`src/tui/winlist.rs`** — removed BitChat from the badge char and badge color lookup tables; updated the module-level doc - **`src/core/history.rs`** — removed the `"P2P" => BitChat` tag mapping (old history files with this tag will be silently reassigned to Status) - **`src/logging/mod.rs`** — removed BitChat from `sanitize_server` match; updated the test - **`src/transfer/engine.rs`** — updated the integration test to use `ProtocolType::Adc` instead of `ProtocolType::BitChat` - **`src/core/app.rs`** — updated the `next_tab_by_priority_mixes_protocols_freely` test to use `ProtocolType::Adc` instead of `ProtocolType::BitChat` - **`src/config/mod.rs`** — updated the BitChat server-entries doc section to note the removal - **`src/engine/crypto.rs`** — updated the module-level doc to note that the Noise primitive is now only used by ADC (was previously shared with BitChat) - **`src/main.rs`** — renamed `_p2p_keypair` → `_noise_keypair` (still generated, since ADC uses it); removed the BitChat help text and replaced with a media-commands help section + a BitChat-removed note; removed the `Command::BitChatPeers | BitChatDm | BitChatSendFile` dispatch arm - **`Cargo.toml`** — bumped version to 0.10.2; removed `libp2p` dependency (BitChat was the only consumer); removed `"p2p"` from the keywords list - **`NOTICES.md`** — new file, contains the full rationale and re-evaluation criteria for the BitChat withdrawal - **`README.md`, `STATUS.md`, `TODO.md`, `QUICKSTART.md`/`quickstart.md`, `man/man1/nirc.1`, `completions/nirc.{bash,zsh,fish}`, `packaging/PKGBUILD`, `packaging/nirc.spec`, `packaging/debian/DEBIAN/control`, `BLOG_POST.md`** — updated to reflect the removal and point at `NOTICES.md` ### User Impact - **Existing configs:** Any `[[servers]]` entry with `protocol = "bitchat"` will be silently ignored at load time. You do not need to edit your config file, but you may remove the entries to clean it up. - **Existing history files:** Per-tab scrollback files tagged `P2P:` will fail to match any known protocol on load and will be silently assigned to the Status tab. The files themselves are not deleted; you can read them with a text editor if you need to recover the content. - **No data loss:** Your IRC / Matrix / ADC / Discord / Stout / Spacebar / Nerimity history, configs, and credentials are unaffected. ### Re-evaluation Criteria We will re-evaluate restoring the BitChat module when **all** of the following are true: 1. The India courts case has reached a final judgement (not an interim order), OR the parties have publicly settled and the settlement terms are clear about downstream-implementation rights. 2. The BitChat reference implementation's license is unambiguous and permits third-party reimplementations. 3. There is at least one independent legal opinion (not from a party to the litigation) concluding that shipping a clean-room reimplementation of the protocol is safe. Until then, the module will remain withdrawn. --- ## 0.10.1 — IRC Fixes, Throttle, Rotation Revert, URLs/Media, Bandwidth Monitor, Line Wrap **Date:** 2026-07-28 This patch batch addresses the user-reported issues with nirc-rs 0.10.0 and adds several requested features. The changes are organized into five phases. ### Phase 1: IRC Protocol Fixes (`src/protocols/irc.rs`, `src/main.rs`) - **CTCP spec compliance** — Outgoing CTCP requests now use `PRIVMSG` (was `NOTICE`). Per the IRCv3 CTCP spec, requests must be PRIVMSG; only replies use NOTICE. This was why `/ctcp VERSION` was silently ignored by strict servers. - **Self-targeted CTCP visible** — `/ctcp mynick VERSION` now displays the request in the relevant tab. Previously the entire CTCP block was skipped when the sender was the local nick, silently swallowing self-targeted queries. - **`/away` tracking** — Added `is_away` and `away_message` fields to `ConnState`. The `/away [msg]` command optimistically marks the local state and posts a confirmation notice. Added explicit handlers for `RPL_NOWAWAY` (306) and `RPL_UNAWAY` (305) instead of letting them fall through to the generic numeric dump. - **IRCv3 `away-notify` handler** — Added a dedicated `AWAY` command handler that caches the away reason per nick in `state.nick_away` and posts a notice. Previously the `away-notify` capability was negotiated but the incoming AWAY messages fell into the "Unhandled command" path. - **`/who` hardening** — `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 explicit `RPL_ENDOFWHO` (315) terminator handler. This addresses the historical `/who ` crash. - **`/me` local echo** (`src/main.rs`) — 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.). - **`/notice` local echo** (`src/main.rs`) — Same local-echo treatment for sent notices. ### Phase 2: Input Rate Throttle + Channel Rotation Revert - **New module: `src/core/throttle.rs`** — `InputThrottle` struct with sliding-window rate limiting and per-send line cap. Returns `Allow { lines_sent }` or `Reject { lines_sent, dropped, reason }`. 7 unit tests. - **`src/main.rs`** — Wired the throttle into the `SendMessage` path. Input is split on newlines (paste guard), capped at 4 lines per submission, and rate-limited to 8 lines per 3 seconds. Rejected lines produce a single warning notice per burst (subsequent rejections are silent to avoid flooding the user's tab). - **`src/core/app.rs`** — Reverted `next_tab_by_priority` and `prev_tab_by_priority` to static insertion-order cycling. The previous activity-tier-based reordering made Ctrl-N feel non-deterministic. Updated 4 existing tests to reflect the new behaviour. ### Phase 3: URL Detection + Inline Photo + External Video - **New module: `src/tui/media.rs`** — URL detection (`detect_urls`), media classification (`classify_url`: image/video/other by extension), external launching (`open_external`: xdg-open / open / start with http-scheme safety check), inline-image protocol detection (`detect_image_protocol`: Kitty / iTerm2 / Sixel / None), and a `try_render_inline_image` stub that gracefully returns `Unsupported` for now. 20+ unit tests. - **`src/tui/chat_view.rs`** — `render_body` now scans each text segment for URLs and renders them underlined in cyan. This is the foundation for the inline-photo and external-video features. - **`src/core/command.rs`** — Added `Command::Url`, `Command::Video`, `Command::Image` variants and parsers (`/url`, `/video`, `/image` commands). - **`src/main.rs`** — Added handlers for the new commands in `handle_user_command`. `/image` attempts inline rendering and falls back to external open if the terminal doesn't support it. ### Phase 4: Top-Right Bandwidth Monitor - **`src/transfer/mod.rs`** — Added `TransferSummary` struct and `TransferManager::summary()` method. The summary 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. - **`src/tui/input_bar.rs`** — `render_top_status_bar_naim` and `render_top_status_bar` now accept an `Option<&TransferSummary>` parameter. When transfers are active, the static `nirc` label in the top-right is replaced with `↓rate ↑rate filename %`. Falls back to `nirc` when no transfers are active. - **`src/main.rs`** — Calls `transfer_manager.summary()` once per frame and passes the result to the top status bar renderer. ### Phase 5: Line Wrapping Fix - **`src/tui/chat_view.rs`** — Added `wrap_text(text, max_cols)` helper that breaks on word boundaries when possible and falls back to hard character breaks for words longer than the available width (e.g. long URLs). The `ChatView::render` method now wraps each body line to fit the available width instead of truncating at the right margin. 5 unit tests. ### New Commands - `/url ` — open a URL in the OS default browser (xdg-open / open / start) - `/video ` — launch a video URL in the OS default video player - `/image ` — attempt inline image rendering; falls back to `/url` if the terminal doesn't support inline images ### Configuration The throttle limits are currently hardcoded in `src/core/throttle.rs`: - `MAX_LINES_PER_SEND = 4` — max lines per single input submission - `MAX_LINES_PER_WINDOW = 8` — max lines per sliding window - `WINDOW_SECS = 3` — sliding window duration in seconds These will be exposed as config options in a future release (see TODO.md). --- ## What's NOT in These Patches (Deferred) Per user direction, the following are deferred to follow-up sessions: - **Matrix protocol production hardening** — Most complex of the group, gets its own session. - **Stout / Spacebar / Nerimity full builds** — These are currently true stubs whose `run_*()` functions just log placeholder notices. Building them out to "production ready" is multiple full protocol implementations, each comparable in scope to the Discord backend. - **Real inline image rendering** — The `try_render_inline_image()` function is a stub returning `Unsupported`. The graceful-fallback path (text placeholder + external open) is wired up, so this is a pure feature add with no risk to existing functionality. See TODO.md for the implementation outline. - **Configurable throttle limits** — Currently hardcoded; will be exposed via `config.toml` in a future release.