Commit Graph

1876 Commits

Author SHA1 Message Date
aeb5cfd7db fix(xmpp): obfuscate client identity in protocol exchanges
Some checks failed
CI Code / Check spelling (pull_request) Successful in 16s
CI Code / Check coding style (pull_request) Successful in 28s
CI Code / Code Coverage (pull_request) Failing after 10m0s
CI Code / Linux (debian) (pull_request) Failing after 12m58s
CI Code / Linux (arch) (pull_request) Failing after 13m56s
CI Code / Linux (ubuntu) (pull_request) Failing after 16m18s
Modify version responses to return a generic client name and omit
version strings. Drop the "profanity." prefix from dynamically
generated JID resources. Clear the XEP-0115 capabilities node URI to
prevent service discovery fingerprinting. These adjustments reduce the
client's attack surface by minimizing identifiable metadata.
2026-07-09 17:49:21 +00:00
ca92d29179 fix(ui): measure dead pad space from cursor instead of absolute height
All checks were successful
CI Code / Check spelling (push) Successful in 20s
CI Code / Check coding style (push) Successful in 38s
CI Code / Code Coverage (push) Successful in 4m2s
CI Code / Linux (ubuntu) (push) Successful in 5m22s
CI Code / Linux (debian) (push) Successful in 7m21s
CI Code / Linux (arch) (push) Successful in 7m39s
Remove the /autoping warning subcommand and PREF_AUTOPING_WARNING
preference entirely. The warning was shown at connect time when
autoping was disabled but the server supported XEP-0199 ping.

The pad threshold logic previously used an absolute height
(PAD_THRESHOLD=12000) which was above the buffer cap and never
fired during normal scrolling. Replace with a dead-space measurement
(cursor position minus live buffer lines) that only triggers a redraw
when dead space exceeds PAD_DEAD_SPACE_LIMIT (2000 lines).

Author: jabber.developer2 <jabber.developer2@jabber.space>
2026-06-24 16:22:52 +00:00
02e679c277 feat(autoping): autoping availability warning
All checks were successful
CI Code / Check spelling (push) Successful in 16s
CI Code / Check coding style (push) Successful in 30s
CI Code / Linux (debian) (push) Successful in 5m25s
CI Code / Linux (ubuntu) (push) Successful in 5m33s
CI Code / Code Coverage (push) Successful in 7m54s
CI Code / Linux (arch) (push) Successful in 12m7s
## Introduced change

A new warning that notifies users when the connected XMPP server
advertises XEP-0199 (urn:xmpp:ping) support but the autoping feature
is disabled in settings. The warning can be toggled with
`/autoping warning on|off`.

The warning fires during the on-connect disco#info exchange, only for
responses from the server's own domain — responses from user JIDs or
subdomain services (e.g., conference servers) are excluded.

### Capabilities

- **On-connect detection**: Warning is emitted automatically when the
  server's disco#info response indicates `urn:xmpp:ping` support while
  autoping is disabled and the preference is enabled (default: on)
- **`/autoping warning on|off`**: Toggle the warning via the existing
  autoping command
- **Domain-scoped**: Only triggers for disco#info from the bound server
  domain; user JIDs and subdomain service JIDs are skipped
- **Case-insensitive domain matching**: Uses `g_ascii_strcasecmp` instead
  of `g_strcmp0` to handle case differences between the stanza `from`
  field and the bound domain
- **Display in settings**: Shown in both `/notify` and `/autoping`
  settings dumps, with consistent alignment and `(/autoping warning)`
  reference in each line
- **Autocomplete**: Dedicated `_autoping_autocomplete` function handles
  the `warning` subcommand with `on|off` completion

## Reasoning behind the change

Users connecting to servers that support XEP-0199 ping but have autoping
disabled may experience poorer connection stability. The warning draws
attention to this configuration mismatch without requiring users to read
documentation or dig into settings.

The warning is scoped to the server domain (not user JIDs or subdomain
services) because autoping is a connection-level feature — it only makes
sense in the context of the server's keepalive capabilities.

The warning preference defaults to `on` so users are informed by default,
but can be disabled with `/autoping warning off` if they prefer not to
see it.

## Implementation details

### Warning logic (`src/xmpp/iq.c`)

`_disco_autoping_warning_message()` is called from the on-connect
disco#info handler when the `from` field matches the bound domain. It
checks three conditions:

1. Server features contain `urn:xmpp:ping`
2. Autoping interval is 0 (disabled)
3. `PREF_AUTOPING_WARNING` is true

All three must be true for the warning to display.

### Domain matching

`g_ascii_strcasecmp(from, connection_get_domain())` is used instead of
`g_strcmp0` to handle case differences. This prevents the warning from
silently skipping if a server echoes the `from` field in a different
case than the bound domain.

### Command integration (`src/command/cmd_*.c`)

- `cmd_defs.c`: Added `/autoping warning on|off` syntax and argument
  description
- `cmd_funcs.c`: Added `warning` subcommand handler that calls
  `_cmd_set_boolean_preference` with `PREF_AUTOPING_WARNING`
- `cmd_ac.c`: Registered dedicated `_autoping_autocomplete` that handles
  the `warning` subcommand with `on|off` boolean completion

### Preference storage (`src/config/preferences.c`)

- Group: `PREF_GROUP_NOTIFICATIONS`
- Key: `autoping.warning`
- Default: `TRUE`

### Settings display (`src/ui/console.c`)

The autoping warning preference is shown in both `cons_notify_setting()`
and `cons_autoping_setting()` with consistent column alignment and a
`(/autoping warning)` reference in each line.

### Tests (`tests/functionaltests/test_autoping.c`)

Six functional tests cover all condition combinations:

| Test | Server ping | Autoping | Warning pref | Expected |
|---|---|---|---|---|
| `autoping_warning_shown_when_disabled` | yes | off | on | warning shown |
| `autoping_warning_not_shown_when_server_unsupported` | no | off | on | no warning |
| `autoping_warning_not_shown_when_autoping_enabled` | yes | on | on | no warning |
| `autoping_warning_not_shown_when_user_disabled` | yes | off | off | no warning |
| `autoping_warning_not_shown_for_user_jid` | yes (from user JID) | off | on | no warning |
| `autoping_warning_not_shown_for_subdomain_service` | yes (from subdomain) | off | on | no warning |

