diff --git a/src/command/commands.c b/src/command/commands.c index 0627b383..d0409890 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -2260,7 +2260,7 @@ cmd_autoping(gchar **args, struct cmd_help_t help) if (_strtoi(value, &intval, 0, INT_MAX) == 0) { prefs_set_autoping(intval); - jabber_set_autoping(intval); + iq_set_autoping(intval); if (intval == 0) { cons_show("Autoping disabled.", intval); } else { diff --git a/src/server_events.c b/src/server_events.c index 8b2d6b78..929f4707 100644 --- a/src/server_events.c +++ b/src/server_events.c @@ -508,3 +508,11 @@ handle_roster_add(const char * const barejid, const char * const name) ui_roster_add(barejid, name); ui_current_page_off(); } + +void +handle_autoping_cancel(void) +{ + prefs_set_autoping(0); + cons_show_error("Server ping not supported, autoping disabled."); + ui_current_page_off(); +} diff --git a/src/server_events.h b/src/server_events.h index 64bd04a7..7704cd44 100644 --- a/src/server_events.h +++ b/src/server_events.h @@ -74,5 +74,6 @@ void handle_group_remove(const char * const contact, const char * const group); void handle_roster_remove(const char * const barejid); void handle_roster_add(const char * const barejid, const char * const name); +void handle_autoping_cancel(void); #endif diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c index e5e691df..b7ffe410 100644 --- a/src/xmpp/connection.c +++ b/src/xmpp/connection.c @@ -88,7 +88,6 @@ static void _jabber_reconnect(void); static void _connection_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error, void * const userdata); -static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata); void _connection_free_saved_account(void); void _connection_free_saved_details(void); @@ -228,20 +227,6 @@ _jabber_process_events(void) } -static void -_jabber_set_autoping(const int seconds) -{ - if (jabber_conn.conn_status == JABBER_CONNECTED) { - xmpp_timed_handler_delete(jabber_conn.conn, _ping_timed_handler); - - if (seconds != 0) { - int millis = seconds * 1000; - xmpp_timed_handler_add(jabber_conn.conn, _ping_timed_handler, millis, - jabber_conn.ctx); - } - } -} - static GList * _jabber_get_available_resources(void) { @@ -463,8 +448,6 @@ _connection_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int error, xmpp_stream_error_t * const stream_error, void * const userdata) { - xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; - // login success if (status == XMPP_CONN_CONNECT) { log_debug("Connection handler: XMPP_CONN_CONNECT"); @@ -498,11 +481,6 @@ _connection_handler(xmpp_conn_t * const conn, presence_add_handlers(); iq_add_handlers(); - if (prefs_get_autoping() != 0) { - int millis = prefs_get_autoping() * 1000; - xmpp_timed_handler_add(conn, _ping_timed_handler, millis, ctx); - } - roster_request(); bookmark_request(); jabber_conn.conn_status = JABBER_CONNECTED; @@ -563,20 +541,6 @@ _connection_handler(xmpp_conn_t * const conn, } } -static int -_ping_timed_handler(xmpp_conn_t * const conn, void * const userdata) -{ - if (jabber_conn.conn_status == JABBER_CONNECTED) { - xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; - - xmpp_stanza_t *iq = stanza_create_ping_iq(ctx); - xmpp_send(conn, iq); - xmpp_stanza_release(iq); - } - - return 1; -} - static log_level_t _get_log_level(const xmpp_log_level_t xmpp_level) { @@ -636,7 +600,6 @@ jabber_init_module(void) jabber_disconnect = _jabber_disconnect; jabber_shutdown = _jabber_shutdown; jabber_process_events = _jabber_process_events; - jabber_set_autoping = _jabber_set_autoping; jabber_get_available_resources = _jabber_get_available_resources; jabber_get_connection_status = _jabber_get_connection_status; jabber_get_fulljid = _jabber_get_fulljid; diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 48ec09eb..1c0e80fd 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -35,6 +35,7 @@ #include "log.h" #include "muc.h" #include "profanity.h" +#include "config/preferences.h" #include "server_events.h" #include "xmpp/capabilities.h" #include "xmpp/connection.h" @@ -60,6 +61,8 @@ static int _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_items_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _ping_timed_handler(xmpp_conn_t * const conn, + void * const userdata); void iq_add_handlers(void) @@ -79,6 +82,28 @@ iq_add_handlers(void) HANDLE(STANZA_NS_VERSION, STANZA_TYPE_RESULT, _version_result_handler); HANDLE(STANZA_NS_PING, STANZA_TYPE_GET, _ping_get_handler); + + if (prefs_get_autoping() != 0) { + int millis = prefs_get_autoping() * 1000; + xmpp_timed_handler_add(conn, _ping_timed_handler, millis, ctx); + } +} + +static void +_iq_set_autoping(const int seconds) +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + + if (jabber_get_connection_status() == JABBER_CONNECTED) { + xmpp_timed_handler_delete(conn, _ping_timed_handler); + + if (seconds != 0) { + int millis = seconds * 1000; + xmpp_timed_handler_add(conn, _ping_timed_handler, millis, + ctx); + } + } } static void @@ -136,6 +161,57 @@ _error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, return 1; } +static int +_pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + char *id = xmpp_stanza_get_id(stanza); + char *type = xmpp_stanza_get_type(stanza); + + if (id != NULL && type != NULL) { + // show warning if error + if (strcmp(type, STANZA_TYPE_ERROR) == 0) { + log_warning("Server ping (id=%s) responded with error", id); + + // turn off autoping if error type is 'cancel' + xmpp_stanza_t *error = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); + if (error != NULL) { + char *errtype = xmpp_stanza_get_type(error); + if (errtype != NULL) { + if (strcmp(errtype, "cancel") == 0) { + log_warning("Server ping (id=%s) error type 'cancel', disabling autoping.", id); + handle_autoping_cancel(); + xmpp_timed_handler_delete(conn, _ping_timed_handler); + } + } + } + } + } + + // remove this handler + return 0; +} + +static int +_ping_timed_handler(xmpp_conn_t * const conn, void * const userdata) +{ + xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; + + if (jabber_get_connection_status() == JABBER_CONNECTED) { + + xmpp_stanza_t *iq = stanza_create_ping_iq(ctx); + char *id = xmpp_stanza_get_id(iq); + + // add pong handler + xmpp_id_handler_add(conn, _pong_handler, id, ctx); + + xmpp_send(conn, iq); + xmpp_stanza_release(iq); + } + + return 1; +} + static int _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) @@ -581,4 +657,5 @@ iq_init_module(void) iq_disco_info_request = _iq_disco_info_request; iq_disco_items_request = _iq_disco_items_request; iq_send_software_version = _iq_send_software_version; + iq_set_autoping = _iq_set_autoping; } diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 97cebc73..635d12db 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -394,7 +394,8 @@ stanza_create_ping_iq(xmpp_ctx_t *ctx) xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); - xmpp_stanza_set_id(iq, "c2s1"); + char *id = generate_unique_id("ping"); + xmpp_stanza_set_id(iq, id); xmpp_stanza_t *ping = xmpp_stanza_new(ctx); xmpp_stanza_set_name(ping, STANZA_NAME_PING); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 5a331b04..dd91e398 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -94,7 +94,6 @@ const char * (*jabber_get_fulljid)(void); const char * (*jabber_get_domain)(void); jabber_conn_status_t (*jabber_get_connection_status)(void); char * (*jabber_get_presence_message)(void); -void (*jabber_set_autoping)(int seconds); char* (*jabber_get_account_name)(void); GList * (*jabber_get_available_resources)(void); @@ -127,6 +126,7 @@ void (*iq_send_software_version)(const char * const fulljid); void (*iq_room_list_request)(gchar *conferencejid); void (*iq_disco_info_request)(gchar *jid); void (*iq_disco_items_request)(gchar *jid); +void (*iq_set_autoping)(int seconds); // caps functions Capabilities* (*caps_get)(const char * const caps_str);