From c5a131ee466188e4b8e958752bdfeff3f0d598ad Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Fri, 7 Mar 2025 11:44:31 +0100 Subject: [PATCH] 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 --- src/chatlog.c | 30 ++++--- src/chatlog.h | 4 +- src/command/cmd_defs.c | 18 ++-- src/command/cmd_defs.h | 1 - src/common.h | 1 + src/config/accounts.c | 21 +++-- src/config/accounts.h | 1 - src/config/theme.c | 46 ++++++----- src/config/tlscerts.c | 27 +++--- src/config/tlscerts.h | 2 - src/log.c | 32 +++---- src/log.h | 1 - src/omemo/omemo.c | 23 +++--- src/omemo/omemo.h | 1 - src/otr/otr.c | 22 ++--- src/otr/otr.h | 1 - src/pgp/gpg.c | 42 +++++----- src/pgp/gpg.h | 1 - src/plugins/plugins.c | 110 +++++++++++++------------ src/plugins/plugins.h | 2 - src/profanity.c | 71 ++++++++++------ src/ui/core.c | 31 +++---- src/ui/tray.c | 23 +++--- src/ui/tray.h | 1 - src/ui/ui.h | 1 - src/xmpp/capabilities.c | 29 ++++--- src/xmpp/muc.c | 23 +++--- src/xmpp/muc.h | 1 - src/xmpp/session.c | 29 +++---- src/xmpp/xmpp.h | 2 - tests/unittests/chatlog/stub_chatlog.c | 7 +- tests/unittests/config/stub_accounts.c | 4 - tests/unittests/log/stub_log.c | 4 - tests/unittests/omemo/stub_omemo.c | 4 - tests/unittests/otr/stub_otr.c | 4 - tests/unittests/pgp/stub_gpg.c | 4 - tests/unittests/test_server_events.c | 11 ++- tests/unittests/ui/stub_ui.c | 4 - tests/unittests/xmpp/stub_xmpp.c | 9 -- 39 files changed, 321 insertions(+), 327 deletions(-) diff --git a/src/chatlog.c b/src/chatlog.c index 313ad71a..8e18a6a7 100644 --- a/src/chatlog.c +++ b/src/chatlog.c @@ -73,12 +73,25 @@ static void _chat_log_chat(const char* const login, const char* const other, con chat_log_direction_t direction, GDateTime* timestamp, const char* const resourcepart); static void _groupchat_log_chat(const gchar* const login, const gchar* const room, const gchar* const nick, const gchar* const msg); + void -chat_log_init(void) +_chatlog_close(void) +{ + g_hash_table_destroy(logs); + g_hash_table_destroy(groupchat_logs); +} + +void +chatlog_init(void) { log_info("Initialising chat logs"); + + prof_add_shutdown_routine(_chatlog_close); + logs = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, free, (GDestroyNotify)_free_chat_log); + groupchat_logs = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, free, + (GDestroyNotify)_free_chat_log); } void @@ -295,14 +308,6 @@ _chat_log_chat(const char* const login, const char* const other, const char* msg g_date_time_unref(timestamp); } -void -groupchat_log_init(void) -{ - log_info("Initialising groupchat logs"); - groupchat_logs = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, free, - (GDestroyNotify)_free_chat_log); -} - void groupchat_log_msg_out(const gchar* const room, const gchar* const msg) { @@ -391,13 +396,6 @@ _groupchat_log_chat(const gchar* const login, const gchar* const room, const gch g_date_time_unref(dt_tmp); } -void -chat_log_close(void) -{ - g_hash_table_destroy(logs); - g_hash_table_destroy(groupchat_logs); -} - static char* _get_log_filename(const char* const other, const char* const login, GDateTime* dt, gboolean is_room) { diff --git a/src/chatlog.h b/src/chatlog.h index af61c8a5..94717fbf 100644 --- a/src/chatlog.h +++ b/src/chatlog.h @@ -45,7 +45,7 @@ typedef enum { PROF_OUT_LOG } chat_log_direction_t; -void chat_log_init(void); +void chatlog_init(void); void chat_log_msg_out(const char* const barejid, const char* const msg, const char* resource); void chat_log_otr_msg_out(const char* const barejid, const char* const msg, const char* resource); @@ -57,8 +57,6 @@ void chat_log_otr_msg_in(ProfMessage* message); void chat_log_pgp_msg_in(ProfMessage* message); void chat_log_omemo_msg_in(ProfMessage* message); -void chat_log_close(void); - void groupchat_log_init(void); void groupchat_log_msg_out(const gchar* const room, const gchar* const msg); diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 0253d411..d432cd0b 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2840,6 +2840,14 @@ cmd_search_index_all(char* term) return results; } +static void +_cmd_uninit(void) +{ + cmd_ac_uninit(); + g_hash_table_destroy(commands); + g_hash_table_destroy(search_index); +} + /* * Initialise command autocompleter and history */ @@ -2848,6 +2856,8 @@ cmd_init(void) { log_info("Initialising commands"); + prof_add_shutdown_routine(_cmd_uninit); + cmd_ac_init(); search_index = g_hash_table_new_full(g_str_hash, g_str_equal, free, g_free); @@ -2878,14 +2888,6 @@ cmd_init(void) prefs_free_aliases(aliases); } -void -cmd_uninit(void) -{ - cmd_ac_uninit(); - g_hash_table_destroy(commands); - g_hash_table_destroy(search_index); -} - gboolean cmd_valid_tag(const char* const str) { diff --git a/src/command/cmd_defs.h b/src/command/cmd_defs.h index cb4cf481..846e79dd 100644 --- a/src/command/cmd_defs.h +++ b/src/command/cmd_defs.h @@ -42,7 +42,6 @@ #include "ui/ui.h" void cmd_init(void); -void cmd_uninit(void); Command* cmd_get(const char* const command); GList* cmd_get_ordered(const char* const tag); diff --git a/src/common.h b/src/common.h index 5996c5d5..6e32e6ea 100644 --- a/src/common.h +++ b/src/common.h @@ -196,5 +196,6 @@ gchar* get_expanded_path(const char* path); char* basename_from_url(const char* url); gchar* prof_get_version(void); +void prof_add_shutdown_routine(void (*routine)(void)); #endif diff --git a/src/config/accounts.c b/src/config/accounts.c index 203e9474..e8ea84b2 100644 --- a/src/config/accounts.c +++ b/src/config/accounts.c @@ -61,10 +61,22 @@ static Autocomplete enabled_ac; static void _save_accounts(void); +static void +_accounts_close(void) +{ + autocomplete_free(all_ac); + autocomplete_free(enabled_ac); + free_keyfile(&accounts_prof_keyfile); + accounts = NULL; +} + void accounts_load(void) { log_info("Loading accounts"); + + prof_add_shutdown_routine(_accounts_close); + all_ac = autocomplete_new(); enabled_ac = autocomplete_new(); load_data_keyfile(&accounts_prof_keyfile, FILE_ACCOUNTS); @@ -82,15 +94,6 @@ accounts_load(void) } } -void -accounts_close(void) -{ - autocomplete_free(all_ac); - autocomplete_free(enabled_ac); - free_keyfile(&accounts_prof_keyfile); - accounts = NULL; -} - char* accounts_find_enabled(const char* const prefix, gboolean previous, void* context) { diff --git a/src/config/accounts.h b/src/config/accounts.h index 06599054..d72ebac2 100644 --- a/src/config/accounts.h +++ b/src/config/accounts.h @@ -42,7 +42,6 @@ #include "config/account.h" void accounts_load(void); -void accounts_close(void); char* accounts_find_all(const char* const prefix, gboolean previous, void* context); char* accounts_find_enabled(const char* const prefix, gboolean previous, void* context); diff --git a/src/config/theme.c b/src/config/theme.c index 63940f12..7cb459df 100644 --- a/src/config/theme.c +++ b/src/config/theme.c @@ -66,6 +66,28 @@ static void _theme_list_dir(const gchar* const dir, GSList** result); static GString* _theme_find(const char* const theme_name); static gboolean _theme_load_file(const char* const theme_name); +static void +_theme_close(void) +{ + color_pair_cache_free(); + if (theme) { + g_key_file_free(theme); + theme = NULL; + } + if (theme_loc) { + g_string_free(theme_loc, TRUE); + theme_loc = NULL; + } + if (bold_items) { + g_hash_table_destroy(bold_items); + bold_items = NULL; + } + if (defaults) { + g_hash_table_destroy(defaults); + defaults = NULL; + } +} + void theme_init(const char* const theme_name) { @@ -77,6 +99,8 @@ theme_init(const char* const theme_name) } } + prof_add_shutdown_routine(_theme_close); + defaults = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); // Set default colors @@ -248,28 +272,6 @@ theme_list(void) return result; } -void -theme_close(void) -{ - color_pair_cache_free(); - if (theme) { - g_key_file_free(theme); - theme = NULL; - } - if (theme_loc) { - g_string_free(theme_loc, TRUE); - theme_loc = NULL; - } - if (bold_items) { - g_hash_table_destroy(bold_items); - bold_items = NULL; - } - if (defaults) { - g_hash_table_destroy(defaults); - defaults = NULL; - } -} - void theme_init_colours(void) { diff --git a/src/config/tlscerts.c b/src/config/tlscerts.c index 35548b9f..4f45da36 100644 --- a/src/config/tlscerts.c +++ b/src/config/tlscerts.c @@ -56,10 +56,25 @@ static Autocomplete certs_ac; static char* current_fp; +static void +_tlscerts_close(void) +{ + free_keyfile(&tlscerts_prof_keyfile); + tlscerts = NULL; + + free(current_fp); + current_fp = NULL; + + autocomplete_free(certs_ac); +} + void tlscerts_init(void) { log_info("Loading TLS certificates"); + + prof_add_shutdown_routine(_tlscerts_close); + load_data_keyfile(&tlscerts_prof_keyfile, FILE_TLSCERTS); tlscerts = tlscerts_prof_keyfile.keyfile; @@ -356,18 +371,6 @@ tlscerts_free(TLSCertificate* cert) } } -void -tlscerts_close(void) -{ - free_keyfile(&tlscerts_prof_keyfile); - tlscerts = NULL; - - free(current_fp); - current_fp = NULL; - - autocomplete_free(certs_ac); -} - static void _save_tlscerts(void) { diff --git a/src/config/tlscerts.h b/src/config/tlscerts.h index ab3d00e2..b8c9b5c4 100644 --- a/src/config/tlscerts.h +++ b/src/config/tlscerts.h @@ -96,6 +96,4 @@ char* tlscerts_complete(const char* const prefix, gboolean previous, void* conte void tlscerts_reset_ac(void); -void tlscerts_close(void); - #endif diff --git a/src/log.c b/src/log.c index 968b30e2..cacf573b 100644 --- a/src/log.c +++ b/src/log.c @@ -313,6 +313,21 @@ log_stderr_nonblock_set(int fd) return rc; } +static void +_log_stderr_close(void) +{ + if (!stderr_inited) + return; + + /* handle remaining logs before close */ + log_stderr_handler(); + stderr_inited = 0; + free(stderr_buf); + g_string_free(stderr_msg, TRUE); + close(stderr_pipe[0]); + close(stderr_pipe[1]); +} + void log_stderr_init(log_level_t level) { @@ -337,6 +352,8 @@ log_stderr_init(log_level_t level) stderr_level = level; stderr_inited = 1; + prof_add_shutdown_routine(_log_stderr_close); + if (stderr_buf == NULL || stderr_msg == NULL) { errno = ENOMEM; goto err_free; @@ -354,18 +371,3 @@ err: stderr_inited = 0; log_error("Unable to init stderr log handler: %s", strerror(errno)); } - -void -log_stderr_close(void) -{ - if (!stderr_inited) - return; - - /* handle remaining logs before close */ - log_stderr_handler(); - stderr_inited = 0; - free(stderr_buf); - g_string_free(stderr_msg, TRUE); - close(stderr_pipe[0]); - close(stderr_pipe[1]); -} diff --git a/src/log.h b/src/log.h index 671747ae..14394a24 100644 --- a/src/log.h +++ b/src/log.h @@ -59,7 +59,6 @@ int log_level_from_string(char* log_level, log_level_t* level); const char* log_string_from_level(log_level_t level); void log_stderr_init(log_level_t level); -void log_stderr_close(void); void log_stderr_handler(void); #endif diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index da0bfc53..5b512c19 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -116,10 +116,23 @@ static struct omemo_static_data GHashTable* fingerprint_ac; } omemo_static_data; +static void +_omemo_close(void) +{ + if (omemo_static_data.fingerprint_ac) { + g_hash_table_destroy(omemo_static_data.fingerprint_ac); + omemo_static_data.fingerprint_ac = NULL; + } + pthread_mutex_destroy(&omemo_static_data.lock); +} + void omemo_init(void) { log_info("[OMEMO] initialising"); + + prof_add_shutdown_routine(_omemo_close); + if (omemo_crypto_init() != 0) { cons_show("Error initializing OMEMO crypto: gcry_check_version() failed"); } @@ -131,16 +144,6 @@ omemo_init(void) omemo_static_data.fingerprint_ac = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)autocomplete_free); } -void -omemo_close(void) -{ - if (omemo_static_data.fingerprint_ac) { - g_hash_table_destroy(omemo_static_data.fingerprint_ac); - omemo_static_data.fingerprint_ac = NULL; - } - pthread_mutex_destroy(&omemo_static_data.lock); -} - void omemo_on_connect(ProfAccount* account) { diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index 040ab4b7..39479da5 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -61,7 +61,6 @@ typedef struct omemo_key } omemo_key_t; void omemo_init(void); -void omemo_close(void); void omemo_on_connect(ProfAccount* account); void omemo_on_disconnect(void); void omemo_generate_crypto_materials(ProfAccount* account); diff --git a/src/otr/otr.c b/src/otr/otr.c index cd774f56..1ec5695d 100644 --- a/src/otr/otr.c +++ b/src/otr/otr.c @@ -166,12 +166,24 @@ otr_start_query(void) return otrlib_start_query(); } +static void +_otr_shutdown(void) +{ + if (jid) { + free(jid); + jid = NULL; + } + otrlib_shutdown(); +} + void otr_init(void) { log_info("Initialising OTR"); OTRL_INIT; + prof_add_shutdown_routine(_otr_shutdown); + jid = NULL; ops.policy = cb_policy; @@ -187,16 +199,6 @@ otr_init(void) data_loaded = FALSE; } -void -otr_shutdown(void) -{ - if (jid) { - free(jid); - jid = NULL; - } - otrlib_shutdown(); -} - void otr_poll(void) { diff --git a/src/otr/otr.h b/src/otr/otr.h index c909c721..ee5255de 100644 --- a/src/otr/otr.h +++ b/src/otr/otr.h @@ -66,7 +66,6 @@ OtrlMessageAppOps* otr_messageops(void); GHashTable* otr_smpinitators(void); void otr_init(void); -void otr_shutdown(void); char* otr_libotr_version(void); char* otr_start_query(void); void otr_poll(void); diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c index 8cb90362..483ef8c3 100644 --- a/src/pgp/gpg.c +++ b/src/pgp/gpg.c @@ -111,25 +111,8 @@ _p_gpg_passphrase_cb(void* hook, const char* uid_hint, const char* passphrase_in return 0; } -void -p_gpg_init(void) -{ - libversion = gpgme_check_version(NULL); - log_debug("GPG: Found gpgme version: %s", libversion); - gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); - - pubkeys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_p_gpg_free_pubkeyid); - - key_ac = autocomplete_new(); - GHashTable* keys = p_gpg_list_keys(); - p_gpg_free_keys(keys); - - passphrase = NULL; - passphrase_attempt = NULL; -} - -void -p_gpg_close(void) +static void +_p_gpg_close(void) { if (pubkeys) { g_hash_table_destroy(pubkeys); @@ -153,6 +136,25 @@ p_gpg_close(void) } } +void +p_gpg_init(void) +{ + libversion = gpgme_check_version(NULL); + log_debug("GPG: Found gpgme version: %s", libversion); + gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); + + prof_add_shutdown_routine(_p_gpg_close); + + pubkeys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_p_gpg_free_pubkeyid); + + key_ac = autocomplete_new(); + GHashTable* keys = p_gpg_list_keys(); + p_gpg_free_keys(keys); + + passphrase = NULL; + passphrase_attempt = NULL; +} + void p_gpg_on_connect(const char* const barejid) { @@ -208,7 +210,7 @@ p_gpg_on_connect(const char* const barejid) void p_gpg_on_disconnect(void) { - p_gpg_close(); + _p_gpg_close(); pubkeys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_p_gpg_free_pubkeyid); key_ac = autocomplete_new(); } diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h index 883aaf73..d1cff52e 100644 --- a/src/pgp/gpg.h +++ b/src/pgp/gpg.h @@ -55,7 +55,6 @@ typedef struct pgp_pubkeyid_t } ProfPGPPubKeyId; void p_gpg_init(void); -void p_gpg_close(void); void p_gpg_on_connect(const char* const barejid); void p_gpg_on_disconnect(void); GHashTable* p_gpg_list_keys(void); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 6238525d..2236e94f 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -65,9 +65,49 @@ static GHashTable* plugins; +static void +_plugins_shutdown(void) +{ + GList* values = g_hash_table_get_values(plugins); + GList *curr = values, *next; + + while (curr) { + next = g_list_next(curr); +#ifdef HAVE_PYTHON + if (curr && ((ProfPlugin*)curr->data)->lang == LANG_PYTHON) { + python_plugin_destroy(curr->data); + curr = NULL; + } +#endif +#ifdef HAVE_C + if (curr && ((ProfPlugin*)curr->data)->lang == LANG_C) { + c_plugin_destroy(curr->data); + curr = NULL; + } +#endif + curr = next; + } + g_list_free(values); +#ifdef HAVE_PYTHON + python_shutdown(); +#endif +#ifdef HAVE_C + c_shutdown(); +#endif + + autocompleters_destroy(); + plugin_themes_close(); + plugin_settings_close(); + callbacks_close(); + disco_close(); + g_hash_table_destroy(plugins); + plugins = NULL; +} + void plugins_init(void) { + prof_add_shutdown_routine(_plugins_shutdown); plugins = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); callbacks_init(); autocompleters_init(); @@ -421,21 +461,8 @@ plugins_close_win(const char* const plugin_name, const char* const tag) callbacks_remove_win(plugin_name, tag); } -void -plugins_on_start(void) -{ - GList* values = g_hash_table_get_values(plugins); - GList* curr = values; - while (curr) { - ProfPlugin* plugin = curr->data; - plugin->on_start_func(plugin); - curr = g_list_next(curr); - } - g_list_free(values); -} - -void -plugins_on_shutdown(void) +static void +_plugins_on_shutdown(void) { GList* values = g_hash_table_get_values(plugins); GList* curr = values; @@ -447,6 +474,20 @@ plugins_on_shutdown(void) g_list_free(values); } +void +plugins_on_start(void) +{ + prof_add_shutdown_routine(_plugins_on_shutdown); + GList* values = g_hash_table_get_values(plugins); + GList* curr = values; + while (curr) { + ProfPlugin* plugin = curr->data; + plugin->on_start_func(plugin); + curr = g_list_next(curr); + } + g_list_free(values); +} + void plugins_on_connect(const char* const account_name, const char* const fulljid) { @@ -924,42 +965,3 @@ plugins_get_disco_features(void) { return disco_get_features(); } - -void -plugins_shutdown(void) -{ - GList* values = g_hash_table_get_values(plugins); - GList *curr = values, *next; - - while (curr) { - next = g_list_next(curr); -#ifdef HAVE_PYTHON - if (curr && ((ProfPlugin*)curr->data)->lang == LANG_PYTHON) { - python_plugin_destroy(curr->data); - curr = NULL; - } -#endif -#ifdef HAVE_C - if (curr && ((ProfPlugin*)curr->data)->lang == LANG_C) { - c_plugin_destroy(curr->data); - curr = NULL; - } -#endif - curr = next; - } - g_list_free(values); -#ifdef HAVE_PYTHON - python_shutdown(); -#endif -#ifdef HAVE_C - c_shutdown(); -#endif - - autocompleters_destroy(); - plugin_themes_close(); - plugin_settings_close(); - callbacks_close(); - disco_close(); - g_hash_table_destroy(plugins); - plugins = NULL; -} diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 0bd69e41..85087e51 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -113,7 +113,6 @@ GSList* plugins_unloaded_list(void); GList* plugins_loaded_list(void); char* plugins_autocomplete(const char* const input, gboolean previous); void plugins_reset_autocomplete(void); -void plugins_shutdown(void); void plugins_free_install_result(PluginsInstallResult* result); @@ -129,7 +128,6 @@ gboolean plugins_reload(const char* const name, GString* error_message); void plugins_reload_all(void); void plugins_on_start(void); -void plugins_on_shutdown(void); void plugins_on_connect(const char* const account_name, const char* const fulljid); void plugins_on_disconnect(const char* const account_name, const char* const fulljid); diff --git a/src/profanity.c b/src/profanity.c index dea5a6a1..0b639bb1 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -220,8 +220,7 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name) auto_gchar gchar* prof_version = prof_get_version(); log_info("Starting Profanity (%s)…", prof_version); - chat_log_init(); - groupchat_log_init(); + chatlog_init(); accounts_load(); if (theme_name) { @@ -261,6 +260,47 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name) ui_resize(); } +static GList* shutdown_routines = NULL; + +/* We have to encapsulate the function pointer, since the C standard does not guarantee + * that a void* can be converted to a function* and vice-versa. + */ +struct shutdown_routine +{ + void (*routine)(void); +}; + +static gint +_cmp_shutdown_routine(const struct shutdown_routine* a, const struct shutdown_routine* b) +{ + return a->routine != b->routine; +} + +void +prof_add_shutdown_routine(void (*routine)(void)) +{ + struct shutdown_routine this = { .routine = routine }; + if (g_list_find_custom(shutdown_routines, &this, (GCompareFunc)_cmp_shutdown_routine)) { + return; + } + struct shutdown_routine* r = malloc(sizeof *r); + r->routine = routine; + shutdown_routines = g_list_prepend(shutdown_routines, r); +} + +static void +_call_and_free_shutdown_routine(struct shutdown_routine* r) +{ + r->routine(); + free(r); +} + +void +prof_shutdown(void) +{ + g_list_free_full(shutdown_routines, (GDestroyNotify)_call_and_free_shutdown_routine); +} + static void _shutdown(void) { @@ -276,30 +316,9 @@ _shutdown(void) if (conn_status == JABBER_CONNECTED) { cl_ev_disconnect(); } -#ifdef HAVE_GTK - tray_shutdown(); -#endif - session_shutdown(); - plugins_on_shutdown(); - muc_close(); - caps_close(); -#ifdef HAVE_LIBOTR - otr_shutdown(); -#endif -#ifdef HAVE_LIBGPGME - p_gpg_close(); -#endif -#ifdef HAVE_OMEMO - omemo_close(); -#endif - chat_log_close(); - theme_close(); - accounts_close(); - tlscerts_close(); - log_stderr_close(); - plugins_shutdown(); - cmd_uninit(); - ui_close(); + prof_shutdown(); + /* Prefs and logs have to be closed in swapped order, so they're no using the automatic + * shutdown mechanism. */ prefs_close(); log_close(); } diff --git a/src/ui/core.c b/src/ui/core.c index 5db89137..b5a2eb1a 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -89,10 +89,26 @@ static Display* display; static void _ui_draw_term_title(void); +static void +_ui_close(void) +{ + g_timer_destroy(ui_idle_time); + endwin(); + notifier_uninit(); + cons_clear_alerts(); + wins_destroy(); + inp_close(); + status_bar_close(); + free_title_bar(); + delwin(main_scr); + delscreen(set_term(NULL)); +} + void ui_init(void) { log_info("Initialising UI"); + prof_add_shutdown_routine(_ui_close); main_scr = initscr(); nonl(); cbreak(); @@ -180,21 +196,6 @@ ui_reset_idle_time(void) g_timer_start(ui_idle_time); } -void -ui_close(void) -{ - g_timer_destroy(ui_idle_time); - endwin(); - notifier_uninit(); - cons_clear_alerts(); - wins_destroy(); - inp_close(); - status_bar_close(); - free_title_bar(); - delwin(main_scr); - delscreen(set_term(NULL)); -} - void ui_resize(void) { diff --git a/src/ui/tray.c b/src/ui/tray.c index 0e577f8e..a1b28692 100644 --- a/src/ui/tray.c +++ b/src/ui/tray.c @@ -153,9 +153,21 @@ _tray_change_icon(gpointer data) return TRUE; } +static void +_tray_shutdown(void) +{ + if (gtk_ready && prefs_get_boolean(PREF_TRAY)) { + tray_disable(); + } + g_string_free(icon_filename, TRUE); + g_string_free(icon_msg_filename, TRUE); + gtk_main_quit(); +} + void tray_init(void) { + prof_add_shutdown_routine(_tray_shutdown); _get_icons(); gtk_ready = gtk_init_check(0, NULL); log_debug("Env is GTK-ready: %s", gtk_ready ? "true" : "false"); @@ -179,17 +191,6 @@ tray_update(void) } } -void -tray_shutdown(void) -{ - if (gtk_ready && prefs_get_boolean(PREF_TRAY)) { - tray_disable(); - } - g_string_free(icon_filename, TRUE); - g_string_free(icon_msg_filename, TRUE); - gtk_main_quit(); -} - void tray_set_timer(int interval) { diff --git a/src/ui/tray.h b/src/ui/tray.h index 89e51ec0..bb449125 100644 --- a/src/ui/tray.h +++ b/src/ui/tray.h @@ -39,7 +39,6 @@ #ifdef HAVE_GTK void tray_init(void); void tray_update(void); -void tray_shutdown(void); void tray_enable(void); void tray_disable(void); diff --git a/src/ui/ui.h b/src/ui/ui.h index 8841ba07..a8d04ab0 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -62,7 +62,6 @@ void ui_init(void); void ui_load_colours(void); void ui_update(void); -void ui_close(void); void ui_redraw(void); void ui_resize(void); void ui_focus_win(ProfWin* window); diff --git a/src/xmpp/capabilities.c b/src/xmpp/capabilities.c index 96bbd574..4e1e5e2c 100644 --- a/src/xmpp/capabilities.c +++ b/src/xmpp/capabilities.c @@ -69,10 +69,26 @@ static EntityCapabilities* _caps_by_ver(const char* const ver); static EntityCapabilities* _caps_by_jid(const char* const jid); static EntityCapabilities* _caps_copy(EntityCapabilities* caps); +static void +_caps_close(void) +{ + free_keyfile(&caps_prof_keyfile); + cache = NULL; + g_hash_table_destroy(jid_to_ver); + g_hash_table_destroy(jid_to_caps); + g_free(cache_loc); + cache_loc = NULL; + g_hash_table_destroy(prof_features); + prof_features = NULL; +} + void caps_init(void) { log_info("Loading capabilities cache"); + + prof_add_shutdown_routine(_caps_close); + load_data_keyfile(&caps_prof_keyfile, FILE_CAPSCACHE); cache = caps_prof_keyfile.keyfile; @@ -339,19 +355,6 @@ caps_reset_ver(void) } } -void -caps_close(void) -{ - free_keyfile(&caps_prof_keyfile); - cache = NULL; - g_hash_table_destroy(jid_to_ver); - g_hash_table_destroy(jid_to_caps); - g_free(cache_loc); - cache_loc = NULL; - g_hash_table_destroy(prof_features); - prof_features = NULL; -} - static EntityCapabilities* _caps_by_ver(const char* const ver) { diff --git a/src/xmpp/muc.c b/src/xmpp/muc.c index 5c47cd75..b6bb57c9 100644 --- a/src/xmpp/muc.c +++ b/src/xmpp/muc.c @@ -91,17 +91,8 @@ static Occupant* _muc_occupant_new(const char* const nick, const char* const jid muc_affiliation_t affiliation, resource_presence_t presence, const char* const status); static void _occupant_free(Occupant* occupant); -void -muc_init(void) -{ - invite_ac = autocomplete_new(); - confservers_ac = autocomplete_new(); - rooms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_room); - invite_passwords = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); -} - -void -muc_close(void) +static void +_muc_close(void) { autocomplete_free(invite_ac); autocomplete_free(confservers_ac); @@ -113,6 +104,16 @@ muc_close(void) confservers_ac = NULL; } +void +muc_init(void) +{ + prof_add_shutdown_routine(_muc_close); + invite_ac = autocomplete_new(); + confservers_ac = autocomplete_new(); + rooms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_room); + invite_passwords = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); +} + void muc_confserver_add(const char* const server) { diff --git a/src/xmpp/muc.h b/src/xmpp/muc.h index 5e099cea..7ae7a0c9 100644 --- a/src/xmpp/muc.h +++ b/src/xmpp/muc.h @@ -82,7 +82,6 @@ typedef struct _muc_occupant_t } Occupant; void muc_init(void); -void muc_close(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); diff --git a/src/xmpp/session.c b/src/xmpp/session.c index e1b4c1a3..8716bb0d 100644 --- a/src/xmpp/session.c +++ b/src/xmpp/session.c @@ -99,10 +99,25 @@ static char* saved_status; static void _session_free_internals(void); static void _session_free_saved_details(void); +static void +_session_shutdown(void) +{ + _session_free_internals(); + + chat_sessions_clear(); + presence_sub_requests_destroy(); + + connection_shutdown(); + if (saved_status) { + free(saved_status); + } +} + void session_init(void) { log_info("Initialising XMPP"); + prof_add_shutdown_routine(_session_shutdown); connection_init(); presence_sub_requests_init(); caps_init(); @@ -227,20 +242,6 @@ session_disconnect(void) connection_set_disconnected(); } -void -session_shutdown(void) -{ - _session_free_internals(); - - chat_sessions_clear(); - presence_sub_requests_destroy(); - - connection_shutdown(); - if (saved_status) { - free(saved_status); - } -} - void session_process_events(void) { diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 755ad273..f6ed92dd 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -183,7 +183,6 @@ jabber_conn_status_t session_connect_with_details(const char* const jid, const c jabber_conn_status_t session_connect_with_account(const ProfAccount* const account); void session_disconnect(void); -void session_shutdown(void); void session_process_events(void); const char* session_get_account_name(void); void session_reconnect_now(void); @@ -275,7 +274,6 @@ void iq_muc_register_nick(const char* const roomjid); void autoping_timer_extend(void); EntityCapabilities* caps_lookup(const char* const jid); -void caps_close(void); void caps_destroy(EntityCapabilities* caps); void caps_reset_ver(void); void caps_add_feature(char* feature); diff --git a/tests/unittests/chatlog/stub_chatlog.c b/tests/unittests/chatlog/stub_chatlog.c index 33251f57..2d8eb382 100644 --- a/tests/unittests/chatlog/stub_chatlog.c +++ b/tests/unittests/chatlog/stub_chatlog.c @@ -27,7 +27,7 @@ #include void -chat_log_init(void) +chatlog_init(void) { } @@ -65,11 +65,6 @@ chat_log_omemo_msg_in(ProfMessage* message) { } -void -chat_log_close(void) -{ -} - void groupchat_log_init(void) { diff --git a/tests/unittests/config/stub_accounts.c b/tests/unittests/config/stub_accounts.c index a3fcacc7..360e5643 100644 --- a/tests/unittests/config/stub_accounts.c +++ b/tests/unittests/config/stub_accounts.c @@ -10,10 +10,6 @@ void accounts_load(void) { } -void -accounts_close(void) -{ -} char* accounts_find_all(const char* const prefix, gboolean previous, void* context) diff --git a/tests/unittests/log/stub_log.c b/tests/unittests/log/stub_log.c index 18d05eca..23ab5cdc 100644 --- a/tests/unittests/log/stub_log.c +++ b/tests/unittests/log/stub_log.c @@ -78,10 +78,6 @@ log_stderr_init(log_level_t level) { } void -log_stderr_close(void) -{ -} -void log_stderr_handler(void) { } diff --git a/tests/unittests/omemo/stub_omemo.c b/tests/unittests/omemo/stub_omemo.c index 0336e1a3..986de079 100644 --- a/tests/unittests/omemo/stub_omemo.c +++ b/tests/unittests/omemo/stub_omemo.c @@ -7,10 +7,6 @@ void omemo_init(void) { } -void -omemo_close(void) -{ -} char* omemo_fingerprint_autocomplete(const char* const search_str, gboolean previous) diff --git a/tests/unittests/otr/stub_otr.c b/tests/unittests/otr/stub_otr.c index d6827c66..291db41c 100644 --- a/tests/unittests/otr/stub_otr.c +++ b/tests/unittests/otr/stub_otr.c @@ -33,10 +33,6 @@ void otr_init(void) { } -void -otr_shutdown(void) -{ -} char* otr_libotr_version(void) diff --git a/tests/unittests/pgp/stub_gpg.c b/tests/unittests/pgp/stub_gpg.c index 6333e723..249a2c9c 100644 --- a/tests/unittests/pgp/stub_gpg.c +++ b/tests/unittests/pgp/stub_gpg.c @@ -6,10 +6,6 @@ void p_gpg_init(void) { } -void -p_gpg_close(void) -{ -} GHashTable* p_gpg_list_keys(void) diff --git a/tests/unittests/test_server_events.c b/tests/unittests/test_server_events.c index 4ecedace..feed7709 100644 --- a/tests/unittests/test_server_events.c +++ b/tests/unittests/test_server_events.c @@ -17,6 +17,9 @@ #include "plugins/plugins.h" #include "ui/window_list.h" + +void prof_shutdown(void); + void console_shows_online_presence_when_set_online(void** state) { @@ -35,7 +38,7 @@ console_shows_online_presence_when_set_online(void** state) sv_ev_contact_online(barejid, resource, NULL, NULL); roster_destroy(); - plugins_shutdown(); + prof_shutdown(); } void @@ -56,7 +59,7 @@ console_shows_online_presence_when_set_all(void** state) sv_ev_contact_online(barejid, resource, NULL, NULL); roster_destroy(); - plugins_shutdown(); + prof_shutdown(); } void @@ -77,7 +80,7 @@ console_shows_dnd_presence_when_set_all(void** state) sv_ev_contact_online(barejid, resource, NULL, NULL); roster_destroy(); - plugins_shutdown(); + prof_shutdown(); } void @@ -103,7 +106,7 @@ handle_offline_removes_chat_session(void** state) roster_destroy(); chat_sessions_clear(); - plugins_shutdown(); + prof_shutdown(); } void diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index f45f6b07..4c6439dd 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -63,10 +63,6 @@ ui_update(void) { } void -ui_close(void) -{ -} -void ui_redraw(void) { } diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c index 1ff25e69..366f26b3 100644 --- a/tests/unittests/xmpp/stub_xmpp.c +++ b/tests/unittests/xmpp/stub_xmpp.c @@ -47,10 +47,6 @@ session_disconnect(void) { } void -session_shutdown(void) -{ -} -void session_process_events(void) { } @@ -477,11 +473,6 @@ caps_lookup(const char* const jid) return NULL; } -void -caps_close(void) -{ -} - void caps_destroy(EntityCapabilities* caps) {