diff --git a/meson.build b/meson.build index e10168b5d..ee10f68d0 100644 --- a/meson.build +++ b/meson.build @@ -682,6 +682,7 @@ if get_option('tests') 'tests/unittests/command/test_cmd_roster.c', 'tests/unittests/command/test_cmd_ac.c', 'tests/unittests/command/test_cmd_disconnect.c', + 'tests/unittests/command/test_cmd_mucping.c', 'tests/unittests/plugins/test_callbacks.c', 'tests/unittests/plugins/test_plugins_disco.c', 'tests/unittests/unittests.c', diff --git a/profanity.doap b/profanity.doap index fa93ec17d..bb188d403 100644 --- a/profanity.doap +++ b/profanity.doap @@ -463,7 +463,18 @@ - + + + + + complete + 1.1.0 + DEV + + + + + diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 44798f95b..f6ad8caa1 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -226,6 +226,7 @@ static Autocomplete script_show_ac; static Autocomplete console_ac; static Autocomplete console_msg_ac; static Autocomplete autoping_ac; +static Autocomplete mucping_ac; static Autocomplete plugins_ac; static Autocomplete plugins_load_ac; static Autocomplete plugins_unload_ac; @@ -386,6 +387,7 @@ static Autocomplete* all_acs[] = { &console_ac, &console_msg_ac, &autoping_ac, + &mucping_ac, &plugins_ac, &filepath_ac, &blocked_ac, @@ -1035,6 +1037,9 @@ cmd_ac_init(void) autocomplete_add(autoping_ac, "set"); autocomplete_add(autoping_ac, "timeout"); + autocomplete_add(mucping_ac, "set"); + autocomplete_add(mucping_ac, "timeout"); + autocomplete_add(plugins_ac, "install"); autocomplete_add(plugins_ac, "update"); autocomplete_add(plugins_ac, "uninstall"); @@ -1855,6 +1860,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ { "/disco", disco_ac }, { "/room", room_ac }, { "/autoping", autoping_ac }, + { "/mucping", mucping_ac }, { "/mainwin", winpos_ac }, { "/inputwin", winpos_ac }, }; diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 9e13450d8..4fe028fdd 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -1963,6 +1963,22 @@ static const struct cmd_t command_defs[] = { { "timeout ", "Seconds to wait for autoping responses, after which the connection is considered broken." }) }, + { CMD_PREAMBLE("/mucping", + parse_args, 2, 2, &cons_mucping_setting) + CMD_MAINFUNC(cmd_mucping) + CMD_TAGS( + CMD_TAG_CONNECTION) + CMD_SYN( + "/mucping set ", + "/mucping timeout ") + CMD_DESC( + "Set the interval and timeout for MUC self-pings (XEP-0410). Recommended interval is between 300 and 900 seconds, with a timeout of 10 to 60 seconds. " + "Note that the interval must be greater than the timeout.") + CMD_ARGS( + { "set ", "Number of seconds of idle room activity before sending a ping, a value of 0 disables MUC self-pings." }, + { "timeout ", "Seconds to wait for MUC self-ping responses, after which the room connection is considered disconnected. A value of 0 disables MUC self-pings entirely." }) + }, + { CMD_PREAMBLE("/ping", parse_args, 0, 1, NULL) CMD_MAINFUNC(cmd_ping) diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 2a9b47e2b..d7a31167a 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6297,7 +6297,7 @@ cmd_reconnect(ProfWin* window, const char* const command, gchar** args) } else if (strtoi_range(value, &intval, 0, INT_MAX, &err_msg)) { prefs_set_reconnect(intval); if (intval == 0) { - cons_show("Reconnect disabled.", intval); + cons_show("Reconnect disabled."); } else { cons_show("Reconnect interval set to %d seconds.", intval); } @@ -6355,6 +6355,70 @@ cmd_autoping(ProfWin* window, const char* const command, gchar** args) return TRUE; } +gboolean +cmd_mucping(ProfWin* window, const char* const command, gchar** args) +{ + char* cmd = args[0]; + char* value = args[1]; + + if (g_strcmp0(cmd, "set") == 0) { + int intval = 0; + auto_char char* err_msg = NULL; + gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg); + if (res) { + gint timeout = prefs_get_muc_ping_timeout(); + if (intval != 0 && timeout == 0) { + timeout = (intval > 60) ? 60 : (intval / 2); + if (timeout == 0) { + timeout = 1; + } + prefs_set_muc_ping_timeout(timeout); + } + if (intval != 0 && intval <= timeout) { + cons_show_error("MUC self-ping interval must be greater than timeout (%d seconds).", timeout); + } else { + prefs_set_muc_ping_interval(intval); + if (intval == 0) { + cons_show("MUC self-ping disabled."); + } else { + cons_show("MUC self-ping interval set to %d seconds.", intval); + } + } + } else { + cons_show(err_msg); + cons_bad_cmd_usage(command); + } + + } else if (g_strcmp0(cmd, "timeout") == 0) { + int intval = 0; + auto_char char* err_msg = NULL; + gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg); + if (res) { + if (intval == 0) { + prefs_set_muc_ping_interval(0); + prefs_set_muc_ping_timeout(0); + cons_show("MUC self-ping disabled."); + } else { + gint interval = prefs_get_muc_ping_interval(); + if (interval != 0 && intval >= interval) { + cons_show_error("MUC self-ping timeout must be less than interval (%d seconds).", interval); + } else { + prefs_set_muc_ping_timeout(intval); + cons_show("MUC self-ping timeout set to %d seconds.", intval); + } + } + } else { + cons_show(err_msg); + cons_bad_cmd_usage(command); + } + + } else { + cons_bad_cmd_usage(command); + } + + return TRUE; +} + gboolean cmd_ping(ProfWin* window, const char* const command, gchar** args) { diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 10455dc07..882387d6b 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -58,6 +58,7 @@ gboolean cmd_about(ProfWin* window, const char* const command, gchar** args); gboolean cmd_autoaway(ProfWin* window, const char* const command, gchar** args); gboolean cmd_autoconnect(ProfWin* window, const char* const command, gchar** args); gboolean cmd_autoping(ProfWin* window, const char* const command, gchar** args); +gboolean cmd_mucping(ProfWin* window, const char* const command, gchar** args); gboolean cmd_beep(ProfWin* window, const char* const command, gchar** args); gboolean cmd_caps(ProfWin* window, const char* const command, gchar** args); gboolean cmd_logging(ProfWin* window, const char* const command, gchar** args); diff --git a/src/config/preferences.c b/src/config/preferences.c index aa59fa592..f92d49524 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -836,6 +836,38 @@ prefs_set_autoping_timeout(gint value) g_key_file_set_integer(prefs, PREF_GROUP_CONNECTION, "autoping.timeout", value); } +gint +prefs_get_muc_ping_interval(void) +{ + if (!g_key_file_has_key(prefs, PREF_GROUP_CONNECTION, "muc.ping.interval", NULL)) { + return 600; + } else { + return g_key_file_get_integer(prefs, PREF_GROUP_CONNECTION, "muc.ping.interval", NULL); + } +} + +void +prefs_set_muc_ping_interval(gint value) +{ + g_key_file_set_integer(prefs, PREF_GROUP_CONNECTION, "muc.ping.interval", value); +} + +gint +prefs_get_muc_ping_timeout(void) +{ + if (!g_key_file_has_key(prefs, PREF_GROUP_CONNECTION, "muc.ping.timeout", NULL)) { + return 60; + } else { + return g_key_file_get_integer(prefs, PREF_GROUP_CONNECTION, "muc.ping.timeout", NULL); + } +} + +void +prefs_set_muc_ping_timeout(gint value) +{ + g_key_file_set_integer(prefs, PREF_GROUP_CONNECTION, "muc.ping.timeout", value); +} + gint prefs_get_autoaway_time(void) { diff --git a/src/config/preferences.h b/src/config/preferences.h index 1708e4428..76934bbf3 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -206,6 +206,10 @@ void prefs_set_autoping(gint value); gint prefs_get_autoping(void); void prefs_set_autoping_timeout(gint value); gint prefs_get_autoping_timeout(void); +void prefs_set_muc_ping_interval(gint value); +gint prefs_get_muc_ping_interval(void); +void prefs_set_muc_ping_timeout(gint value); +gint prefs_get_muc_ping_timeout(void); gint prefs_get_inpblock(void); void prefs_set_inpblock(gint value); diff --git a/src/ui/console.c b/src/ui/console.c index 57ca3fdad..5ad9019dc 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1817,6 +1817,8 @@ cons_show_chat_prefs(void) cons_history_setting(); cons_carbons_setting(); cons_receipts_setting(); + cons_mam_setting(); + cons_silence_setting(); cons_alert(NULL); } @@ -2033,6 +2035,28 @@ cons_autoping_setting(void) } } +void +cons_mucping_setting(void) +{ + gint muc_ping_interval = prefs_get_muc_ping_interval(); + if (muc_ping_interval == 0) { + cons_show("MUC self-ping interval (/mucping) : OFF"); + } else if (muc_ping_interval == 1) { + cons_show("MUC self-ping interval (/mucping) : 1 second"); + } else { + cons_show("MUC self-ping interval (/mucping) : %d seconds", muc_ping_interval); + } + + gint muc_ping_timeout = prefs_get_muc_ping_timeout(); + if (muc_ping_timeout == 0) { + cons_show("MUC self-ping timeout (/mucping) : OFF"); + } else if (muc_ping_timeout == 1) { + cons_show("MUC self-ping timeout (/mucping) : 1 second"); + } else { + cons_show("MUC self-ping timeout (/mucping) : %d seconds", muc_ping_timeout); + } +} + void cons_color_setting(void) { @@ -2146,6 +2170,7 @@ cons_show_connection_prefs(void) cons_show(""); cons_reconnect_setting(); cons_autoping_setting(); + cons_mucping_setting(); cons_autoconnect_setting(); cons_rooms_cache_setting(); cons_strophe_setting(); diff --git a/src/ui/ui.h b/src/ui/ui.h index 63d8ab0b7..bcd2c428c 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -311,6 +311,7 @@ void cons_logging_setting(void); void cons_autoaway_setting(void); void cons_reconnect_setting(void); void cons_autoping_setting(void); +void cons_mucping_setting(void); void cons_autoconnect_setting(void); void cons_room_cache_setting(void); void cons_inpblock_setting(void); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 90107eac6..dc13af3e7 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -135,6 +135,8 @@ static void _iq_id_handler_free(ProfIqHandler* handler); // scheduled static int _autoping_timed_send(xmpp_conn_t* const conn, void* const userdata); +static int _muc_self_ping_timer_check(xmpp_conn_t* const conn, void* const userdata); +static int _muc_self_pong_handler(xmpp_stanza_t* const stanza, void* const userdata); static void _identity_destroy(DiscoIdentity* identity); static void _item_destroy(DiscoItem* item); @@ -244,6 +246,9 @@ iq_handlers_init(void) int millis = prefs_get_autoping() * 1000; xmpp_timed_handler_add(conn, _autoping_timed_send, millis, ctx); } + if (prefs_get_muc_ping_interval() != 0) { + xmpp_timed_handler_add(conn, _muc_self_ping_timer_check, 10000, ctx); + } received_disco_items = FALSE; iq_handlers_clear(); @@ -1452,6 +1457,109 @@ autoping_timer_extend(void) g_timer_start(autoping_time); } +static int +_muc_self_pong_handler(xmpp_stanza_t* const stanza, void* const userdata) +{ + char* room = (char*)userdata; + log_debug("MUC self-ping: Pong received for room %s", room); + + // Reset ping sent time + muc_set_ping_sent_time(room, 0); + + const char* type = xmpp_stanza_get_type(stanza); + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + xmpp_stanza_t* error_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); + if (error_stanza) { + if (xmpp_stanza_get_child_by_name(error_stanza, "not-acceptable") || xmpp_stanza_get_child_by_name(error_stanza, "not-allowed") || xmpp_stanza_get_child_by_name(error_stanza, "item-not-found")) { + + log_warning("MUC selfping: Disconnected from room %s (stale connection detected)", room); + + ProfMucWin* mucwin = wins_get_muc(room); + if (mucwin) { + win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "Connection to room lost. Attempting to rejoin..."); + } + + char* password = muc_password(room); + const char* nick = muc_nick(room); + if (nick) { + presence_join_room(room, nick, password); + } + return 0; + } + } + } + + // Still connected. Reset idle timer + muc_update_activity(room); + + return 0; +} + +static int +_muc_self_ping_timer_check(xmpp_conn_t* const conn, void* const userdata) +{ + if (connection_get_status() != JABBER_CONNECTED) { + return 1; + } + + gint64 current_time = g_get_monotonic_time() / G_TIME_SPAN_SECOND; + gint interval = prefs_get_muc_ping_interval(); + gint timeout = prefs_get_muc_ping_timeout(); + + if (interval <= 0) { + return 1; + } + + GList* rooms_list = muc_rooms(); + GList* curr = rooms_list; + + while (curr) { + char* room = curr->data; + gint64 last_act = muc_last_activity(room); + gint64 sent_time = muc_ping_sent_time(room); + + if (sent_time > 0) { + // A ping is currently in flight for this room. Check for timeout. + if (current_time - sent_time > timeout) { + log_debug("MUC self-ping: Timeout for room %s", room); + muc_set_ping_sent_time(room, 0); + + ProfMucWin* mucwin = wins_get_muc(room); + if (mucwin) { + win_println((ProfWin*)mucwin, THEME_DEFAULT, "!", "MUC service not responding."); + } + } + } else { + // No ping is in flight. Check if room is idle. + if (current_time - last_act > interval) { + const char* nick = muc_nick(room); + if (nick) { + auto_gchar gchar* occupant_jid = create_fulljid(room, nick); + log_debug("MUC self-ping: Sending ping to %s", occupant_jid); + + xmpp_ctx_t* ctx = (xmpp_ctx_t*)userdata; + xmpp_stanza_t* iq = stanza_create_ping_iq(ctx, occupant_jid); + const char* id = xmpp_stanza_get_id(iq); + + // Add response handler + iq_id_handler_add(id, _muc_self_pong_handler, free, strdup(room)); + + iq_send_stanza(iq); + xmpp_stanza_release(iq); + + muc_set_ping_sent_time(room, current_time); + } + } + } + + curr = g_list_next(curr); + } + + g_list_free(rooms_list); + + return 1; +} + static int _auto_pong_id_handler(xmpp_stanza_t* const stanza, void* const userdata) { diff --git a/src/xmpp/message.c b/src/xmpp/message.c index 130cace03..232457905 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -997,6 +997,8 @@ _handle_groupchat(xmpp_stanza_t* const stanza) return; } + muc_update_activity(from_jid->barejid); + // handle room subject xmpp_stanza_t* subject = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SUBJECT); if (subject) { @@ -1245,6 +1247,8 @@ _handle_muc_private_message(xmpp_stanza_t* const stanza) goto out; } + muc_update_activity(message->from_jid->barejid); + // message stanza id const char* id = xmpp_stanza_get_id(stanza); if (id) { diff --git a/src/xmpp/muc.c b/src/xmpp/muc.c index 472c7ee31..c5fedf696 100644 --- a/src/xmpp/muc.c +++ b/src/xmpp/muc.c @@ -48,6 +48,8 @@ typedef struct _muc_room_t gboolean roster_received; muc_member_type_t member_type; muc_anonymity_type_t anonymity_type; + gint64 last_activity; + gint64 ping_sent_time; } ChatRoom; GHashTable* rooms = NULL; @@ -212,6 +214,8 @@ muc_join(const char* const room, const char* const nick, const char* const passw new_room->autojoin = autojoin; new_room->member_type = MUC_MEMBER_TYPE_UNKNOWN; new_room->anonymity_type = MUC_ANONYMITY_TYPE_UNKNOWN; + new_room->last_activity = g_get_monotonic_time() / G_TIME_SPAN_SECOND; + new_room->ping_sent_time = 0; g_hash_table_insert(rooms, strdup(room), new_room); } @@ -222,6 +226,58 @@ muc_leave(const char* const room) g_hash_table_remove(rooms, room); } +void +muc_update_activity(const char* const room) +{ + if (room == NULL) { + return; + } + ChatRoom* chat_room = g_hash_table_lookup(rooms, room); + if (chat_room) { + chat_room->last_activity = g_get_monotonic_time() / G_TIME_SPAN_SECOND; + } +} + +gint64 +muc_last_activity(const char* const room) +{ + if (room == NULL) { + return 0; + } + ChatRoom* chat_room = g_hash_table_lookup(rooms, room); + if (chat_room) { + return chat_room->last_activity; + } else { + return 0; + } +} + +void +muc_set_ping_sent_time(const char* const room, gint64 time) +{ + if (room == NULL) { + return; + } + ChatRoom* chat_room = g_hash_table_lookup(rooms, room); + if (chat_room) { + chat_room->ping_sent_time = time; + } +} + +gint64 +muc_ping_sent_time(const char* const room) +{ + if (room == NULL) { + return 0; + } + ChatRoom* chat_room = g_hash_table_lookup(rooms, room); + if (chat_room) { + return chat_room->ping_sent_time; + } else { + return 0; + } +} + gboolean muc_requires_config(const char* const room) { diff --git a/src/xmpp/muc.h b/src/xmpp/muc.h index 715fdd886..8885d06f6 100644 --- a/src/xmpp/muc.h +++ b/src/xmpp/muc.h @@ -60,6 +60,11 @@ void muc_init(void); void muc_join(const char* const room, const char* const nick, const char* const password, gboolean autojoin); void muc_leave(const char* const room); +void muc_update_activity(const char* const room); +gint64 muc_last_activity(const char* const room); +void muc_set_ping_sent_time(const char* const room, gint64 time); +gint64 muc_ping_sent_time(const char* const room); + gboolean muc_active(const char* const room); gboolean muc_autojoin(const char* const room); diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index f1aed9acb..c62d862ac 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -793,6 +793,7 @@ _muc_user_self_handler(xmpp_stanza_t* stanza) } if (muc_active(room)) { + muc_update_activity(room); sv_ev_muc_self_online(room, nick, config_required, role, affiliation, actor, reason, jid, show_str, status_str); } else { log_debug("presence: self-presence received for untracked room: %s", room); @@ -817,6 +818,8 @@ _muc_user_occupant_handler(xmpp_stanza_t* stanza) return; } + muc_update_activity(room); + const char* type = xmpp_stanza_get_type(stanza); if (g_strcmp0(type, STANZA_TYPE_UNAVAILABLE) == 0) { diff --git a/tests/unittests/command/test_cmd_mucping.c b/tests/unittests/command/test_cmd_mucping.c new file mode 100644 index 000000000..cae9a203d --- /dev/null +++ b/tests/unittests/command/test_cmd_mucping.c @@ -0,0 +1,98 @@ +#include "prof_cmocka.h" +#include +#include +#include + +#include "config/preferences.h" +#include "ui/ui.h" +#include "ui/stub_ui.h" +#include "command/cmd_funcs.h" + +#define CMD_MUCPING "/mucping" + +void +cmd_mucping__shows__usage_when_invalid_interval_chars(void** state) +{ + gchar* args[] = { "set", "abc", NULL }; + + expect_any_cons_show(); + expect_string(cons_bad_cmd_usage, cmd, CMD_MUCPING); + + gboolean result = cmd_mucping(NULL, CMD_MUCPING, args); + assert_true(result); +} + +void +cmd_mucping__shows__usage_when_invalid_interval_range(void** state) +{ + gchar* args[] = { "set", "-5", NULL }; + + expect_any_cons_show(); + expect_string(cons_bad_cmd_usage, cmd, CMD_MUCPING); + + gboolean result = cmd_mucping(NULL, CMD_MUCPING, args); + assert_true(result); +} + +void +cmd_mucping__shows__usage_when_invalid_timeout_chars(void** state) +{ + gchar* args[] = { "timeout", "xyz", NULL }; + + expect_any_cons_show(); + expect_string(cons_bad_cmd_usage, cmd, CMD_MUCPING); + + gboolean result = cmd_mucping(NULL, CMD_MUCPING, args); + assert_true(result); +} + +void +cmd_mucping__shows__usage_when_invalid_timeout_range(void** state) +{ + gchar* args[] = { "timeout", "-1", NULL }; + + expect_any_cons_show(); + expect_string(cons_bad_cmd_usage, cmd, CMD_MUCPING); + + gboolean result = cmd_mucping(NULL, CMD_MUCPING, args); + assert_true(result); +} + +void +cmd_mucping__shows__error_when_interval_smaller_than_timeout(void** state) +{ + // Default interval = 600, timeout = 60 + assert_int_equal(600, prefs_get_muc_ping_interval()); + assert_int_equal(60, prefs_get_muc_ping_timeout()); + + // Set timeout to 80 (valid) + gchar* args_timeout[] = { "timeout", "80", NULL }; + expect_cons_show("MUC self-ping timeout set to 80 seconds."); + gboolean result1 = cmd_mucping(NULL, CMD_MUCPING, args_timeout); + assert_true(result1); + assert_int_equal(80, prefs_get_muc_ping_timeout()); + + // Try setting interval to 50 (invalid: <= timeout of 80) + gchar* args_interval[] = { "set", "50", NULL }; + expect_cons_show_error("MUC self-ping interval must be greater than timeout (80 seconds)."); + gboolean result2 = cmd_mucping(NULL, CMD_MUCPING, args_interval); + assert_true(result2); + // Interval remains 600 + assert_int_equal(600, prefs_get_muc_ping_interval()); +} + +void +cmd_mucping__shows__error_when_timeout_greater_than_interval(void** state) +{ + // Reset interval and timeout + prefs_set_muc_ping_interval(100); + prefs_set_muc_ping_timeout(60); + + // Try setting timeout to 120 (invalid: >= interval of 100) + gchar* args_timeout[] = { "timeout", "120", NULL }; + expect_cons_show_error("MUC self-ping timeout must be less than interval (100 seconds)."); + gboolean result1 = cmd_mucping(NULL, CMD_MUCPING, args_timeout); + assert_true(result1); + // Timeout remains 60 + assert_int_equal(60, prefs_get_muc_ping_timeout()); +} diff --git a/tests/unittests/command/test_cmd_mucping.h b/tests/unittests/command/test_cmd_mucping.h new file mode 100644 index 000000000..be6f29bb6 --- /dev/null +++ b/tests/unittests/command/test_cmd_mucping.h @@ -0,0 +1,11 @@ +#ifndef TESTS_TEST_CMD_MUCPING_H +#define TESTS_TEST_CMD_MUCPING_H + +void cmd_mucping__shows__usage_when_invalid_interval_chars(void** state); +void cmd_mucping__shows__usage_when_invalid_interval_range(void** state); +void cmd_mucping__shows__usage_when_invalid_timeout_chars(void** state); +void cmd_mucping__shows__usage_when_invalid_timeout_range(void** state); +void cmd_mucping__shows__error_when_interval_smaller_than_timeout(void** state); +void cmd_mucping__shows__error_when_timeout_greater_than_interval(void** state); + +#endif diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index 7c90c480f..84de8aa72 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -1116,6 +1116,10 @@ cons_autoping_setting(void) { } void +cons_mucping_setting(void) +{ +} +void cons_autoconnect_setting(void) { } diff --git a/tests/unittests/unittests.c b/tests/unittests/unittests.c index 17e3774e3..31a03cb95 100644 --- a/tests/unittests/unittests.c +++ b/tests/unittests/unittests.c @@ -27,6 +27,7 @@ #include "command/test_cmd_rooms.h" #include "command/test_cmd_sub.h" #include "command/test_cmd_presence.h" +#include "command/test_cmd_mucping.h" #include "command/test_cmd_otr.h" #include "command/test_cmd_pgp.h" #include "xmpp/test_jid.h" @@ -459,6 +460,17 @@ main(int argc, char* argv[]) cmocka_unit_test(p_contact_is_available__is__true_when_highest_priority_online), cmocka_unit_test(p_contact_is_available__is__true_when_highest_priority_chat), + cmocka_unit_test(cmd_mucping__shows__usage_when_invalid_interval_chars), + cmocka_unit_test(cmd_mucping__shows__usage_when_invalid_interval_range), + cmocka_unit_test(cmd_mucping__shows__usage_when_invalid_timeout_chars), + cmocka_unit_test(cmd_mucping__shows__usage_when_invalid_timeout_range), + cmocka_unit_test_setup_teardown(cmd_mucping__shows__error_when_interval_smaller_than_timeout, + load_preferences, + close_preferences), + cmocka_unit_test_setup_teardown(cmd_mucping__shows__error_when_timeout_greater_than_interval, + load_preferences, + close_preferences), + cmocka_unit_test(cmd_presence__shows__usage_when_bad_subcmd), cmocka_unit_test(cmd_presence__shows__usage_when_bad_console_setting), cmocka_unit_test(cmd_presence__shows__usage_when_bad_chat_setting),