Co-authored-by: Jabber Developer2 <jabber.developer2@jabber.space>
2026-06-23 11:11:25 +00:00
2d3d1ced71 ref(ui): use MAX utility method for code conciseness and clarity
All checks were successful
CI Code / Check coding style (push) Successful in 1m28s
CI Code / Check spelling (push) Successful in 2m20s
CI Code / Linux (ubuntu) (push) Successful in 5m16s
CI Code / Code Coverage (push) Successful in 3m51s
CI Code / Linux (debian) (push) Successful in 5m52s
CI Code / Check coding style (pull_request) Successful in 35s
CI Code / Check spelling (pull_request) Successful in 23s
CI Code / Linux (arch) (push) Successful in 8m34s
CI Code / Linux (debian) (pull_request) Successful in 4m25s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m35s
CI Code / Code Coverage (pull_request) Successful in 3m30s
CI Code / Linux (arch) (pull_request) Successful in 8m55s
2026-06-20 09:40:11 +00:00
adb078a3e2 fix(ui): reserve pad height per message to prevent multi-line clip and scroll desync
Some checks failed
CI Code / Check spelling (pull_request) Successful in 18s
CI Code / Check coding style (pull_request) Successful in 30s
CI Code / Code Coverage (pull_request) Successful in 3m24s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m54s
CI Code / Linux (debian) (pull_request) Successful in 6m58s
CI Code / Linux (arch) (pull_request) Successful in 7m7s
CI Code / Check spelling (push) Successful in 16s
CI Code / Check coding style (push) Successful in 32s
CI Code / Code Coverage (push) Failing after 3m24s
CI Code / Linux (debian) (push) Failing after 5m38s
CI Code / Linux (ubuntu) (push) Failing after 5m51s
CI Code / Linux (arch) (push) Failing after 7m38s
A tall multi-line message printed near the bottom of the ncurses pad was clipped because _win_print_internal grew the pad from the current cursor only (_win_ensure_pad_capacity(getcury)), not the height of the message about to be printed. The clipped message's captured height (e.g. 1 row for a 49-row message) was wrong while win_redraw later rendered it in full; the resulting buffer->lines / y_start_pos mismatch desynced the page-up scroll anchor, producing a ~one-page jump when scrolling past such messages from history.

Estimate the rendered height (hard newlines + soft-wrap over the usable width) and reserve that many rows before printing, so the message is never clipped and its captured height matches the redraw. All print paths go through _win_print_internal, so incoming/outgoing/history are covered.

Regression from the upstream sync (72f4f186d), which replaced the fixed-size pad with the dynamic _win_ensure_pad_capacity model.
2026-06-20 11:59:19 +03:00
bfd7064a40 build: add missing includes to header files
This change adds necessary `#include` directives that were previously
omitted in some header files. Without these includes, compilation
could fail or produce undefined behavior when the headers are used
in isolation (i.e., before their dependencies are included elsewhere).

Ensures better modularity and reliability of header usage.
2026-06-16 11:21:11 +00:00
3f6b8f69fd fix(ui): raise pad redraw threshold above buffer cap to fix history scroll
All checks were successful
CI Code / Check spelling (pull_request) Successful in 19s
CI Code / Check coding style (pull_request) Successful in 30s
CI Code / Code Coverage (pull_request) Successful in 3m21s
CI Code / Linux (debian) (pull_request) Successful in 4m49s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m55s
CI Code / Check coding style (push) Successful in 31s
CI Code / Check spelling (push) Successful in 19s
CI Code / Linux (arch) (pull_request) Successful in 6m39s
CI Code / Linux (debian) (push) Successful in 4m16s
CI Code / Code Coverage (push) Successful in 3m29s
CI Code / Linux (ubuntu) (push) Successful in 4m32s
CI Code / Linux (arch) (push) Successful in 10m51s
PAD_THRESHOLD (3000) sat below the buffer line cap (PAD_SIZE - PAD_SIZE/10 = 9000), so _win_ensure_pad_capacity() fired a full win_redraw() from the hot print path on every message once a chat exceeded 3000 rendered lines. During history paging this turned one redraw per fetch into dozens, corrupting per-entry y_start_pos (offset jumps, dropped/skipped messages) and causing ~10s lag per page. The flat-file backend was byte-identical across the regression; the fault was purely in the UI pad path from the upstream merge.

Raise PAD_THRESHOLD to 12000 (above the cap) so the reclaim redraw only fires to drop dead pad space in long append-only sessions, never during scrolling. Also size the pad once to buffer->lines+100 in win_redraw() instead of shrinking to PAD_MIN_HEIGHT and regrowing per entry, removing the residual per-redraw wresize churn.
2026-06-08 16:03:33 +03:00
a04a8948e1 fix(chatwin): only fire plugins_post_chat_message_display on incoming
All checks were successful
CI Code / Check coding style (pull_request) Successful in 34s
CI Code / Check spelling (pull_request) Successful in 22s
CI Code / Linux (debian) (pull_request) Successful in 4m38s
CI Code / Code Coverage (pull_request) Successful in 3m12s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m34s
CI Code / Linux (arch) (pull_request) Successful in 6m57s
CI Code / Check spelling (push) Successful in 17s
CI Code / Check coding style (push) Successful in 31s
CI Code / Code Coverage (push) Successful in 3m45s
CI Code / Linux (debian) (push) Successful in 4m38s
CI Code / Linux (ubuntu) (push) Successful in 4m49s
CI Code / Linux (arch) (push) Successful in 6m46s
The trigger was wired into outgoing / outgoing-carbon / history paths
too, which made plugins like sounds.py play the "new message" sound
when opening a chat (history loads), sending a message yourself, or
receiving a carbon of your own sent message from another device.

Restrict the call to chatwin_incoming_msg — matches the semantic of
"a remote party sent a chat message and it was displayed".
2026-06-01 16:31:14 +03:00
c1093db090 fix(editor): prevent UI redraw conflicts during editor suspend/resume
All checks were successful
CI Code / Check spelling (push) Successful in 16s
CI Code / Check coding style (push) Successful in 31s
CI Code / Code Coverage (push) Successful in 3m36s
CI Code / Linux (debian) (push) Successful in 4m43s
CI Code / Linux (ubuntu) (push) Successful in 4m54s
CI Code / Linux (arch) (push) Successful in 6m46s
Guard against re-entrant editor launches, abort editor on Ctrl-Z,
and centralize suspend-aware redraws through prof_doupdate() to prevent
terminal corruption when SIGTSTP is received while editor is active.

Removes SIGUSR1 editor escape in favor of standard pkill <editor> recovery.
2026-06-01 12:21:34 +00:00
72f4f186da merge: sync upstream profanity-im/profanity
All checks were successful
CI Code / Check spelling (push) Successful in 18s
CI Code / Check coding style (push) Successful in 34s
CI Code / Code Coverage (push) Successful in 2m36s
CI Code / Linux (debian) (push) Successful in 4m41s
CI Code / Linux (ubuntu) (push) Successful in 4m52s
CI Code / Linux (arch) (push) Successful in 5m40s
Sync with upstream profanity-im/profanity.

Major upstream changes incorporated:

Memory management
  - Replace malloc+memset with g_new0 throughout codebase
  - Adopt auto_gchar / auto_gcharv / auto_gerror / auto_jid cleanup macros
  - Replace free() with g_free() for GAlloc'd memory

Editor rewrite
  - Remove pthread-based async editor; use GChildWatch callback API
  - New launch_editor(initial_content, callback, user_data) interface
  - Proper signal handling (SIGINT, SIGTSTP, SIGPIPE reset in child)
  - ui_suspend()/ui_resume() integration for TTY management

