Compare commits

..

8 Commits

Author SHA1 Message Date
14fb6e3b41 fix(disco): clean up autoping warning message handling
Remove unused return value from _disco_autoping_warning_message by
changing its return type to void. Rename local variable from
users_prefers_warning to user_prefers_warning for correct grammar.

Use g_ascii_strcasecmp instead of g_strcmp0 for the domain match
check, so the warning fires correctly regardless of case differences
between the stanza 'from' field and the bound domain.

Remove duplicate autoping warning display from cons_notify_setting(),
keeping it only in cons_autoping_setting() where it belongs.
2026-06-23 10:57:59 +00:00
19bfad76ba test(autoping): add test for autoping warning exclusion on subdomain services
All checks were successful
CI Code / Check spelling (pull_request) Successful in 15s
CI Code / Check coding style (pull_request) Successful in 30s
CI Code / Code Coverage (pull_request) Successful in 3m47s
CI Code / Linux (debian) (pull_request) Successful in 5m11s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m16s
CI Code / Linux (arch) (pull_request) Successful in 7m9s
The new test verifies that disco#info responses from subdomain services
(e.g., conference servers) do not trigger the autoping warning, ensuring
the check is correctly restricted to the server's own domain.
2026-06-22 09:17:49 +00:00
b5bbad8d2c fix(xmpp): prevent autoping warning repetition on disco items
All checks were successful
CI Code / Check spelling (pull_request) Successful in 17s
CI Code / Check coding style (pull_request) Successful in 31s
CI Code / Code Coverage (pull_request) Successful in 4m0s
CI Code / Linux (debian) (pull_request) Successful in 5m5s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m12s
CI Code / Linux (arch) (pull_request) Successful in 6m55s
The previous logic triggered warnings for disco items. This change restricts the check to only the connection domain, ensuring that auto-discovered items do not trigger duplicate warnings.
2026-06-21 15:37:16 +00:00
7fd0cded3d test(autoping): add test for autoping warning exclusion on user JIDs
All checks were successful
CI Code / Check spelling (pull_request) Successful in 18s
CI Code / Check coding style (pull_request) Successful in 31s
CI Code / Code Coverage (pull_request) Successful in 3m33s
CI Code / Linux (debian) (pull_request) Successful in 5m7s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m12s
CI Code / Linux (arch) (pull_request) Successful in 7m9s
2026-06-20 20:47:05 +00:00
2012e15c0b fix(disco): avoid autoping warning on disco#info responses from users
The autoping availability warning should only trigger for disco#info
responses from the XMPP server (no 'from' attribute), otherwise the
warning message is displayed excessive amount of times.

Refs #80
2026-06-20 19:32:40 +00:00
45b81cf2de test(autoping): cover availability-warning conditions
All checks were successful
CI Code / Check spelling (pull_request) Successful in 15s
CI Code / Check coding style (pull_request) Successful in 30s
CI Code / Code Coverage (pull_request) Successful in 3m57s
CI Code / Linux (debian) (pull_request) Successful in 4m58s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m8s
CI Code / Linux (arch) (pull_request) Successful in 6m58s
Functional tests for the on-connect warning: shown when the server advertises
urn:xmpp:ping while autoping is disabled and the warning preference is on;
suppressed when ping is unsupported, when autoping is enabled, or when the user
turned the warning off.

Refs #80
2026-06-20 14:39:32 +03:00
15a1a343d2 fix(autoping): align warning command with on|off
The warning toggle uses _cmd_set_boolean_preference (accepts on|off) and the
subcommand is "warning", but the help syntax, console status lines and warning
text advertised "warning enable|disable" and "/autoping warn", none of which
work.

- cmd_defs: document "/autoping warning on|off"
- console: show "(/autoping warning)" in the status lines
- iq: point the warning text at "/autoping warning off"
- cmd_ac: register "warning" and complete on|off via a dedicated
  _autoping_autocomplete (moved off the generic single-level table)
2026-06-20 14:39:32 +03:00
0f7741fdfa feat: Autoping availability warning 2026-06-20 14:39:32 +03:00
6 changed files with 23 additions and 45 deletions

6
src/gitversion.h.in Normal file
View File

@@ -0,0 +1,6 @@
#ifndef PROF_GIT_BRANCH
#define PROF_GIT_BRANCH @PROF_GIT_BRANCH@
#endif
#ifndef PROF_GIT_REVISION
#define PROF_GIT_REVISION @PROF_GIT_REVISION@
#endif

View File

