Add /history clean (and per-jid variant) to wipe existing chat history #124

Open
opened 2026-05-16 14:06:14 +00:00 by jabber.developer2 · 0 comments
Collaborator

Context

After PR #116 (feat/no-db-backlog-114), /history off is a real kill switch: it sets PREF_HISTORY=false, PREF_DBLOG=off, PREF_CHLOG=false, so new writes to the DB and to plain chatlogs stop. Backend switching via /privacy logging on|flatfile also takes effect at runtime without reconnect. Both are intentional improvements over master's behaviour.

What's still missing: the on-disk state from before the switch is not touched. After /history off:

  • ~/.local/share/profanity/<account>/chatlog.db (sqlite) or the flatfile backend directory remains on disk with all prior plaintext rows (including decrypted OMEMO / PGP / OTR content).
  • chatlogs/<account>/ plain-text files remain untouched.
  • The backend stays open; chatwin_db_history() keeps returning prior rows on scroll-up.
  • There is no built-in way to purge prior history short of removing files manually outside profanity.

This is by-design — off means "stop writing", not "delete past" — but the mental model of a user reaching for "turn off history" often includes "and forget what was recorded". A separate, explicit clean action closes that gap without overloading off.

Proposal

Add clean as a sub-command of /history, sitting next to /history off|on|switch introduced/normalised in #116:

/history clean                   # wipe DB + plain chatlogs for active account (requires confirm)
/history clean <jid>             # only one contact / MUC (no confirm — blast radius is small)
/history clean confirm           # second-step confirmation for account-wide wipe

/privacy logging clean is an alternative location, but placing it under /history keeps it adjacent to the kill-switch it complements.

Behaviour

  1. Confirmation gate for the account-wide wipe — destructive and irreversible. The per-jid variant can skip the confirm step.
  2. log_database_close().
  3. Delete:
    • Active backend storage for the account (sqlite DB file, or flatfile directory).
    • chatlogs/<account>/ plain-text directory.
    • Groupchat-log directory for the active account (PREF_GRLOG).
  4. If PREF_DBLOG != "off", re-initialize the backend so subsequent messages are recorded into a fresh store.
  5. Per-jid mode:
    • sqlite: DELETE FROM ChatLogs WHERE from_jid = ? OR to_jid = ? (parameterised, not concatenated).
    • flatfile: remove matching <jid>.log files in the backend dir.
    • plain chatlogs: remove the matching chatlogs/<account>/<jid>.log.

Backend hooks

Add to the db_backend vtable in src/database.h:

gboolean (*clean_all)(ProfAccount* account);
gboolean (*clean_for)(const char* barejid);

Implement in src/database_sqlite.c and src/database_flatfile.c.

Affected files

  • src/database.{c,h} — public API + backend dispatch.
  • src/database_sqlite.c, src/database_flatfile.c — backend implementations.
  • src/chatlog.c — plain-chatlog directory removal helper.
  • src/command/cmd_funcs.c::cmd_history — sub-command wiring.
  • src/command/cmd_defs.c — help text + autocomplete.
  • docs/profanity.1 — manpage entry.