OMEMO improvements
  - Dual backend support: libsignal-protocol-c and libomemo-c
  - Proper pre-key removal after use (XEP-0384 compliance)
  - Automatic pre-key regeneration when store drops below threshold
  - New functions: omemo_is_device_active(), omemo_is_jid_trusted()
  - omemo_get_jid_untrusted_fingerprints() for better error messages
  - Fingerprint notifications on new device identity discovery
  - Deterministic pre-key ID generation tracking max_pre_key_id
  - omemo_trust_changed() UI updates on trust state changes

JID validation
  - RFC 6122-compliant validation in jid_is_valid()
  - Character-level checks (RFC 6122 forbidden chars: & ' / : < > @)
  - Length limits: 1023 per component, 3071 total
  - New jid_is_valid_user_jid() for user vs. service JID distinction

Database
  - Schema migration v3: UNIQUE constraint on archive_id for deduplication
  - Triggers for corrected message tracking (replaces_db_id / replaced_by_db_id)
  - db_history_result_t return type, _truncate_datetime_suffix()

UI / console
  - win_warn_needed() / win_warn_sent() warning deduplication hash table
  - PAD_MIN_HEIGHT dynamic pad sizing with PAD_THRESHOLD auto-cleanup
  - Spellcheck integration in input field with Unicode word detection
  - cons_spellcheck_setting() for /settings ui output
  - /[command]? shortcut for command help

Account config
  - Account name sanitization for GKeyFile special chars ([ ] = # \n \r)
  - Replace popen() with g_spawn_sync() for eval_password
  - TLS policy: add "direct" option alongside legacy

Connection
  - Port validation with g_assert (0–65535)
  - SHA-256 certificate fingerprint support (XMPP_CERT_PUBKEY_FINGERPRINT_SHA256)
  - "direct" TLS policy alias for legacy SSL

Common utilities
  - str_xml_sanitize() for XML 1.0 illegal character removal
  - string_matches_one_of() with formatted error messages
  - valid_tls_policy_option() helper
  - prof_date_time_format_iso8601() utility
  - Improved strip_arg_quotes() with backslash unescaping
  - prof_occurrences() uses g_slist_prepend + reverse for performance

PGP / OX
  - Proper GPGME resource cleanup with goto-cleanup pattern
  - g_string_free(xmppuri) leak fix in _ox_key_lookup

CSV export
  - Use GString + g_file_set_contents instead of raw write() syscalls

Tests
  - Restructured into subdirectories: command/, config/, xmpp/, ui/, omemo/, otr/, pgp/
  - New test_cmd_ac.c for autocompleter unit tests
  - Updated stubs for new UI suspend/resume functions

License headers
  - Migrate to SPDX-3.0 identifiers (GPL-3.0-or-later WITH OpenSSL-exception)

────────────────────────────────────────────────────
cproof-specific preservations:

  - XEP-0308 LMC: replace_id ?: id logic in message/stanza/omemo
  - Force encryption: cmd_force_encryption, test_forced_encryption
  - CWE-134: format string protection (cons_show("%s", ...))
  - y_start_pos-based paging in window.c
  - db_history_result_t return type, _truncate_datetime_suffix()

Merge-time fixes:

  - common.c: format-security (-Werror) — cons_show(errmsg) → cons_show("%s", errmsg)
  - database.c: null-deref guard — !msg->timestamp → msg && !msg->timestamp
  - console.c: implicit size_t → int cast — (int)(maxlen + 1)
  - tlscerts.c: %d for size_t — %zu

Build system:
  - Kept autotools (Makefile.am, configure.ac); upstream uses Meson
  - Restored deleted files: bootstrap.sh, autogen.sh, ax_valgrind_check.m4, configure-debug
  - Updated Makefile.am test paths for subdirectory structure
  - Added test_cmd_ac, test_forced_encryption to test sources

Functional tests:
  - Use cproof version; upstream requires stbbr_for_xmlns from updated stabber
  - Not yet available in devs/stabber fork

Closes #64

Merge author: jabber.developer2
Commits authors:
 Michael Vetter <jubalh@iodoru.org>
& Steffen Jaeckel <s@jaeckel.eu>
2026-05-26 17:48:14 +00:00
a3a45ad477 fix(ui): preserve messages in non-chat windows while scrolled
All checks were successful
CI Code / Check spelling (push) Successful in 17s
CI Code / Check coding style (push) Successful in 31s
CI Code / Code Coverage (push) Successful in 2m43s
CI Code / Linux (debian) (push) Successful in 4m33s
CI Code / Linux (ubuntu) (push) Successful in 4m48s
CI Code / Linux (arch) (push) Successful in 5m36s
_win_printf dropped buffer append and render for any window in paged
state, but only WIN_CHAT can recover lost messages via chatwin_db_history()
on scroll-down. WIN_MUC, WIN_PRIVATE and WIN_AI have no such fallback, so
incoming and outgoing messages were silently lost when the user was viewing
history.

Introduce log_database_can_recover_messages() to check whether the DB
backend can replay messages (returns FALSE when PREF_DBLOG is "off",
"redact", or no backend is active). Gate the WIN_CHAT early return in
_win_printf() on this check: when recovery is impossible, fall through
and append to the buffer so messages remain visible on scroll-down.

Add a buffer-bottom reset in win_page_down() for non-chat windows.
WIN_SCROLL_REACHED_BOTTOM is only set on the is_chat DB branch, so
non-chat windows never clear paged on their own; reset paged and
unread_msg when the last line of the buffer reaches the screen.

Add missing scroll rendering for AI windows in the title bar draw
function, ensuring AI windows display their scrolled state consistently
with other window types.

Remove the manual paged/unread_msg reset before printing the user
message in cl_ev_send_ai_msg() -- it was a local workaround for the
same drop and is no longer needed.
2026-05-16 15:47:49 +00:00
2952466abd feat(history): consolidate logging controls and add dbbackend statusbar indicator
All checks were successful
CI Code / Check spelling (push) Successful in 18s
CI Code / Check coding style (push) Successful in 33s
CI Code / Code Coverage (push) Successful in 2m42s
CI Code / Linux (debian) (push) Successful in 4m40s
CI Code / Linux (ubuntu) (push) Successful in 4m53s
CI Code / Linux (arch) (push) Successful in 5m38s
Deprecate /logging command in favor of /history for chat logging control.
/history off now stops persistence (sets PREF_DBLOG=off + PREF_CHLOG=false)
in addition to hiding history on open. /history on restores persistence
(re-enabling PREF_DBLOG=on if it was off) and PREF_CHLOG.

statusbar
- PREF_STATUSBAR_SHOW_DBBACKEND (default ON) gates the [sqlite] /
  [flatfile] indicator; toggle via "/statusbar show|hide dbbackend"

/history off|on
- "/history off" now stops persistence as well as hiding history on
  open: sets PREF_DBLOG=off + PREF_CHLOG=false in addition to
  PREF_HISTORY=false
- "/history on" restores persistence (re-enabling PREF_DBLOG=on if
  it was off) and PREF_CHLOG, in addition to PREF_HISTORY=true

/logging
- Deprecated /logging command. It now prints a single notice
  pointing to /history; CMD_PREAMBLE trimmed (min_args=0, no
  setting_func, syntax/args/examples dropped); subcommand 'group'
  removed from autocomplete
- All "use '/logging chat on' to enable" hints replaced with
  "/history on" across /omemo-log, /pgp-log, /otr-log, and /ox-log

/privacy logging
- Single-pass validation across {on, off, redact, flatfile}
- Backend-switching values (on, flatfile) now take effect
  immediately when connected (via log_database_switch_backend),
  matching "/history switch" behaviour; off/redact only flip
  pref bits and keep the live backend open

/correction off
- win_print_outgoing and win_print_outgoing_with_receipt now gate
  _win_correct on PREF_CORRECTION_ALLOW, matching incoming-msg
  paths. Previously a peer's correction reflected via XEP-0280
  carbons (or the user's own /correct invocation) was applied
  in-buffer regardless of the pref

console
- Drop orphaned /logging chat reference from cons_privacy_setting()
- Delete cons_logging_setting() and remove its call from
  cons_show_log_prefs()

autocomplete
- Add dbbackend to statusbar_show_ac
- Remove logging_ac entries for chat/group subcommands
- Remove _logging_autocomplete() param handler for chat subcommand

database_flatfile
- Two local g_strndup allocations switched from char* with manual
  g_free to auto_gchar gchar* for automatic cleanup

tests
- Update test_cmd_otr.c to expect new /history-on warning messages

@author: jabber.developer2 <jabber.developer2@jabber.space>
2026-05-16 15:33:42 +00:00
9e5dfb14f8 feat(ai): add AI client with multi-provider chat support
All checks were successful
CI Code / Check spelling (push) Successful in 18s
CI Code / Check coding style (push) Successful in 29s
CI Code / Code Coverage (push) Successful in 2m44s
CI Code / Linux (debian) (push) Successful in 4m46s
CI Code / Linux (ubuntu) (push) Successful in 4m59s
CI Code / Linux (arch) (push) Successful in 5m56s
Add an AI client module that integrates with OpenAI-compatible API
providers (OpenAI, Perplexity, and custom endpoints) to provide
AI-assisted chat within CProof. Users can start sessions with /ai start,
send prompts, receive responses in a dedicated AI window, switch between
providers and models, and manage API keys — all with tab-completion.

Providers are configured via /ai set commands with per-provider API keys,
endpoints, default models, and custom settings. Two default providers
(openai, perplexity) are seeded on first use. Provider state persists in
[ai/<name>] sections of the preferences keyfile with automatic migration
from the previous flat-key format.

The /ai command integrates into the existing command system with 8
subcommands covering provider management, session lifecycle, model
fetching, and conversation clearing. Autocomplete uses the standard
flat prefix-matching chain for reliable tab-completion at every nesting
level. A new ProfAiWin window type is added to the window system.

Architecture:

Async design: HTTP requests run on a background thread (pthread) to avoid blocking the ncurses UI loop; results are displayed on the main thread via direct function calls
Thread safety: AIProvider and AISession use atomic ref-counting and mutex-protected session state; the request thread snapshots all session data before making the HTTP call
Window validation: wins_ai_exists() prevents use-after-free when the user closes the AI window during an in-flight HTTP request (~60s)
Privacy: store:false is sent with every request to prevent providers from persisting conversations or using them for training
Response size limit: 10MB cap with immediate curl abort via CURL_WRITEFUNC_ERROR to prevent OOM
JSON parsing uses unified helpers for both chat responses and error
envelopes with consistent escape decoding. The response parser tries
Perplexity /v1/responses "text" field first, then falls back to OpenAI
"content". Error parsing extracts provider error.message from the
standard envelope format. Model parsing handles multiple API response
formats (OpenAI list, Perplexity, array) including edge cases.

Tests include 470+ lines of unit tests covering provider management,
session lifecycle, JSON parsing (multiple formats), autocomplete cycling,
and error handling, plus functional tests for /ai command dispatch.
A stub_ai.c module isolates unit tests from UI dependencies.
2026-05-15 02:21:54 +00:00
3f36c303c2 feat(history): flat-file backend with bidirectional SQLite migration
All checks were successful
CI Code / Check spelling (push) Successful in 21s
CI Code / Check coding style (push) Successful in 31s
CI Code / Code Coverage (push) Successful in 2m21s
CI Code / Linux (ubuntu) (push) Successful in 4m30s
CI Code / Linux (debian) (push) Successful in 6m43s
CI Code / Linux (arch) (push) Successful in 10m8s
A flat-file alternative to the SQLite chatlog backend with runtime
switching, full migration tooling, integrity verification, and a
synthetic load harness. SQLite remains the default; both backends share
one dispatch layer (db_backend_t vtable) so callers don't change.

Storage layout
- Per-contact append-only `flatlog/<account>/<contact>/history.log`
  under XDG_DATA_HOME, one line per message
- Single-line file header with embedded format-version marker
  (FLATFILE_FORMAT_VERSION); reader warns on missing or mismatched
  marker, writer and checker stay in sync via preprocessor
  stringification
- Deterministic key=value metadata (`id`, `aid`, `corrects`, `to`,
  `to_res`, `read`) plus escaped body \u2014 `\|`, `\]`, `\\`, `\n`, `\r`
  literals prevent log injection
- Sparse byte-offset index (FF_INDEX_STEP=500) per contact for
  O(log n) time-range lookups; rebuilt on inode / size / mtime
  change, extended in-place when the file just grew
- Per-contact GHashTable caches for archive_id presence and
  stanza_id \u2192 from_jid mapping (O(1) MAM dedup, O(1) LMC sender
  validation)

Hardening
- Path-traversal protection: JID directory name normalisation
  (`@` \u2192 `_at_`, slashes and `..` rejected at construction); every
  per-contact path is anchored under the account's flatlog/
  directory and validated before open
- Symlink-attack protection: every fopen / open uses O_NOFOLLOW; on
  ELOOP the operation aborts with an error rather than following
- Filesystem permissions: log files created with mode 0600,
  directories with mode 0700; both enforced at creation, verified
  on each open and reported on drift by `/history verify`
- Atomic crash-safe export: write to a temp file via mkstemp (mode
  0600, random suffix, no name collisions between concurrent
  exports), fsync, then rename \u2014 partial state never replaces the
  live file
- Concurrency: advisory flock(LOCK_EX) held for the duration of
  every write, including append from live messages and full rewrite
  from export, so two profanity processes can't interleave bytes
  on the same log
- DoS / abuse guards:
    * FF_MAX_LINE_LEN = 10 MB \u2014 lines longer than this are rejected
      at read with a warning; the parser will not allocate
      unbounded memory for a single record
    * FF_MAX_LMC_DEPTH = 100 \u2014 `corrects:` chain walk stops at this
      depth and emits a warning, preventing a malicious correction
      cycle from spinning the apply pass
    * FF_VERSION_SCAN_MAX = 16 \u2014 header version probe never reads
      past 16 leading comment lines, even on garbage input
    * Empty / inverted byte-range early-return in page-up read path
      so a malformed time filter cannot cause an unbounded scan
    * Zero-entry index guard so a file whose every line failed to
      parse cannot cause a NULL deref on later page-up
- LMC sender validation: an incoming correction whose sender does
  not match the original message's sender is rejected at write
  time and surfaced via cons_show_error; a cycle in the apply pass
  is broken via a visited-set
- jid_create_from_bare_and_resource treats NULL, empty string, and
  the literal "(null)" as no resource and returns a bare jid;
  similar normalisation for barejid eliminates the legacy
  "user@host/(null)" artefact that leaked into stored fulljids
  whenever g_strdup_printf("%s", NULL) ran inside create_fulljid

Commands
- `/history switch sqlite|flatfile` \u2014 runtime backend swap, closes
  the old backend and opens the new one without reconnecting
- `/history export [<jid>]` \u2014 SQLite -> flat-file, merging with any
  existing flatlog (dedup keyed on a SHA-256 hash mixing stanza_id,
  timestamp, from_jid, body \u2014 robust against id reuse by older
  clients)
- `/history import [<jid>]` \u2014 flat-file -> SQLite, same merge
  semantics, runs inside a single SQLite transaction with rollback
  on per-contact failure
- `/history verify [<jid>]` \u2014 integrity check; emits a structured
  list of issues (ERROR / WARNING / INFO) per file:
    * file-level: missing log, wrong permissions (\u2260 0600), UTF-8
      BOM present, CRLF line endings, empty file
    * line-level: invalid UTF-8 (with byte offset), embedded
      control characters, unparsable lines, timestamps out of
      order, duplicate `id:` and `aid:` (tracked separately so a
      stanza/archive id collision isn't double-reported)
    * cross-line: broken `corrects:` references whose target id is
      not present in the file
- `/history backend` \u2014 show currently active backend
- Active backend indicator `[sqlite]` / `[flatfile]` in the status
  bar next to the JID
- Roster-JID autocomplete for verify / export / import
- export and import open a SQLite handle on demand when the
  flatfile backend is currently active, so migration works
  regardless of which backend is live

Tests
- Unit: database_export (parser round-trip, escape/unescape, dedup
  key stability, JID normalisation), database_stress (14 cases
  exercising rapid writes, large messages, deep LMC chains, MAM
  dedup, concurrent contacts)
- Functional: history persistence across reconnects, export /
  import round-trip with content equality, MUC migration,
  timestamp normalisation across timezones
- Bench harness P1\u2013P5 (synthetic load: bulk insert, time-range
  read, page-up scroll, MAM ingest, mixed workload) and failure
  modes F1\u2013F17 (page-up cursor and forward-iteration symmetry,
  oversized lines, MAM dedup, LMC depth and cycles, BOM/CRLF,
  missing log, empty file, mtime+inode flip, broken corrects, etc.)
- All bench tests integrate with the existing make targets and
  emit CSV rows for baseline comparison

Author: jabber.developer2 <jabber.developer2@jabber.space>
Reviewed-by: jabber.developer <jabber.developer@jabber.space>
2026-05-05 19:26:07 +00:00
9ec01fa8cc fix: CWE-134 format string audit and compiler hardening
All checks were successful
CI Code / Check spelling (push) Successful in 20s
CI Code / Check coding style (push) Successful in 36s
CI Code / Code Coverage (push) Successful in 5m38s
CI Code / Linux (ubuntu) (push) Successful in 7m1s
CI Code / Linux (debian) (push) Successful in 7m5s
CI Code / Linux (arch) (push) Successful in 7m19s
Security:
Fix CWE-134 in iq.c: user-controlled string passed as format argument
Add G_GNUC_PRINTF annotations to all variadic printf-like wrappers
in ui.h, log.h and http_common.h
Compiler flags (configure.ac):

Replace basic -Wformat/-Wformat-nonliteral with -Wformat=2
Add -Wextra, -Wnull-dereference, -Wpointer-arith,
-Wimplicit-function-declaration, -Wundef, -Wfloat-equal,
-Wredundant-decls, -Walloc-zero
Add -fstack-protector-strong, -fno-common, -D_FORTIFY_SOURCE=2
Add GCC-specific flags via AC_COMPILE_IFELSE: -Wlogical-op,
-Wduplicated-cond, -Wduplicated-branches, -Wstringop-overflow,
-Warray-bounds=2
Suppress noisy -Wextra sub-warnings: -Wno-unused-parameter,
-Wno-missing-field-initializers, -Wno-sign-compare,
-Wno-cast-function-type
Remove AM_CFLAGS/CFLAGS duplication
Bug fixes found by new warnings:

chatlog.c: non-MUCPM redact path passed resourcepart instead of NULL
rosterwin.c: merge duplicated if/else branches into single condition
omemo.c: redundant else-if in omemo_automatic_start; remove
unnecessary scope block and goto, use early return
console.c: pointer compared to integer 0 instead of NULL
stanza.c: increase pri_str/idle_str buffers from 10 to 12 bytes
(INT_MIN = -2147483648 needs 12 bytes including NUL)
vcard.c: NULL guard for filename before g_file_set_contents
api.c: broken log_warning() calls with extra format argument
Format mismatch fixes:

chatwin.c: Jid* → char* for %s
connection.c: %x → %lx for long flags
cmd_funcs.c: %d → %zu for size_t; cast gpointer to char* for %s
cmd_defs.c: %d → %u for g_list_length() return (guint)
iq.c: barejid → fulljid for from_jid
console.c, mucwin.c, privwin.c, account.c, omemo.c, presence.c:
gpointer → (char*) casts for %s
Const-correctness and cleanup:

database.c: const for type, query, sort variables
form.c/xmpp.h: const for form_set_value parameter
files.c: refactor to early return, eliminating NULL logfile path
muc.c/muc.h: remove meaningless top-level const on return type
common.c: const for URL string literal
Remove stale declarations: cons_show_desktop_prefs (ui.h),
connection_set_priority (connection.h),
omemo_devicelist_configure_and_request (omemo.h)
test_common.c: add currb NULL check to silence -Wnull-dereference
Tooling (check-cwe134.sh):

Reduce from 5 checks to 2 (checks 1-3 redundant with -Wformat=2)
Check 1: verify known wrappers have G_GNUC_PRINTF attribute
Check 2: auto-detect unannotated variadic printf-like functions
Match both const char* and const gchar* in variadic patterns

Author: jabber.developer2 <jabber.developer2@jabber.space>
2026-03-07 11:55:50 +01:00
467222d0ca fix(ui,db): harden NULL handling, fix CWE-134, optimize iterations
Some checks failed
CI Code / Code Coverage (push) Failing after 10m34s
CI Code / Check spelling (push) Failing after 10m47s
CI Code / Check coding style (push) Failing after 11m4s
CI Code / Linux (ubuntu) (push) Failing after 11m19s
CI Code / Linux (debian) (push) Failing after 11m28s
CI Code / Linux (arch) (push) Failing after 11m38s
security(CWE-134): fix format string injections + add CI check
fix(ui): subwindow lifecycle, newwin/newpad guards, fallback timestamps
fix(db): sqlite cleanup on failures, sqlite3_close_v2
fix(xmpp): queued_messages loop, barejid leak
perf(core): g_hash_table_iter_init instead of g_hash_table_get_keys
refactor(ui): CLAMP macro in _check_subwin_width
test: XEP-0012 and XEP-0045 functional tests

Author: jabber.developer2
Closes #58, #85
2026-02-06 19:27:40 +01:00
f446f48d07 feat(ui,window): add accurate unread indicators and history paging support
Some checks failed
CI Code / Check spelling (push) Successful in 18s
CI Code / Linux (arch) (push) Has been cancelled
CI Code / Linux (debian) (push) Has been cancelled
CI Code / Linux (ubuntu) (push) Has started running
CI Code / Check coding style (push) Has been cancelled
- Track unread message indicators and paging state in the window component
- Clear and restore unread markers correctly when navigating between conversations
- Suppress buffer updates and message printing while viewing history to prevent
  unwanted scroll jumps and viewport lock

Also includes minor code-style, whitespace, and comment cleanups as well as
updated documentation for metrics and buffer handling.
2025-12-02 17:59:25 +01:00
fac1e224bc fix(scroll): handle edge case of extremely long messages
All checks were successful
CI Code / Check coding style (pull_request) Successful in 34s
CI Code / Check spelling (pull_request) Successful in 45s
CI Code / Linux (arch) (pull_request) Successful in 10m43s
CI Code / Linux (ubuntu) (pull_request) Successful in 13m11s
CI Code / Linux (debian) (pull_request) Successful in 16m46s
CI Code / Check spelling (push) Successful in 18s
CI Code / Check coding style (push) Successful in 32s
CI Code / Linux (arch) (push) Successful in 12m56s
CI Code / Linux (debian) (push) Successful in 13m28s
CI Code / Linux (ubuntu) (push) Successful in 16m20s
Prior commit (6ad8a190) did not properly handle overflow by long (9000 lines) message,
to address this issue, multiple changes were made:
- Add lines recalculation on win_redraw
- Move `prof_buff_t` struct to header file so its lines could be externally changed
- Call win_redraw once overflow is detected: it allows to recalculate sizes in lines and apply changes to the buffer
2025-10-08 13:00:32 +02:00
6ad8a19053 fix(buffer): use dynamic buffer size to prevent unnecessary buffer cleanups
All checks were successful
CI Code / Check spelling (pull_request) Successful in 22s
CI Code / Check coding style (pull_request) Successful in 38s
CI Code / Linux (arch) (pull_request) Successful in 13m4s
CI Code / Linux (debian) (pull_request) Successful in 13m32s
CI Code / Linux (ubuntu) (pull_request) Successful in 16m23s
CI Code / Check spelling (push) Successful in 19s
CI Code / Check coding style (push) Successful in 37s
CI Code / Linux (arch) (push) Successful in 13m8s
CI Code / Linux (ubuntu) (push) Successful in 16m2s
CI Code / Linux (debian) (push) Successful in 16m26s
Refactor buffer trimming logic to use dynamic line counts (_lines per entry)
against PAD_SIZE (10k) instead of fixed entry count (MAX_BUFFER_SIZE=200). This
prevents premature cleanups for short messages, reduces scrolling disruptions
during history loads, and scales better with rendered content size.

Delete oldest/newest entry from opposite end only when total lines approach
ncurses pad limit, minimizing unnecessary deletions.
Simplify overflow warning log by removing unused MAX_BUFFER_SIZE reference.

Update buffer.c header for improved DX:
- Add detailed module overview explaining role (in-memory UI buffer vs. DB
persistence), key features (trimming, metadata), and integration (ncurses).
- Shorten copyright/license boilerplate to concise pointer (LICENSE ref).
- Add fork notice; preserve original copyrights per GPLv3.

Partially addresses #36 (stuck scroll mitigation via fewer cleanups)
Related to #36
2025-10-07 15:12:20 +02:00
Steffen Jaeckel
75b378cf54 Don't use memchr() on strings potentially shorter than 4 bytes.
When running profanity under Valgrind with slashguard enabled, the
following error could occur:

```
[...]
==4021347== Invalid read of size 1
==4021347==    at 0x4851F49: memchr (vg_replace_strmem.c:986)
==4021347==    by 0x45CEAD: _inp_slashguard_check (inputwin.c:183)
==4021347==    by 0x45CEAD: inp_readline (inputwin.c:225)
==4021347==    by 0x431184: prof_run (profanity.c:121)
==4021347==    by 0x42C609: main (main.c:176)
==4021347==  Address 0xe850883 is 0 bytes after a block of size 3 alloc'd
==4021347==    at 0x48477C4: malloc (vg_replace_malloc.c:446)
[...]
```

`memchr()` requires the complete memory that shall be searched to be
accessible. Using `strchr()` could work for shorter strings, but we only
want to search in the first 4 chars.

Instead of somehow working around those limitations, simply search manually
in the first 4 bytes.

Fixes: 3c56b289 ("Add slashguard feature")
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>

(cherry picked from commit 7f48452d84)
2025-09-10 14:16:19 +02:00
Steffen Jaeckel
1a385b8cd2 Refactor slashguard
Fixes #2054
Fixes: 95c2199c ("Some more memory improvements")

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
(cherry picked from commit 40aafd06e7)
2025-09-10 14:05:30 +02:00
ea8a758ecf Merge branch 'fix/correct-autocompletion'
All checks were successful
CI / Check spelling (push) Successful in 18s
CI / Check coding style (push) Successful in 31s
CI / Linux (debian) (push) Successful in 10m43s
CI / Linux (arch) (push) Successful in 13m6s
CI / Linux (ubuntu) (push) Successful in 13m13s
2025-09-02 14:20:23 +02:00
2808def933 fix(chatwin): Fix LMC autocompletion to suggest corrected message content
All checks were successful
CI / Check spelling (pull_request) Successful in 18s
CI / Check coding style (pull_request) Successful in 33s
CI / Linux (debian) (pull_request) Successful in 9m45s
CI / Linux (ubuntu) (pull_request) Successful in 10m0s
CI / Linux (arch) (pull_request) Successful in 16m48s
- Modified chatwin_outgoing_msg to call _chatwin_set_last_message for corrected messages, using replace_id per XEP-0308.
- Updated _chatwin_set_last_message to skip redundant and invalid free/strdup for same pointers.
- Added null checks in _chatwin_set_last_message for safety.
- Fixes autocompletion suggesting original message content instead of corrected content.

Fixes #24
2025-09-02 00:29:13 +02:00
741dc4c275 fix(ui.h): cons_show_qrcode declaration. Minor change
All checks were successful
CI / Check spelling (pull_request) Successful in 17s
CI / Check coding style (pull_request) Successful in 30s
CI / Linux (debian) (pull_request) Successful in 10m43s
CI / Linux (arch) (pull_request) Successful in 13m6s
CI / Linux (ubuntu) (pull_request) Successful in 13m18s
CI / Check coding style (push) Successful in 36s
CI / Check spelling (push) Successful in 20s
CI / Linux (debian) (push) Successful in 9m44s
CI / Linux (ubuntu) (push) Successful in 10m3s
CI / Linux (arch) (push) Successful in 12m12s
Prior to the change declaration did not include parameters,
leading to errors within static analyzers and potential issues with compilation.
2025-09-01 23:29:26 +02:00
442bfb6ce1 feat: Add /force-encryption command and update message handling
All checks were successful
CI / Check spelling (pull_request) Successful in 18s
CI / Check coding style (pull_request) Successful in 34s
CI / Linux (ubuntu) (pull_request) Successful in 14m5s
CI / Linux (debian) (pull_request) Successful in 14m5s
CI / Linux (arch) (pull_request) Successful in 14m53s
Implement /force-encryption command to configure forced encryption
settings with on|off and policy resend-to-confirm|block options.

The changes enhance user experience by clarifying encryption requirements
and providing actionable commands. Users can now press Enter again to
confirm unencrypted messages in resend-to-confirm mode.
2025-08-25 21:11:27 +02:00
ad294cdd6d feat(editor): add asynchronous external editor support
Some checks failed
CI / Check spelling (pull_request) Successful in 18s
CI / Check coding style (pull_request) Successful in 31s
CI / Linux (fedora) (pull_request) Failing after 1m14s
CI / Linux (debian) (pull_request) Successful in 10m19s
CI / Linux (ubuntu) (pull_request) Successful in 10m42s
CI / Linux (arch) (pull_request) Successful in 13m2s
The synchronous `get_message_from_editor` blocked the main loop (`prof_run`) while launching an external editor like `vim`, halting network I/O in `session_process_events` and preventing incoming message reception.

Introduced `get_message_from_editor_async` for `cmd_editor` to run the editor asynchronously. It forks and execs the editor in a thread (`editor_thread`), suspending NCurses to free the terminal. The main loop skips `inp_readline` and `ui_update` via a new `background_mode` flag while the editor runs, allowing `session_process_events` to keep the connection alive.

On editor completion, `editor_process` (called per loop iteration) resumes NCurses with `ui_resize`, inserts the result into the readline buffer and clears `background_mode`.

Retained synchronous `get_message_from_editor` for ~20 existing code paths (e.g., `vcard_nickname`) to avoid breaking them.

Tested with `vim` and `nano`: confirms no rendering conflicts, messages received during editing, and seamless resume. Edge cases like editor crashes handled via error logging and seamless resume.
2025-08-07 03:03:43 +02:00
5ed8ec30f0 Update name and license
All checks were successful
CI / Linux (debian) (pull_request) Successful in 11m26s
CI / Linux (arch) (pull_request) Successful in 13m51s
CI / Linux (fedora) (pull_request) Successful in 12m27s
CI / Check coding style (pull_request) Successful in 30s
CI / Check spelling (pull_request) Successful in 14s
CI / Linux (ubuntu) (pull_request) Successful in 11m43s
CI / Linux (debian) (push) Successful in 11m31s
CI / Linux (arch) (push) Successful in 13m51s
CI / Linux (fedora) (push) Successful in 12m16s
CI / Check coding style (push) Successful in 29s
CI / Check spelling (push) Successful in 17s
CI / Linux (ubuntu) (push) Successful in 11m49s
2025-07-19 14:32:26 +02:00
Michael Vetter
091ff41c06 Merge pull request #2041 from profanity-im/some-improvements
All checks were successful
CI / Linux (debian) (pull_request) Successful in 13m45s
CI / Linux (arch) (pull_request) Successful in 16m48s
CI / Linux (fedora) (pull_request) Successful in 15m11s
CI / Check coding style (pull_request) Successful in 29s
CI / Check spelling (pull_request) Successful in 15s
CI / Linux (ubuntu) (pull_request) Successful in 13m50s
CI / Linux (debian) (push) Successful in 11m36s
CI / Linux (arch) (push) Successful in 14m0s
CI / Linux (fedora) (push) Successful in 12m25s
CI / Check coding style (push) Successful in 30s
CI / Check spelling (push) Successful in 16s
CI / Linux (ubuntu) (push) Successful in 11m55s
Summary:
- Print the final storage location when successfully decrypting a file with `aesgcm://` source.
- Less GString
- Re-factor cmd_presence()
- Improve const correctness
- Use correct free function. Fixes: 75d7663 ("Free wins summary list")

Pull Request Source: https://github.com/profanity-im/profanity/pull/2041

Author: Steffen Jaeckel <s@jaeckel.eu>
2025-07-19 00:13:49 +02:00
Steffen Jaeckel
b7afea7ec3 Use correct free function.
Fixes: 75d76638 ("Free wins summary list")

Author: Steffen Jaeckel <s@jaeckel.eu>
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-07-19 00:13:40 +02:00
f636090fd9 fix(window): preserve scroll offset on page_down and refactor
All checks were successful
CI / Check spelling (pull_request) Successful in 29s
CI / Check coding style (pull_request) Successful in 2m22s
CI / Linux (debian) (pull_request) Successful in 11m28s
CI / Linux (fedora) (pull_request) Successful in 16m46s
CI / Linux (arch) (pull_request) Successful in 20m29s
CI / Linux (ubuntu) (pull_request) Successful in 35m7s
CI / Check spelling (push) Successful in 17s
CI / Check coding style (push) Successful in 31s
CI / Linux (ubuntu) (push) Successful in 11m11s
CI / Linux (debian) (push) Successful in 13m26s
CI / Linux (fedora) (push) Successful in 16m10s
CI / Linux (arch) (push) Successful in 32m49s
When paging down beyond the visible chat buffer, the scroll position could
jump unexpectedly. This occurred because the visual distance from the bottom
(e.g. 6 lines until the last message) wasn’t preserved after loading new
messages from the DB.

This patch fixes that by capturing the visual offset (`current_offset`) before
the DB fetch and reapplying it after, based on the y-position of the final
buffer entry. This ensures consistent and smooth scroll transitions, even
as message heights vary.

In addition to fixing the visual glitch, this commit introduces a targeted
performance optimization: once the bottom of the chat has been reached
(`WIN_SCROLL_REACHED_BOTTOM`), we skip expensive operations entirely —
including datetime lookups and entry formatting — during further page_down
events. This reduces performance stalls
during rapid paging (e.g. holding the Page Down key at the bottom of the scrolling area).

This update also adapts to the recent change in `chatwin_db_history()`,
which now returns a `db_history_result_t` instead of `gboolean`, allowing
correct differentiation between an empty result and an actual DB error.

Together, these changes:
- Fix a scroll-jump bug in `page_down`
- Improve performance and responsiveness during rapid navigation
- Align with improved DB result handling
2025-07-02 19:27:15 +02:00
f824cde45f fix(mam, log): improve datetime handling and memory management in MAM and log fetching
- Introduce static helper `_truncate_datetime_suffix()` to safely trim datetime strings, removing unwanted suffixes like timezone offsets
- Replace manual string management with auto_gchar and g_strdup for safer, clearer ownership and to prevent leaks
- Add safety checks and logging warnings for unexpected datetime string lengths or null pointers
- Refactor _mam_rsm_id_handler to use the helper function and updated string handling
- Change log_database_get_previous_chat parameters for consistent ownership semantics, avoiding double frees and mem leaks
- Overall improve stability and prevent memory leaks during log database queries
2025-07-02 14:59:31 +02:00
40b7a12543 Clarify and improve win_page_up() scrolling offset adjustment for smoother paging
All checks were successful
CI / Check spelling (pull_request) Successful in 17s
CI / Check coding style (pull_request) Successful in 29s
CI / Linux (ubuntu) (pull_request) Successful in 11m6s
CI / Linux (debian) (pull_request) Successful in 13m9s
CI / Linux (fedora) (pull_request) Successful in 15m14s
CI / Linux (arch) (pull_request) Successful in 37m59s
CI / Check spelling (push) Successful in 16s
CI / Check coding style (push) Successful in 32s
CI / Linux (debian) (push) Successful in 9m53s
CI / Linux (ubuntu) (push) Successful in 10m9s
CI / Linux (fedora) (push) Successful in 15m8s
CI / Linux (arch) (push) Successful in 15m28s
This commit refines the existing logic in win_page_up() by:
- Improving comments to clearly explain the rationale behind adjusting
  the scroll offset relative to the first buffer entry’s visual position,
  helping future maintainers understand why this is necessary.
- Fixing offset recalculation to better handle cases where older messages
  with variable heights are loaded from the DB, improving scroll smoothness.
- Changing the logging of negative *page_start values from warning to debug,
  recognizing that this can be a normal scenario when insufficient history is loaded.
- Simplifying some conditionals and renaming variables for clearer intent.

No changes yet applied to win_page_down(), but similar improvements could
be considered in the future.

Overall, this enhances the robustness and user experience of scrolling up
in chat windows, while preserving existing functional logic.
2025-07-01 20:53:18 +02:00
6a394ae2e5 fix: Increase scrollback buffer height for chat rendering (PAD_SIZE)
f27fa98 commit introduced issue of scrolling seemingly randomly being stuck and the following message flood in the logs: "WRN: Ncurses Overflow..."

A pad is an off-screen buffer — larger than the visible terminal screen — that you can scroll, render parts of, or update selectively.

Unlike regular windows, a pad is not tied to screen size. You can create a pad that's 1,000 lines tall, even if your terminal is only 40 lines tall.

This commit addresses the issue by increasing PAD_SIZE to a reasonable number,
allowing messages from buffer to be displayed without overflowing NCurses' window size (maxy).

Minor change: add .cache folder to gitignore
2025-07-01 16:42:03 +02:00
Steffen Jaeckel
5efec675fd No need to always get a fresh list of keys or values.
> The returned data is valid until changes to the hash release those keys.
As of the doc of `g_hash_table_get_keys()` [0].

> The returned data is valid until hash_table is modified.
As of the doc of `g_hash_table_get_values()` [1].

Use this property and create the lists when modifying the hashtable.
The `keys` list is most of the time used sorted, so sort it immediately. In
the cases where it was not used sorted, it does not matter.

This started off by looking into whether this can be improved.
`g_hash_table_foreach()` is discouraged to be used and proposes to use
a `GHashTableIter`. Since our lists are not modified very often it does not
really make sense, so I decided to keep using lists, but allocating
those lists statically instead of per invocation.

Instead of using a list, we could maybe use the `GArray` version, but
I am not sure whether it wouldn't be even better to replace the
`GHashTable` all along to store the `windows` instead.

[0] https://docs.gtk.org/glib/type_func.HashTable.get_keys.html
[1] https://docs.gtk.org/glib/type_func.HashTable.get_values.html

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-04-11 18:55:17 +02:00
Steffen Jaeckel
a6f1250589 Fix memleak
`end_date` only gets free'd if `chatwin_db_history()` is called, which is
not always the case.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-04-02 13:07:47 +02:00
Michael Vetter
07dfeec816 Release 0.15.0 2025-03-27 20:06:38 +01:00
Steffen Jaeckel
25184a53e0 Improve const correctness.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-13 15:07:39 +01:00
Steffen Jaeckel
666895905b Revert API change of plugins_pre_chat_message_display()
In order to keep the C plugins API stable, we have to revert this part of
the changes done in 16ed7cc187.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-13 13:28:06 +01:00
Steffen Jaeckel
edb41bef60 Re-factor notifier.
* Add an internal `_notifier_uninit()` function.
* Instead of `#ifdef` inside `notify()`, provide different target-specific
static implementations.

This also introduces `log_error_once()`.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-12 10:15:39 +01:00
Steffen Jaeckel
95c2199ca2 Some more memory improvements
* Less leaks
* Less allocations

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-12 10:09:41 +01:00
Steffen Jaeckel
c0da36c48d Rage-cleanup.
While trying to get the unit tests working again I stumbled over all those
things that I thought could be better^TM.

Now we also know "TODO: why does this make the test fail?" - because
the unit tests are brittle AF ... and we have to init the subsystems
we use in the test, otherwise the cleanup will fail...

BTW. you can now also only run a single test ... or a pattern or so ...
you'd have to read how `cmocka_set_test_filter()` works exactly.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-10 11:45:15 +01:00
Steffen Jaeckel
72b99ceb6d Some minor improvements
* destroy/free/shutdown/close in reverse order of allocation
* more static/auto_Xfree
* less variables/strlen/GString
* properly `\0`-terminate string of testcase

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-10 11:45:15 +01:00
Steffen Jaeckel
c5a131ee46 Introduce our own shutdown callback mechanism.
Instead of adding stuff to `_shutdown()`, we can now register a shutdown
routine from the respective `init()` function of our modules.

This also has the advantage, that we're sure they're called in reverse
order from how the initialization happened.

I didn't simply use `atexit()` because POSIX says that the number of
possible callbacks is limited (min 32) and I was not sure whether
we will maybe extend this number at one point.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-07 21:09:16 +01:00
Steffen Jaeckel
f27fa98717 Some minor changes
* Fix some linter suggestions.
* Change some defines to `const` vars.
* Free buffer entries in the reverse order they were allocated.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-01-28 16:43:13 +01:00
Steffen Jaeckel
2696989ce5 Fix a bunch of obvious memory leaks at termination
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-01-28 16:43:13 +01:00
Steffen Jaeckel
46b788846c These defines don't have to be in the header file
They're only used in `window.c`.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-01-28 16:43:13 +01:00
Steffen Jaeckel
67d8d7110b Revert "Fix underscrolling problem"
This reverts commit d7e46d64fe.
2025-01-28 16:43:13 +01:00
Hanspeter Portner
cb395b7c09 Make muc_nick return a const char* const
In the documentation of the `muc_nick` function we can read:

> The nickname is owned by the chat room and should not be modified or freed

We should reflect that in the return type and `strdup` the value for the
plugin API.

Fixes: https://github.com/profanity-im/profanity/issues/2013
2025-01-26 18:16:14 +01:00
Michael Vetter
29fd8199f1 Merge pull request #1978 from profanity-im/feat/1974-actlist
Make statusbar actlist respect the /statusbar show setting
2024-06-20 12:47:34 +02:00
Michael Vetter
87935b744d Merge pull request #1979 from profanity-im/fix/leaks
Fix memleaks
2024-06-20 10:51:12 +02:00