257 lines
14 KiB
Markdown
Executable File
257 lines
14 KiB
Markdown
Executable File
# nirc-rs 0.10.1 — Status Report
|
|
|
|
**Version:** 0.10.1
|
|
**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** | ✅ Complete | ❌ Untested | libp2p P2P, mDNS, gossipsub, noise |
|
|
|
|
---
|
|
|
|
## 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` 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
|
|
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.rs` — `InputThrottle` 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 cycling** — `next_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.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 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 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 via `zeroize`.
|
|
- **Lightgray color fix** — `lightgray`/`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 |