Interaction with #116

  • Depends on #116: /history off only becomes a true persistence kill-switch after #116 merges, which is the prerequisite for clean to be coherent.
  • After #116, the unified /history tree (on / off / switch / ...) is the natural home for clean.
  • The status-bar [sqlite] / [flatfile] indicator (PREF_STATUSBAR_SHOW_DBBACKEND from #116) should reflect the post-clean state — backend may be re-initialized empty, or closed if PREF_DBLOG=off.

Interaction with PR #123 (scroll-state)

After clean, chatwin_db_history() on scroll-down returns DB_RESPONSE_EMPTY and WIN_SCROLL_REACHED_BOTTOM fires correctly — the indicator-reset paths from #123 keep working unchanged.

Out of scope / follow-ups

  • Retention policy: /history retain <days> — drop rows older than N days. Reduces the surface area without manual wipes.
  • DB at rest encryption (sqlcipher) — would make redact less of a workaround for on-disk privacy.
  • Secure-delete pass (overwrite before unlink) for filesystems where deleted blocks may persist. Probably not worth the complexity given how often the user's homedir is the real boundary.
## Context After [PR #116](https://git.jabber.space/devs/cproof/pulls/116) (`feat/no-db-backlog-114`), `/history off` is a real kill switch: it sets `PREF_HISTORY=false`, `PREF_DBLOG=off`, `PREF_CHLOG=false`, so new writes to the DB and to plain chatlogs stop. Backend switching via `/privacy logging on|flatfile` also takes effect at runtime without reconnect. Both are intentional improvements over master's behaviour. What's still missing: **the on-disk state from before the switch is not touched.** After `/history off`: - `~/.local/share/profanity/<account>/chatlog.db` (sqlite) or the flatfile backend directory remains on disk with all prior plaintext rows (including decrypted OMEMO / PGP / OTR content). - `chatlogs/<account>/` plain-text files remain untouched. - The backend stays open; `chatwin_db_history()` keeps returning prior rows on scroll-up. - There is no built-in way to purge prior history short of removing files manually outside profanity. This is by-design — `off` means "stop writing", not "delete past" — but the mental model of a user reaching for "turn off history" often includes "and forget what was recorded". A separate, explicit `clean` action closes that gap without overloading `off`. ## Proposal Add `clean` as a sub-command of `/history`, sitting next to `/history off|on|switch` introduced/normalised in #116: ``` /history clean # wipe DB + plain chatlogs for active account (requires confirm) /history clean <jid> # only one contact / MUC (no confirm — blast radius is small) /history clean confirm # second-step confirmation for account-wide wipe ``` `/privacy logging clean` is an alternative location, but placing it under `/history` keeps it adjacent to the kill-switch it complements. ### Behaviour 1. Confirmation gate for the account-wide wipe — destructive and irreversible. The per-jid variant can skip the confirm step. 2. `log_database_close()`. 3. Delete: - Active backend storage for the account (sqlite DB file, or flatfile directory). - `chatlogs/<account>/` plain-text directory. - Groupchat-log directory for the active account (`PREF_GRLOG`). 4. If `PREF_DBLOG != "off"`, re-initialize the backend so subsequent messages are recorded into a fresh store. 5. Per-jid mode: - sqlite: `DELETE FROM ChatLogs WHERE from_jid = ? OR to_jid = ?` (parameterised, not concatenated). - flatfile: remove matching `<jid>.log` files in the backend dir. - plain chatlogs: remove the matching `chatlogs/<account>/<jid>.log`. ### Backend hooks Add to the `db_backend` vtable in `src/database.h`: ```c gboolean (*clean_all)(ProfAccount* account); gboolean (*clean_for)(const char* barejid); ``` Implement in `src/database_sqlite.c` and `src/database_flatfile.c`. ### Affected files - `src/database.{c,h}` — public API + backend dispatch. - `src/database_sqlite.c`, `src/database_flatfile.c` — backend implementations. - `src/chatlog.c` — plain-chatlog directory removal helper. - `src/command/cmd_funcs.c::cmd_history` — sub-command wiring. - `src/command/cmd_defs.c` — help text + autocomplete. - `docs/profanity.1` — manpage entry. ## Interaction with #116 - Depends on #116: `/history off` only becomes a true persistence kill-switch after #116 merges, which is the prerequisite for `clean` to be coherent. - After #116, the unified `/history` tree (`on` / `off` / `switch` / ...) is the natural home for `clean`. - The status-bar `[sqlite] / [flatfile]` indicator (`PREF_STATUSBAR_SHOW_DBBACKEND` from #116) should reflect the post-clean state — backend may be re-initialized empty, or closed if `PREF_DBLOG=off`. ## Interaction with PR #123 (scroll-state) After `clean`, `chatwin_db_history()` on scroll-down returns `DB_RESPONSE_EMPTY` and `WIN_SCROLL_REACHED_BOTTOM` fires correctly — the indicator-reset paths from #123 keep working unchanged. ## Out of scope / follow-ups - Retention policy: `/history retain <days>` — drop rows older than N days. Reduces the surface area without manual wipes. - DB at rest encryption (sqlcipher) — would make `redact` less of a workaround for on-disk privacy. - Secure-delete pass (overwrite before unlink) for filesystems where deleted blocks may persist. Probably not worth the complexity given how often the user's homedir is the real boundary.
jabber.developer added this to the Plans (2025-2026) project 2026-05-18 09:46:12 +00:00
jabber.developer added the
Kind/Feature
Priority
Low
4
labels 2026-06-24 07:29:39 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: devs/cproof#124
No description provided.