SalastilandClaude Sonnet 5 20389e7396 Add Matrix verification/backup, per-protocol join pages, Discord friends, and expired-media/auth-failure recovery
- Matrix: interactive device verification (SAS emoji flow), recovery-key
  backup/restore, membership announcement moderation, member/room avatars,
  power-level-aware moderation menu, and an encryption lock indicator on
  the composer - verified live with two independent devices.
- Replace the single combined join panel with a dedicated page per
  protocol (IrcJoinPanel/MatrixJoinPanel/DiscordJoinPanel), routed by
  whichever account the "+" button was clicked for rather than listing
  every account in one expandable page.
- Discord: friends list (Online/All, click-to-DM, add-friend, matches
  READY's relationships + live PRESENCE_UPDATE), create-a-server, and
  join-by-invite alongside the existing DM-by-ID flow.
- Discord: an expired attachment-link fallback ("Open in Discord") for
  scrollback media whose signed cdn.discordapp.com URL has lapsed -
  Discord's own /attachments/refresh-urls re-sign endpoint hard-rejects
  this backend's user-token requests, confirmed live, so this opens the
  real message instead of showing a broken embed.
- Discord: detect gateway close code 4004 (revoked token) as a distinct
  ConnState::AuthFailed instead of retrying a dead credential forever;
  the Accounts pane shows a clear "needs login" state that routes
  straight to a fresh QR login, which upserts the same account id in
  place (no lost buffers/scrollback).
- Fix the unread-DM pinned-buffer flash never reliably triggering: an
  implicit property binding computed via nested closures over two
  separate properties wasn't consistently re-evaluated by QML's
  dependency tracker; replaced with an explicit recompute function called
  at every actual mutation point.
- Fix ChatBarWidget.qml's pill double-padding against BasePill's own
  padding.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-21 12:30:46 -04:00

dms-irc (Dank Chat)

A Dank Material Shell plugin that brings a unified chat frontend to the shell: IRC, Discord, and Sneedchat (SockChat, the Tor-only XenForo chat feature) today, with XMPP/Matrix/Slack support landing protocol by protocol without frontend changes. The architecture is deliberately service-agnostic - the QML side only ever sees a unified account/buffer/message model, never a protocol-specific concept.

Why two parts

Quickshell's QML runtime only exposes Unix-domain sockets, not raw TCP/TLS, so the actual protocol work can't live in QML. Instead:

  • chatd (chatd-rs/, Rust) speaks each protocol directly and translates it into a small unified JSON model (accounts, buffers, messages) over a Unix socket. It never exposes protocol-specific concepts to the plugin; it speaks the unified model, and each backend module happens to be how that model gets populated for a given service.
  • The QML plugin (top-level *.qml, plugin.json) spawns/supervises chatd and renders whatever it reports: a DankBar status pill, a slideout for quick access, and a floating window for a full chat session.
chatd-rs/               chatd - the Rust daemon, one crate per concern:
  chatd/src/backend/      one module per protocol (irc, discord, sockchat, ...)
  chatd/src/rpc/          the Unix-socket JSON-RPC server
  chatd/src/store.rs      SQLite-backed scrollback persistence
  chatd/src/runtime.rs    protocol-agnostic connection/buffer/message state
*.qml                    the DMS plugin surfaces plugin.json points at directly:
                           daemon supervisor, bar widget, startup check, settings entry
views/                   main chat UI: slideout/popout window, accounts, buffers, messages
settings/                per-protocol settings panels loaded by views/ChatSettings.qml
forms/                   per-protocol account-connect forms loaded by views/AccountsPanel.qml
plugin.json              DMS plugin manifest

Building chatd

cd chatd-rs
cargo build --release

Enable the plugin in DMS (Settings → Plugins, or dms ipc call plugins enable dankChat). StartupCheck.qml verifies the built binary exists at chatd-rs/target/release/chatd before allowing activation.

Opening the chat UI

Besides the DankBar pill (ChatBarWidget.qml), ChatDaemon.qml registers an IpcHandler under the dankChat target for scripting/keybinds:

dms ipc call dankChat toggle   # open/close the slideout (or the floating window, if that's what's open)
dms ipc call dankChat popout   # open (or bring forward) the floating window directly

Protocol backends

  • IRC - TLS with SASL PLAIN, NickServ auto-identify, autojoin.
  • Discord - official cross-device QR login (the same one discord.com/app offers), a real-time gateway client, message edit/delete/reactions/replies sync.
  • Sneedchat (SockChat) - the Tor-only chat built into Kiwi Farms. Runs over an embedded Tor client (or an external SOCKS5 proxy), solves the site's own proof-of-work anti-bot gate, and connects to every configured room simultaneously (one persistent websocket per room, sharing a single login). Supports message edit/delete and avatars (fetched through the same Tor session and cached locally, since the frontend has no route to a .onion host on its own).
  • XMPP/Matrix/Slack - not implemented yet; see the project plan for the milestone list.

Wire protocol

Newline-delimited JSON over a Unix socket at $XDG_RUNTIME_DIR/dms-chat/chatd.sock:

request:  {"id": 1, "method": "sendMessage", "params": {...}}
response: {"id": 1, "result": {...}}  or  {"id": 1, "error": "..."}
push:     {"event": "message", "data": {...}}

Core methods: listAccounts, listBuffers, listProtocols, addAccount, removeAccount, setAccountConnected, joinBuffer, partBuffer, sendMessage, editMessage, deleteMessage, subscribe/unsubscribe, getBacklog (SQLite-backed, persists across chatd restarts). Each protocol also has its own account-creation method (addAccount for IRC, addDiscordAccount, addSockChatAccount, ...).

Push events: message, messageUpdated, messageDeleted, reactionsChanged, presenceChange, bufferListChange, connectionState, notification, plus per-protocol login-flow events (discordLoginQr/discordLoginScanned/ discordLoginResult, sockChatLoginStatus/sockChatLoginResult). message and presenceChange are only delivered to clients that called subscribe for that buffer.

Status

Core loop is verified end to end through the actual DMS-spawned plugin: connect to real IRC networks over TLS with SASL PLAIN auth, log into Discord via QR and Sneedchat via username/password (+ optional TOTP 2FA), list/add accounts, join channels, send/ receive messages through a slideout or floating window, mentions flagged as highlights and pushed as notification events, and scrollback that survives a chatd restart. Not yet built: tab-complete, multi-account grouping in the buffer list, and XMPP/ Matrix/Slack backends. See the project plan for the full milestone list.

S
Description
No description provided
Readme
2.2 MiB
Languages
Rust 57.7%
QML 42.3%