@@ -519,15 +519,13 @@ p_gpg_sign(const gchar* const str, const gchar* const fp)
} }
gchar* gchar*
p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp, gchar** err) p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp)
{ {
ProfPGPPubKeyId* pubkeyid = g_hash_table_lookup(pubkeys, barejid); ProfPGPPubKeyId* pubkeyid = g_hash_table_lookup(pubkeys, barejid);
if (!pubkeyid) { if (!pubkeyid) {
*err = g_strdup("No PGP key found for recipient");
return NULL; return NULL;
} }
if (!pubkeyid->id) { if (!pubkeyid->id) {
*err = g_strdup("No key ID found for recipient");
return NULL; return NULL;
} }
@@ -540,7 +538,6 @@ p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gcha
gpgme_ctx_t ctx; gpgme_ctx_t ctx;
gpgme_error_t error = gpgme_new(&ctx); gpgme_error_t error = gpgme_new(&ctx);
if (error) { if (error) {
*err = g_strdup_printf("Failed to create GPGME context: %s %s", gpgme_strsource(error), gpgme_strerror(error));
log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
return NULL; return NULL;
} }
@@ -548,7 +545,6 @@ p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gcha
gpgme_key_t receiver_key; gpgme_key_t receiver_key;
error = gpgme_get_key(ctx, pubkeyid->id, &receiver_key, 0); error = gpgme_get_key(ctx, pubkeyid->id, &receiver_key, 0);
if (error || receiver_key == NULL) { if (error || receiver_key == NULL) {
*err = g_strdup_printf("Failed to get receiver key '%s': %s %s", pubkeyid->id, gpgme_strsource(error), gpgme_strerror(error));
log_error("GPG: Failed to get receiver_key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); log_error("GPG: Failed to get receiver_key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
gpgme_release(ctx); gpgme_release(ctx);
return NULL; return NULL;
@@ -558,10 +554,8 @@ p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gcha
gpgme_key_t sender_key = NULL; gpgme_key_t sender_key = NULL;
error = gpgme_get_key(ctx, fp, &sender_key, 0); error = gpgme_get_key(ctx, fp, &sender_key, 0);
if (error || sender_key == NULL) { if (error || sender_key == NULL) {
*err = g_strdup_printf("Failed to get sender key '%s': %s %s", fp, gpgme_strsource(error), gpgme_strerror(error));
log_error("GPG: Failed to get sender_key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); log_error("GPG: Failed to get sender_key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
gpgme_release(ctx); gpgme_release(ctx);
gpgme_key_unref(receiver_key);
return NULL; return NULL;
} }
keys[1] = sender_key; keys[1] = sender_key;
@@ -580,8 +574,7 @@ p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gcha
gpgme_key_unref(sender_key); gpgme_key_unref(sender_key);
if (error) { if (error) {
*err = g_strdup_printf("Encryption failed: (%s) %s", gpgme_strsource(error), gpgme_strerror(error)); log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error));
log_error("GPG: Failed to encrypt message. (%s) %s", gpgme_strsource(error), gpgme_strerror(error));
return NULL; return NULL;
} }

View File

@@ -42,7 +42,7 @@ gboolean p_gpg_available(const gchar* const barejid);
const gchar* p_gpg_libver(void); const gchar* p_gpg_libver(void);
gchar* p_gpg_sign(const gchar* const str, const gchar* const fp); gchar* p_gpg_sign(const gchar* const str, const gchar* const fp);
void p_gpg_verify(const gchar* const barejid, const gchar* const sign); void p_gpg_verify(const gchar* const barejid, const gchar* const sign);
gchar* p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp, gchar** err); gchar* p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp);
gchar* p_gpg_decrypt(const gchar* const cipher); gchar* p_gpg_decrypt(const gchar* const cipher);
void p_gpg_free_decrypted(gchar* decrypted); void p_gpg_free_decrypted(gchar* decrypted);
gchar* p_gpg_autocomplete_key(const gchar* const search_str, gboolean previous, void* context); gchar* p_gpg_autocomplete_key(const gchar* const search_str, gboolean previous, void* context);

View File

@@ -43,7 +43,7 @@
#include "ai/ai_client.h" #include "ai/ai_client.h"
static const int PAD_MIN_HEIGHT = 100; static const int PAD_MIN_HEIGHT = 100;
static const int PAD_DEAD_SPACE_LIMIT = 2000; // reclaim once the pad holds this much dead space (cursor past live buffer); size-independent, so it never fires while scrolling static const int PAD_THRESHOLD = 12000; // above buffer cap (~9000): reclaims dead pad space, never fires while scrolling
static gboolean _in_redraw = FALSE; static gboolean _in_redraw = FALSE;
static void static void
@@ -56,10 +56,9 @@ _win_ensure_pad_capacity(ProfWin* window, WINDOW* win, int lines_needed)
int cur_height = getmaxy(win); int cur_height = getmaxy(win);
int cur_width = getmaxx(win); int cur_width = getmaxx(win);
if (lines_needed >= cur_height - 1) { if (lines_needed >= cur_height - 1) {
// redraw to reclaim dead pad space (cursor far past live buffer, e.g. a long // If we are getting too large, trigger a redraw to clean up old lines
// append-only session); dead space never accrues while scrolling, only here // but only if we are not already in a redraw process.
int dead = window ? getcury(win) - window->layout->buffer->lines : 0; if (window && cur_height >= PAD_THRESHOLD && !_in_redraw) {
if (window && dead > PAD_DEAD_SPACE_LIMIT && !_in_redraw) {
win_redraw(window); win_redraw(window);
} else { } else {
// resize to required lines + some buffer for next messages // resize to required lines + some buffer for next messages

View File

@@ -2432,8 +2432,7 @@ _disco_info_response_id_handler_onconnect(xmpp_stanza_t* const stanza, void* con
} }
// Prevent repetitions by avoiding checks of disco items (from connection_set_disco_items) // Prevent repetitions by avoiding checks of disco items (from connection_set_disco_items)
const char* domain = connection_get_domain(); if (from && g_ascii_strcasecmp(from, connection_get_domain()) == 0) {
if (from && domain && g_ascii_strcasecmp(from, domain) == 0) {
_disco_autoping_warning_message(features); _disco_autoping_warning_message(features);
} }
} }

View File

@@ -467,15 +467,12 @@ message_send_chat_pgp(const char* const barejid, const char* const msg, gboolean
auto_char char* jid = chat_session_get_jid(barejid); auto_char char* jid = chat_session_get_jid(barejid);
char* id = connection_create_stanza_id(); char* id = connection_create_stanza_id();
ProfWin* current = wins_get_current();
xmpp_stanza_t* message = NULL; xmpp_stanza_t* message = NULL;
#ifdef HAVE_LIBGPGME #ifdef HAVE_LIBGPGME
ProfAccount* account = accounts_get_account(session_get_account_name()); ProfAccount* account = accounts_get_account(session_get_account_name());
if (account->pgp_keyid) { if (account->pgp_keyid) {
auto_jid Jid* jidp = jid_create(jid); auto_jid Jid* jidp = jid_create(jid);
auto_gchar gchar* err = NULL; auto_gchar gchar* encrypted = p_gpg_encrypt(jidp->barejid, msg, account->pgp_keyid);
auto_gchar gchar* encrypted = p_gpg_encrypt(jidp->barejid, msg, account->pgp_keyid, &err);
if (encrypted) { if (encrypted) {
message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
xmpp_message_set_body(message, "This message is encrypted (XEP-0027)."); xmpp_message_set_body(message, "This message is encrypted (XEP-0027).");
@@ -489,31 +486,18 @@ message_send_chat_pgp(const char* const barejid, const char* const msg, gboolean
xmpp_stanza_add_child(message, x); xmpp_stanza_add_child(message, x);
xmpp_stanza_release(x); xmpp_stanza_release(x);
} else { } else {
if (current) { message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
win_println(current, THEME_ERROR, "-", "Unable to encrypt message for %s: %s.", jid, err); xmpp_message_set_body(message, msg);
}
log_error("Message not encrypted for %s: %s.", jid, err);
account_free(account);
free(id);
return NULL;
} }
} else { } else {
if (current) { message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
win_println(current, THEME_ERROR, "-", "No PGP key configured for this account."); xmpp_message_set_body(message, msg);
}
log_error("No PGP key configured, message not sent.");
account_free(account);
free(id);
return NULL;
} }
account_free(account); account_free(account);
#else #else
if (current) { // ?
win_println(current, THEME_ERROR, "-", "LibGPGME not available, message not sent."); message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
} xmpp_message_set_body(message, msg);
log_error("LibGPGME not available, message not sent.");
free(id);
return NULL;
#endif #endif
if (state) { if (state) {
@@ -562,10 +546,7 @@ message_send_chat_ox(const char* const barejid, const char* const msg, gboolean
xmpp_stanza_to_text(signcrypt, &c, &s); xmpp_stanza_to_text(signcrypt, &c, &s);
char* signcrypt_e = p_ox_gpg_signcrypt(account->jid, barejid, c); char* signcrypt_e = p_ox_gpg_signcrypt(account->jid, barejid, c);
if (signcrypt_e == NULL) { if (signcrypt_e == NULL) {
ProfWin* current = wins_get_current(); cons_show("Unable to send OX message. Check log file and profanity-ox-setup man page for details.");
if (current) {
win_println(current, THEME_ERROR, "-", "Unable to send OX message. Check log file and profanity-ox-setup man page for details.");
}
log_error("Message not signcrypted."); log_error("Message not signcrypted.");
return NULL; return NULL;
} }