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>
256 lines
7.3 KiB
C
256 lines
7.3 KiB
C
#include <glib.h>
|
|
#include "prof_cmocka.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <stabber.h>
|
|
|
|
#include "proftest.h"
|
|
|
|
void
|
|
autoping_set_interval(void** state)
|
|
{
|
|
prof_connect();
|
|
|
|
prof_input("/autoping set 60");
|
|
assert_true(prof_output_exact("Autoping interval set to 60 seconds."));
|
|
}
|
|
|
|
void
|
|
autoping_set_zero_disables(void** state)
|
|
{
|
|
prof_connect();
|
|
|
|
prof_input("/autoping set 0");
|
|
assert_true(prof_output_exact("Autoping disabled."));
|
|
}
|
|
|
|
void
|
|
autoping_timeout_set(void** state)
|
|
{
|
|
prof_connect();
|
|
|
|
prof_input("/autoping timeout 30");
|
|
assert_true(prof_output_exact("Autoping timeout set to 30 seconds."));
|
|
}
|
|
|
|
void
|
|
autoping_timeout_zero_disables(void** state)
|
|
{
|
|
prof_connect();
|
|
|
|
prof_input("/autoping timeout 0");
|
|
assert_true(prof_output_exact("Autoping timeout disabled."));
|
|
}
|
|
|
|
void
|
|
autoping_sends_ping_after_interval(void** state)
|
|
{
|
|
/*
|
|
* This test verifies that autoping sends a ping IQ after the configured
|
|
* interval. We set a short interval (1 second) and verify the ping is sent.
|
|
*/
|
|
|
|
// Register disco#info response with ping support
|
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
|
"<iq to='stabber@localhost/profanity' type='result' from='localhost'>"
|
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
|
"<identity category='server' type='im' name='Stabber'/>"
|
|
"<feature var='urn:xmpp:ping'/>"
|
|
"</query>"
|
|
"</iq>"
|
|
);
|
|
|
|
// Register ping response
|
|
stbbr_for_query("urn:xmpp:ping",
|
|
"<iq from='localhost' to='stabber@localhost/profanity' type='result'/>"
|
|
);
|
|
|
|
prof_connect();
|
|
|
|
// Set short autoping interval
|
|
prof_input("/autoping set 1");
|
|
assert_true(prof_output_exact("Autoping interval set to 1 seconds."));
|
|
|
|
// Wait for autoping to trigger (interval + some buffer)
|
|
sleep(2);
|
|
|
|
// Verify ping was sent (no 'to' attribute means server ping)
|
|
assert_true(stbbr_received(
|
|
"<iq id='*' type='get'>"
|
|
"<ping xmlns='urn:xmpp:ping'/>"
|
|
"</iq>"
|
|
));
|
|
}
|
|
|
|
void
|
|
autoping_server_not_supporting_ping(void** state)
|
|
{
|
|
/*
|
|
* When server doesn't support ping, autoping should show error.
|
|
*/
|
|
|
|
// Register disco#info response WITHOUT ping support
|
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
|
"<iq to='stabber@localhost/profanity' type='result' from='localhost'>"
|
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
|
"<identity category='server' type='im' name='Stabber'/>"
|
|
"</query>"
|
|
"</iq>"
|
|
);
|
|
|
|
prof_connect();
|
|
|
|
// Set short autoping interval
|
|
prof_input("/autoping set 1");
|
|
assert_true(prof_output_exact("Autoping interval set to 1 seconds."));
|
|
|
|
// Wait for autoping to trigger
|
|
sleep(2);
|
|
|
|
// Should show error about ping not being supported
|
|
assert_true(prof_output_regex("Server ping not supported"));
|
|
}
|
|
|
|
/*
|
|
* Autoping availability warning.
|
|
*
|
|
* The warning fires from the on-connect disco handler, so the three inputs
|
|
* (server ping support, autoping interval, warning preference) must all be
|
|
* set before prof_connect().
|
|
*/
|
|
|
|
/* Stable substring of the warning text emitted by iq.c. */
|
|
#define AUTOPING_WARNING_MATCH "This server supports XEP-0199"
|
|
|
|
static void
|
|
_stub_server_disco(gboolean with_ping)
|
|
{
|
|
if (with_ping) {
|
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
|
"<iq to='stabber@localhost/profanity' type='result' from='localhost'>"
|
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
|
"<identity category='server' type='im' name='Stabber'/>"
|
|
"<feature var='urn:xmpp:ping'/>"
|
|
"</query>"
|
|
"</iq>"
|
|
);
|
|
} else {
|
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
|
"<iq to='stabber@localhost/profanity' type='result' from='localhost'>"
|
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
|
"<identity category='server' type='im' name='Stabber'/>"
|
|
"</query>"
|
|
"</iq>"
|
|
);
|
|
}
|
|
}
|
|
|
|
void
|
|
autoping_warning_shown_when_disabled(void** state)
|
|
{
|
|
// All conditions met: server supports ping, autoping off, warning on (default).
|
|
_stub_server_disco(TRUE);
|
|
|
|
prof_input("/autoping set 0");
|
|
assert_true(prof_output_exact("Autoping disabled."));
|
|
|
|
prof_connect();
|
|
|
|
assert_true(prof_output_regex(AUTOPING_WARNING_MATCH));
|
|
}
|
|
|
|
void
|
|
autoping_warning_not_shown_when_server_unsupported(void** state)
|
|
{
|
|
// Server does not advertise urn:xmpp:ping -> no warning even with autoping off.
|
|
_stub_server_disco(FALSE);
|
|
|
|
prof_input("/autoping set 0");
|
|
assert_true(prof_output_exact("Autoping disabled."));
|
|
|
|
prof_connect();
|
|
|
|
prof_timeout(NEGATIVE_ASSERT_TIMEOUT);
|
|
assert_false(prof_output_regex(AUTOPING_WARNING_MATCH));
|
|
}
|
|
|
|
void
|
|
autoping_warning_not_shown_when_autoping_enabled(void** state)
|
|
{
|
|
// Warning is suppressed while autoping is enabled.
|
|
_stub_server_disco(TRUE);
|
|
|
|
prof_input("/autoping set 30");
|
|
assert_true(prof_output_exact("Autoping interval set to 30 seconds."));
|
|
|
|
prof_connect();
|
|
|
|
prof_timeout(NEGATIVE_ASSERT_TIMEOUT);
|
|
assert_false(prof_output_regex(AUTOPING_WARNING_MATCH));
|
|
}
|
|
|
|
void
|
|
autoping_warning_not_shown_when_user_disabled(void** state)
|
|
{
|
|
// User opted out -> no warning.
|
|
_stub_server_disco(TRUE);
|
|
|
|
prof_input("/autoping set 0");
|
|
assert_true(prof_output_exact("Autoping disabled."));
|
|
|
|
prof_input("/autoping warning off");
|
|
assert_true(prof_output_exact("Autoping availability warning disabled."));
|
|
|
|
prof_connect();
|
|
|
|
prof_timeout(NEGATIVE_ASSERT_TIMEOUT);
|
|
assert_false(prof_output_regex(AUTOPING_WARNING_MATCH));
|
|
}
|
|
|
|
void
|
|
autoping_warning_not_shown_for_user_jid(void** state)
|
|
{
|
|
// disco#info from a user JID (with '@') should not trigger the warning,
|
|
// only server responses (no '@') should.
|
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
|
"<iq to='stabber@localhost/profanity' type='result' from='buddy1@localhost'>"
|
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
|
"<identity category='person' type='chat' name='Buddy1'/>"
|
|
"<feature var='urn:xmpp:ping'/>"
|
|
"</query>"
|
|
"</iq>"
|
|
);
|
|
|
|
prof_input("/autoping set 0");
|
|
assert_true(prof_output_exact("Autoping disabled."));
|
|
|
|
prof_connect();
|
|
|
|
prof_timeout(NEGATIVE_ASSERT_TIMEOUT);
|
|
assert_false(prof_output_regex(AUTOPING_WARNING_MATCH));
|
|
}
|
|
|
|
void
|
|
autoping_warning_not_shown_for_subdomain_service(void** state)
|
|
{
|
|
// disco#info from a subdomain service should not trigger the warning, only the server's own domain should
|
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
|
"<iq to='stabber@localhost/profanity' type='result' from='conf.localhost'>"
|
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
|
"<identity category='conference' type='text' name='Conference Service'/>"
|
|
"<feature var='urn:xmpp:ping'/>"
|
|
"</query>"
|
|
"</iq>"
|
|
);
|
|
|
|
prof_input("/autoping set 0");
|
|
assert_true(prof_output_exact("Autoping disabled."));
|
|
|
|
prof_connect();
|
|
|
|
prof_timeout(NEGATIVE_ASSERT_TIMEOUT);
|
|
assert_false(prof_output_regex(AUTOPING_WARNING_MATCH));
|
|
}
|