about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMichael Vetter <jubalh@iodoru.org>2023-01-19 11:05:42 +0100
committerGitHub <noreply@github.com>2023-01-19 11:05:42 +0100
commit494512c25cabc2271b4132f19ad38fb8edee1afa (patch)
treee7131bb283b4731cbe0e1c595bfd7b3faa349c77
parent78496d6226cb6f00ba3b14db479497ab3cfc8160 (diff)
parent99ffaf0a008cabbc0855b0d3b818ce9a2ad6bd62 (diff)
downloadprofani-tty-494512c25cabc2271b4132f19ad38fb8edee1afa.tar.gz
Merge pull request #1780 from profanity-im/minor-improvements
Minor improvements
-rw-r--r--.gitignore3
-rw-r--r--src/command/cmd_ac.c129
-rw-r--r--src/command/cmd_ac.h2
-rw-r--r--src/command/cmd_defs.c751
-rw-r--r--src/command/cmd_funcs.c100
-rw-r--r--src/command/cmd_funcs.h7
-rw-r--r--src/common.c57
-rw-r--r--src/common.h13
-rw-r--r--src/config/account.c110
-rw-r--r--src/config/account.h19
-rw-r--r--src/config/accounts.c19
-rw-r--r--src/config/preferences.c19
-rw-r--r--src/config/preferences.h7
-rw-r--r--src/database.c14
-rw-r--r--src/log.c18
-rw-r--r--src/log.h2
-rw-r--r--src/omemo/omemo.c66
-rw-r--r--src/omemo/store.c21
-rw-r--r--src/omemo/store.h1
-rw-r--r--src/profanity.c3
-rw-r--r--src/tools/autocomplete.c49
-rw-r--r--src/tools/editor.c2
-rw-r--r--src/ui/console.c16
-rw-r--r--src/ui/ui.h1
-rw-r--r--src/ui/window.c2
-rw-r--r--src/xmpp/chat_session.c4
-rw-r--r--src/xmpp/chat_session.h2
-rw-r--r--src/xmpp/connection.c24
-rw-r--r--src/xmpp/iq.c25
-rw-r--r--src/xmpp/jid.c19
-rw-r--r--src/xmpp/jid.h5
-rw-r--r--src/xmpp/message.c48
-rw-r--r--src/xmpp/session.c12
-rw-r--r--src/xmpp/session.h1
-rw-r--r--tests/unittests/log/stub_log.c6
-rw-r--r--tests/unittests/test_cmd_account.c14
-rw-r--r--tests/unittests/test_cmd_connect.c10
-rw-r--r--tests/unittests/test_cmd_join.c32
-rw-r--r--tests/unittests/test_cmd_otr.c4
-rw-r--r--tests/unittests/test_cmd_rooms.c8
-rw-r--r--tests/unittests/ui/stub_ui.c5
-rw-r--r--tests/unittests/xmpp/stub_xmpp.c4
42 files changed, 773 insertions, 881 deletions
diff --git a/.gitignore b/.gitignore
index 446a3868..cc3402a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,6 +55,9 @@ tests/unittests/unittests.log
 tests/unittests/unittests.trs
 test-suite.log
 
+# valgrind output
+profval*
+
 # local scripts
 clean-test.sh
 gen_docs.sh
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c
index f0210713..f424d401 100644
--- a/src/command/cmd_ac.c
+++ b/src/command/cmd_ac.c
@@ -131,6 +131,7 @@ static char* _executable_autocomplete(ProfWin* window, const char* const input,
 static char* _lastactivity_autocomplete(ProfWin* window, const char* const input, gboolean previous);
 static char* _intype_autocomplete(ProfWin* window, const char* const input, gboolean previous);
 static char* _mood_autocomplete(ProfWin* window, const char* const input, gboolean previous);
+static char* _strophe_autocomplete(ProfWin* window, const char* const input, gboolean previous);
 static char* _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous);
 static char* _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous);
 
@@ -276,6 +277,9 @@ static Autocomplete executable_ac;
 static Autocomplete intype_ac;
 static Autocomplete mood_ac;
 static Autocomplete mood_type_ac;
+static Autocomplete strophe_ac;
+static Autocomplete strophe_sm_ac;
+static Autocomplete strophe_verbosity_ac;
 static Autocomplete adhoc_cmd_ac;
 static Autocomplete lastactivity_ac;
 static Autocomplete vcard_ac;
@@ -1098,6 +1102,19 @@ cmd_ac_init(void)
     autocomplete_add(intype_ac, "console");
     autocomplete_add(intype_ac, "titlebar");
 
+    strophe_ac = autocomplete_new();
+    autocomplete_add(strophe_ac, "sm");
+    autocomplete_add(strophe_ac, "verbosity");
+    strophe_sm_ac = autocomplete_new();
+    autocomplete_add(strophe_sm_ac, "on");
+    autocomplete_add(strophe_sm_ac, "no-resend");
+    autocomplete_add(strophe_sm_ac, "off");
+    strophe_verbosity_ac = autocomplete_new();
+    autocomplete_add(strophe_verbosity_ac, "0");
+    autocomplete_add(strophe_verbosity_ac, "1");
+    autocomplete_add(strophe_verbosity_ac, "2");
+    autocomplete_add(strophe_verbosity_ac, "3");
+
     mood_ac = autocomplete_new();
     autocomplete_add(mood_ac, "set");
     autocomplete_add(mood_ac, "clear");
@@ -1298,7 +1315,7 @@ cmd_ac_add_help(const char* const value)
 }
 
 void
-cmd_ac_add_cmd(Command* command)
+cmd_ac_add_cmd(const Command* command)
 {
     autocomplete_add(commands_ac, command->cmd);
     autocomplete_add(help_ac, command->cmd + 1);
@@ -1595,6 +1612,9 @@ cmd_ac_reset(ProfWin* window)
     autocomplete_reset(intype_ac);
     autocomplete_reset(mood_ac);
     autocomplete_reset(mood_type_ac);
+    autocomplete_reset(strophe_verbosity_ac);
+    autocomplete_reset(strophe_sm_ac);
+    autocomplete_reset(strophe_ac);
     autocomplete_reset(adhoc_cmd_ac);
 
     autocomplete_reset(vcard_ac);
@@ -2057,6 +2077,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
     g_hash_table_insert(ac_funcs, "/lastactivity", _lastactivity_autocomplete);
     g_hash_table_insert(ac_funcs, "/intype", _intype_autocomplete);
     g_hash_table_insert(ac_funcs, "/mood", _mood_autocomplete);
+    g_hash_table_insert(ac_funcs, "/strophe", _strophe_autocomplete);
     g_hash_table_insert(ac_funcs, "/cmd", _adhoc_cmd_autocomplete);
     g_hash_table_insert(ac_funcs, "/vcard", _vcard_autocomplete);
 
@@ -2360,7 +2381,7 @@ _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previo
     char* found = NULL;
 
     gboolean result;
-    gchar** args = parse_args(input, 2, 8, &result);
+    auto_gcharv gchar** args = parse_args(input, 2, 8, &result);
 
     if (result && ((strcmp(args[0], "add") == 0) || (strcmp(args[0], "update") == 0))) {
         gboolean space_at_end = g_str_has_suffix(input, " ");
@@ -2371,7 +2392,6 @@ _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previo
             found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -2382,7 +2402,6 @@ _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previo
             found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -2392,7 +2411,6 @@ _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previo
             found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -2403,7 +2421,6 @@ _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previo
             found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -2413,7 +2430,6 @@ _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previo
             found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -2424,14 +2440,11 @@ _bookmark_autocomplete(ProfWin* window, const char* const input, gboolean previo
             found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
     }
 
-    g_strfreev(args);
-
     found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find, previous, NULL);
     if (found) {
         return found;
@@ -2633,7 +2646,7 @@ _otr_autocomplete(ProfWin* window, const char* const input, gboolean previous)
     // /otr policy always user@server.com
     if (conn_status == JABBER_CONNECTED) {
         gboolean result;
-        gchar** args = parse_args(input, 2, 3, &result);
+        auto_gcharv gchar** args = parse_args(input, 2, 3, &result);
         if (result && (strcmp(args[0], "policy") == 0)) {
             GString* beginning = g_string_new("/otr ");
             g_string_append(beginning, args[0]);
@@ -2645,11 +2658,9 @@ _otr_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
-        g_strfreev(args);
     }
 
     found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE, previous);
@@ -2697,7 +2708,7 @@ _pgp_autocomplete(ProfWin* window, const char* const input, gboolean previous)
     }
 
     gboolean result;
-    gchar** args = parse_args(input, 2, 3, &result);
+    auto_gcharv gchar** args = parse_args(input, 2, 3, &result);
     if ((strncmp(input, "/pgp", 4) == 0) && (result == TRUE)) {
         GString* beginning = g_string_new("/pgp ");
         g_string_append(beginning, args[0]);
@@ -2708,11 +2719,9 @@ _pgp_autocomplete(ProfWin* window, const char* const input, gboolean previous)
         found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
         g_string_free(beginning, TRUE);
         if (found) {
-            g_strfreev(args);
             return found;
         }
     }
-    g_strfreev(args);
 
     if (conn_status == JABBER_CONNECTED) {
         found = autocomplete_param_with_func(input, "/pgp setkey", roster_barejid_autocomplete, previous, NULL);
@@ -2826,9 +2835,9 @@ _omemo_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             int num_tokens = count_tokens(input);
             if (num_tokens == 4) {
                 gboolean result;
-                gchar** args = parse_args(input, 2, 3, &result);
+                auto_gcharv gchar** args = parse_args(input, 2, 3, &result);
                 if (result) {
-                    gchar* jid = g_strdup(args[1]);
+                    auto_gchar gchar* jid = g_strdup(args[1]);
                     found = autocomplete_param_no_with_func(input, "/omemo trust", 4, omemo_fingerprint_autocomplete, previous, jid);
                     if (found) {
                         return found;
@@ -2853,9 +2862,9 @@ _omemo_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             int num_tokens = count_tokens(input);
             if (num_tokens == 4) {
                 gboolean result;
-                gchar** args = parse_args(input, 2, 3, &result);
+                auto_gcharv gchar** args = parse_args(input, 2, 3, &result);
                 if (result) {
-                    gchar* jid = g_strdup(args[1]);
+                    auto_gchar gchar* jid = g_strdup(args[1]);
                     found = autocomplete_param_no_with_func(input, "/omemo untrust", 4, omemo_fingerprint_autocomplete, previous, jid);
                     if (found) {
                         return found;
@@ -3389,7 +3398,7 @@ _affiliation_autocomplete(ProfWin* window, const char* const input, gboolean pre
         gboolean parse_result;
         Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
 
-        gchar** args = parse_args(input, 2, 3, &parse_result);
+        auto_gcharv gchar** args = parse_args(input, 2, 3, &parse_result);
 
         if ((strncmp(input, "/affiliation", 12) == 0) && (parse_result == TRUE)) {
             GString* beginning = g_string_new("/affiliation ");
@@ -3402,12 +3411,9 @@ _affiliation_autocomplete(ProfWin* window, const char* const input, gboolean pre
             result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (result) {
-                g_strfreev(args);
                 return result;
             }
         }
-
-        g_strfreev(args);
     }
 
     result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE, previous);
@@ -3436,7 +3442,7 @@ _role_autocomplete(ProfWin* window, const char* const input, gboolean previous)
         gboolean parse_result;
         Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
 
-        gchar** args = parse_args(input, 2, 3, &parse_result);
+        auto_gcharv gchar** args = parse_args(input, 2, 3, &parse_result);
 
         if ((strncmp(input, "/role", 5) == 0) && (parse_result == TRUE)) {
             GString* beginning = g_string_new("/role ");
@@ -3449,12 +3455,9 @@ _role_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (result) {
-                g_strfreev(args);
                 return result;
             }
         }
-
-        g_strfreev(args);
     }
 
     result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE, previous);
@@ -3568,7 +3571,7 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
     char* found = NULL;
     gboolean result = FALSE;
 
-    gchar** args = parse_args(input, 1, 9, &result);
+    auto_gcharv gchar** args = parse_args(input, 1, 9, &result);
 
     if (result) {
         gboolean space_at_end = g_str_has_suffix(input, " ");
@@ -3579,7 +3582,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3590,7 +3592,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3600,7 +3601,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3611,7 +3611,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3621,7 +3620,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3632,7 +3630,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3642,7 +3639,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3653,7 +3649,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3667,7 +3662,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3678,7 +3672,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3689,7 +3682,6 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3700,14 +3692,11 @@ _connect_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
     }
 
-    g_strfreev(args);
-
     found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled, previous, NULL);
     if (found) {
         return found;
@@ -3736,7 +3725,7 @@ _join_autocomplete(ProfWin* window, const char* const input, gboolean previous)
     char* found = NULL;
     gboolean result = FALSE;
 
-    gchar** args = parse_args(input, 1, 5, &result);
+    auto_gcharv gchar** args = parse_args(input, 1, 5, &result);
 
     if (result) {
         gboolean space_at_end = g_str_has_suffix(input, " ");
@@ -3747,7 +3736,6 @@ _join_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3757,14 +3745,11 @@ _join_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
     }
 
-    g_strfreev(args);
-
     found = autocomplete_param_with_func(input, "/join", bookmark_find, previous, NULL);
 
     return found;
@@ -3856,7 +3841,7 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
     char* found = NULL;
     gboolean result = FALSE;
 
-    gchar** args = parse_args(input, 2, 4, &result);
+    auto_gcharv gchar** args = parse_args(input, 2, 4, &result);
     if (result && (strcmp(args[0], "set") == 0)) {
         gboolean space_at_end = g_str_has_suffix(input, " ");
         int num_args = g_strv_length(args);
@@ -3866,7 +3851,6 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3890,7 +3874,6 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, account_status_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3901,7 +3884,6 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, tls_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3912,7 +3894,6 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, auth_property_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3923,7 +3904,6 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_func(input, beginning->str, _script_autocomplete_func, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3945,7 +3925,6 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_ac(input, beginning->str, theme_load_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3957,7 +3936,6 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
             found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -3970,13 +3948,10 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
         found = autocomplete_param_with_ac(input, beginning->str, account_clear_ac, TRUE, previous);
         g_string_free(beginning, TRUE);
         if (found) {
-            g_strfreev(args);
             return found;
         }
     }
 
-    g_strfreev(args);
-
     found = autocomplete_param_with_ac(input, "/account default", account_default_ac, TRUE, previous);
     if (found) {
         return found;
@@ -4033,7 +4008,7 @@ _rooms_autocomplete(ProfWin* window, const char* const input, gboolean previous)
     char* found = NULL;
     gboolean result = FALSE;
 
-    gchar** args = parse_args(input, 0, 4, &result);
+    auto_gcharv gchar** args = parse_args(input, 0, 4, &result);
 
     if (result) {
         gboolean space_at_end = g_str_has_suffix(input, " ");
@@ -4041,21 +4016,18 @@ _rooms_autocomplete(ProfWin* window, const char* const input, gboolean previous)
         if (num_args <= 1) {
             found = autocomplete_param_with_ac(input, "/rooms", rooms_all_ac, TRUE, previous);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
         if ((num_args == 1 && g_strcmp0(args[0], "service") == 0 && space_at_end) || (num_args == 2 && g_strcmp0(args[0], "service") == 0 && !space_at_end)) {
             found = autocomplete_param_with_func(input, "/rooms service", muc_confserver_find, previous, NULL);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
         if ((num_args == 1 && g_strcmp0(args[0], "cache") == 0 && space_at_end) || (num_args == 2 && g_strcmp0(args[0], "cache") == 0 && !space_at_end)) {
             found = autocomplete_param_with_ac(input, "/rooms cache", rooms_cache_ac, TRUE, previous);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -4065,7 +4037,6 @@ _rooms_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             found = autocomplete_param_with_ac(input, beginning->str, rooms_list_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
@@ -4075,18 +4046,14 @@ _rooms_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             found = autocomplete_param_with_func(input, beginning->str, muc_confserver_find, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
-                g_strfreev(args);
                 return found;
             }
         }
         if ((num_args >= 2) && g_strcmp0(args[0], "cache") == 0) {
-            g_strfreev(args);
             return NULL;
         }
     }
 
-    g_strfreev(args);
-
     return NULL;
 }
 
@@ -4353,7 +4320,7 @@ _url_autocomplete(ProfWin* window, const char* const input, gboolean previous)
         }
 
         gboolean arg_result;
-        gchar** args = parse_args(input, 1, 8, &arg_result);
+        auto_gcharv gchar** args = parse_args(input, 1, 8, &arg_result);
         gboolean space_at_end = g_str_has_suffix(input, " ");
         int num_args = g_strv_length(args);
 
@@ -4366,7 +4333,6 @@ _url_autocomplete(ProfWin* window, const char* const input, gboolean previous)
                 g_free(cmd);
             }
         }
-        g_strfreev(args);
     }
 
     return result;
@@ -4443,6 +4409,24 @@ _mood_autocomplete(ProfWin* window, const char* const input, gboolean previous)
 }
 
 static char*
+_strophe_autocomplete(ProfWin* window, const char* const input, gboolean previous)
+{
+    char* result = NULL;
+
+    result = autocomplete_param_with_ac(input, "/strophe sm", strophe_sm_ac, FALSE, previous);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/strophe verbosity", strophe_verbosity_ac, FALSE, previous);
+    if (result) {
+        return result;
+    }
+
+    return autocomplete_param_with_ac(input, "/strophe", strophe_ac, FALSE, previous);
+}
+
+static char*
 _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous)
 {
     char* result = NULL;
@@ -4458,7 +4442,7 @@ _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
     char* result = NULL;
 
     gboolean parse_result = FALSE;
-    gchar** args = parse_args(input, 0, 7, &parse_result);
+    auto_gcharv gchar** args = parse_args(input, 0, 7, &parse_result);
 
     if (parse_result && (g_strcmp0(args[0], "set") == 0)) {
         gboolean space_at_end = g_str_has_suffix(input, " ");
@@ -4480,7 +4464,6 @@ _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             result = autocomplete_param_with_ac(input, beginning->str, vcard_set_param_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (result) {
-                g_strfreev(args);
                 return result;
             }
         } else if ((num_args == 3 && space_at_end && is_num && (g_strcmp0(args[2], "type") == 0)) || (num_args == 4 && !space_at_end && is_num && (g_strcmp0(args[2], "type") == 0))) {
@@ -4489,7 +4472,6 @@ _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             result = autocomplete_param_with_ac(input, beginning->str, vcard_address_type_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (result) {
-                g_strfreev(args);
                 return result;
             }
         } else if ((num_args == 3 && space_at_end && is_num && autocomplete_contains(vcard_togglable_param_ac, args[2])) || (num_args == 4 && !space_at_end && is_num && autocomplete_contains(vcard_togglable_param_ac, args[2]))) {
@@ -4498,7 +4480,6 @@ _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
             result = autocomplete_param_with_ac(input, beginning->str, vcard_toggle_ac, TRUE, previous);
             g_string_free(beginning, TRUE);
             if (result) {
-                g_strfreev(args);
                 return result;
             }
         } else {
diff --git a/src/command/cmd_ac.h b/src/command/cmd_ac.h
index ef715310..ceab49b2 100644
--- a/src/command/cmd_ac.h
+++ b/src/command/cmd_ac.h
@@ -47,7 +47,7 @@ gboolean cmd_ac_exists(char* cmd);
 
 void cmd_ac_add(const char* const value);
 void cmd_ac_add_help(const char* const value);
-void cmd_ac_add_cmd(Command* command);
+void cmd_ac_add_cmd(const Command* command);
 void cmd_ac_add_alias(ProfAlias* alias);
 void cmd_ac_add_alias_value(char* value);
 
diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c
index 0a2a7440..fb37341d 100644
--- a/src/command/cmd_defs.c
+++ b/src/command/cmd_defs.c
@@ -88,31 +88,14 @@
 #define CMD_TAG_UI         "ui"
 #define CMD_TAG_PLUGINS    "plugins"
 
-#define CMD_MAINFUNC(func) func,
-#define CMD_NOMAINFUNC     NULL,
-#define CMD_SUBFUNCS(...)  { __VA_ARGS__, { NULL, NULL } },
-#define CMD_NOSUBFUNCS     { { NULL, NULL } },
-
-#define CMD_NOTAGS \
-    {              \
-        { NULL },
-#define CMD_TAGS(...) \
-    {                 \
-        { __VA_ARGS__, NULL },
-#define CMD_SYN(...)   { __VA_ARGS__, NULL },
-#define CMD_DESC(desc) desc,
-#define CMD_NOARGS     { { NULL, NULL } },
-#define CMD_ARGS(...)  { __VA_ARGS__, { NULL, NULL } },
-#define CMD_NOEXAMPLES \
-    {                  \
-        NULL           \
-    }                  \
-    }
-#define CMD_EXAMPLES(...) \
-    {                     \
-        __VA_ARGS__, NULL \
-    }                     \
-    }
+#define CMD_PREAMBLE(c, p, min, max, set) .cmd = c, .parser = p, .min_args = min, .max_args = max, .setting_func = set,
+#define CMD_MAINFUNC(f)                   .func = f,
+#define CMD_SUBFUNCS(...)                 .sub_funcs = { __VA_ARGS__, { NULL, NULL } },
+#define CMD_TAGS(...)                     .help.tags = { __VA_ARGS__, NULL },
+#define CMD_SYN(...)                      .help.synopsis = { __VA_ARGS__, NULL },
+#define CMD_DESC(d)                       .help.desc = d,
+#define CMD_ARGS(...)                     .help.args = { __VA_ARGS__, { NULL, NULL } },
+#define CMD_EXAMPLES(...)                 .help.examples = { __VA_ARGS__, NULL }
 
 GHashTable* commands = NULL;
 
@@ -123,12 +106,10 @@ static gboolean _cmd_has_tag(Command* pcmd, const char* const tag);
  */
 
 // clang-format off
-static struct cmd_t command_defs[] = {
-    { "/help",
-      parse_args_with_freetext, 0, 2, NULL,
-      CMD_NOSUBFUNCS
+static const struct cmd_t command_defs[] = {
+    { CMD_PREAMBLE("/help",
+      parse_args_with_freetext, 0, 2, NULL)
       CMD_MAINFUNC(cmd_help)
-      CMD_NOTAGS
       CMD_SYN(
               "/help [<area>|<command>|search_all|search_any] [<search_terms>]")
       CMD_DESC(
@@ -149,36 +130,34 @@ static struct cmd_t command_defs[] = {
               "/help who")
     },
 
-    { "/about",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/about",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_about)
-      CMD_NOTAGS
       CMD_SYN(
               "/about")
       CMD_DESC(
               "Show version and license information.")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/connect",
-      parse_args, 0, 7, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/connect",
+                   parse_args, 0, 7, NULL)
       CMD_MAINFUNC(cmd_connect)
       CMD_TAGS(
               CMD_TAG_CONNECTION)
       CMD_SYN(
               "/connect [<account>]",
-              "/connect <account> [server <server>] [port <port>] [tls force|allow|trust|legacy|disable] [auth default|legacy]")
+              "/connect <account> [server <server>] [port <port>] [tls force|allow|trust|legacy|disable] [auth default|legacy]",
+              "/connect <server>")
       CMD_DESC(
               "Login to a chat service. "
               "If no account is specified, the default is used if one is configured. "
-              "A local account is created with the JID as it's name if it doesn't already exist.")
+              "A local account is created with the JID as it's name if it doesn't already exist. "
+              "In case you want to connect to a server via SASL ANONYMOUS (c.f. XEP-0175) you can also do that.")
       CMD_ARGS(
               { "<account>", "The local account you wish to connect with, or a JID if connecting for the first time." },
               { "server <server>", "Supply a server if it is different to the domain part of your JID." },
               { "port <port>", "The port to use if different to the default (5222, or 5223 for SSL)." },
+              { "<server>", "Connect to said server in an anonymous way. (Be aware: There aren't many servers that support this.)" },
               { "tls force", "Force TLS connection, and fail if one cannot be established, this is default behaviour." },
               { "tls allow", "Use TLS for the connection if it is available." },
               { "tls trust", "Force TLS connection and trust server's certificate." },
@@ -192,54 +171,52 @@ static struct cmd_t command_defs[] = {
               "/connect odin@valhalla.edda server talk.google.com",
               "/connect freyr@vanaheimr.edda port 5678",
               "/connect me@localhost.test.org server 127.0.0.1 tls disable",
-              "/connect me@chatty server chatty.com port 5443")
+              "/connect me@chatty server chatty.com port 5443",
+              "/connect server.supporting.sasl.anonymous.example")
     },
 
-    { "/tls",
-      parse_args, 1, 3, NULL,
+    { CMD_PREAMBLE("/tls",
+                   parse_args, 1, 3, NULL)
       CMD_SUBFUNCS(
               { "certpath", cmd_tls_certpath },
               { "trust", cmd_tls_trust },
               { "trusted", cmd_tls_trusted },
               { "revoke", cmd_tls_revoke },
               { "cert", cmd_tls_cert })
-      CMD_NOMAINFUNC
-          CMD_TAGS(
-                  CMD_TAG_CONNECTION,
-                  CMD_TAG_UI)
-          CMD_SYN(
-                  "/tls allow",
-                  "/tls always",
-                  "/tls deny",
-                  "/tls cert [<fingerprint>]",
-                  "/tls trust",
-                  "/tls trusted",
-                  "/tls revoke <fingerprint>",
-                  "/tls certpath",
-                  "/tls certpath set <path>",
-                  "/tls certpath clear",
-                  "/tls certpath default")
-          CMD_DESC(
-                  "Handle TLS certificates. ")
-          CMD_ARGS(
-                  { "allow", "Allow connection to continue with TLS certificate." },
-                  { "always", "Always allow connections with TLS certificate." },
-                  { "deny", "Abort connection." },
-                  { "cert", "Show the current TLS certificate." },
-                  { "cert <fingerprint>", "Show details of trusted certificate." },
-                  { "trust", "Add the current TLS certificate to manually trusted certificates." },
-                  { "trusted", "List summary of manually trusted certificates (with '/tls always' or '/tls trust')." },
-                  { "revoke <fingerprint>", "Remove a manually trusted certificate." },
-                  { "certpath", "Show the trusted certificate path." },
-                  { "certpath set <path>", "Specify filesystem path containing trusted certificates." },
-                  { "certpath clear", "Clear the trusted certificate path." },
-                  { "certpath default", "Use default system certificate path, if it can be found." })
-      CMD_NOEXAMPLES
-    },
-
-    { "/disconnect",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+      CMD_TAGS(
+              CMD_TAG_CONNECTION,
+              CMD_TAG_UI)
+      CMD_SYN(
+              "/tls allow",
+              "/tls always",
+              "/tls deny",
+              "/tls cert [<fingerprint>]",
+              "/tls trust",
+              "/tls trusted",
+              "/tls revoke <fingerprint>",
+              "/tls certpath",
+              "/tls certpath set <path>",
+              "/tls certpath clear",
+              "/tls certpath default")
+      CMD_DESC(
+              "Handle TLS certificates. ")
+      CMD_ARGS(
+              { "allow", "Allow connection to continue with TLS certificate." },
+              { "always", "Always allow connections with TLS certificate." },
+              { "deny", "Abort connection." },
+              { "cert", "Show the current TLS certificate." },
+              { "cert <fingerprint>", "Show details of trusted certificate." },
+              { "trust", "Add the current TLS certificate to manually trusted certificates." },
+              { "trusted", "List summary of manually trusted certificates (with '/tls always' or '/tls trust')." },
+              { "revoke <fingerprint>", "Remove a manually trusted certificate." },
+              { "certpath", "Show the trusted certificate path." },
+              { "certpath set <path>", "Specify filesystem path containing trusted certificates." },
+              { "certpath clear", "Clear the trusted certificate path." },
+              { "certpath default", "Use default system certificate path, if it can be found." })
+    },
+
+    { CMD_PREAMBLE("/disconnect",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_disconnect)
       CMD_TAGS(
               CMD_TAG_CONNECTION)
@@ -247,13 +224,10 @@ static struct cmd_t command_defs[] = {
               "/disconnect")
       CMD_DESC(
               "Disconnect from the current chat service.")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/msg",
-      parse_args_with_freetext, 1, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/msg",
+                   parse_args_with_freetext, 1, 2, NULL)
       CMD_MAINFUNC(cmd_msg)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -276,8 +250,8 @@ static struct cmd_t command_defs[] = {
               "/msg \"My Friend\" Hi, how are you?")
     },
 
-    { "/roster",
-      parse_args_with_freetext, 0, 4, NULL,
+    { CMD_PREAMBLE("/roster",
+                   parse_args_with_freetext, 0, 4, NULL)
       CMD_SUBFUNCS(
               { "group", cmd_group })
       CMD_MAINFUNC(cmd_roster)
@@ -419,9 +393,8 @@ static struct cmd_t command_defs[] = {
               "/roster group remove colleagues boss@work.com")
     },
 
-    { "/blocked",
-      parse_args_with_freetext, 0, 3, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/blocked",
+                   parse_args_with_freetext, 0, 3, NULL)
       CMD_MAINFUNC(cmd_blocked)
       CMD_TAGS(
               CMD_TAG_ROSTER,
@@ -447,9 +420,8 @@ static struct cmd_t command_defs[] = {
               "/blocked add profanity@rooms.dismail.de/spammy-user")
     },
 
-    { "/info",
-      parse_args, 0, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/info",
+                   parse_args, 0, 1, NULL)
       CMD_MAINFUNC(cmd_info)
       CMD_TAGS(
               CMD_TAG_ROSTER,
@@ -470,9 +442,8 @@ static struct cmd_t command_defs[] = {
               "/info heimdall")
     },
 
-    { "/caps",
-      parse_args, 0, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/caps",
+                   parse_args, 0, 1, NULL)
       CMD_MAINFUNC(cmd_caps)
       CMD_TAGS(
               CMD_TAG_DISCOVERY,
@@ -493,9 +464,8 @@ static struct cmd_t command_defs[] = {
               "/caps aegir")
     },
 
-    { "/software",
-      parse_args, 0, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/software",
+                   parse_args, 0, 1, NULL)
       CMD_MAINFUNC(cmd_software)
       CMD_TAGS(
               CMD_TAG_DISCOVERY,
@@ -517,12 +487,11 @@ static struct cmd_t command_defs[] = {
               "/software thor")
     },
 
-    { "/status",
-      parse_args, 2, 3, NULL,
+    { CMD_PREAMBLE("/status",
+                   parse_args, 2, 3, NULL)
       CMD_SUBFUNCS(
               { "get", cmd_status_get },
               { "set", cmd_status_set })
-      CMD_NOMAINFUNC
       CMD_TAGS(
               CMD_TAG_CHAT,
               CMD_TAG_GROUPCHAT)
@@ -543,9 +512,8 @@ static struct cmd_t command_defs[] = {
               "/status set online")
     },
 
-    { "/resource",
-      parse_args, 1, 2, &cons_resource_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/resource",
+                   parse_args, 1, 2, &cons_resource_setting)
       CMD_MAINFUNC(cmd_resource)
       CMD_TAGS(
               CMD_TAG_CHAT,
@@ -562,12 +530,10 @@ static struct cmd_t command_defs[] = {
               { "off", "Let the server choose which resource to route messages to." },
               { "title on|off", "Show or hide the current resource in the titlebar." },
               { "message on|off", "Show or hide the resource when showing an incoming message." })
-      CMD_NOEXAMPLES
     },
 
-    { "/join",
-      parse_args, 0, 5, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/join",
+                   parse_args, 0, 5, NULL)
       CMD_MAINFUNC(cmd_join)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -594,9 +560,8 @@ static struct cmd_t command_defs[] = {
               "/join mychannel")
     },
 
-    { "/invite",
-      parse_args_with_freetext, 1, 3, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/invite",
+                   parse_args_with_freetext, 1, 3, NULL)
       CMD_MAINFUNC(cmd_invite)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -619,9 +584,8 @@ static struct cmd_t command_defs[] = {
               "/invite list")
     },
 
-    { "/room",
-      parse_args, 1, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/room",
+                   parse_args, 1, 1, NULL)
       CMD_MAINFUNC(cmd_room)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -633,12 +597,10 @@ static struct cmd_t command_defs[] = {
               { "accept", "Accept default room configuration." },
               { "destroy", "Reject default room configuration, and destroy the room." },
               { "config", "Edit room configuration." })
-      CMD_NOEXAMPLES
     },
 
-    { "/kick",
-      parse_args_with_freetext, 1, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/kick",
+                   parse_args_with_freetext, 1, 2, NULL)
       CMD_MAINFUNC(cmd_kick)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -649,11 +611,10 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "<nick>", "Nickname of the occupant to kick from the room." },
               { "<reason>", "Optional reason for kicking the occupant." })
-      CMD_NOEXAMPLES },
+    },
 
-    { "/ban",
-      parse_args_with_freetext, 1, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/ban",
+                   parse_args_with_freetext, 1, 2, NULL)
       CMD_MAINFUNC(cmd_ban)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -664,12 +625,10 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "<jid>", "Bare JID of the user to ban from the room." },
               { "<reason>", "Optional reason for banning the user." })
-      CMD_NOEXAMPLES
     },
 
-    { "/subject",
-      parse_args_with_freetext, 0, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/subject",
+                   parse_args_with_freetext, 0, 2, NULL)
       CMD_MAINFUNC(cmd_subject)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -689,12 +648,10 @@ static struct cmd_t command_defs[] = {
               { "prepend <text>", "Prepend text to the current room subject, use double quotes if a trailing space is needed." },
               { "append <text>", "Append text to the current room subject, use double quotes if a preceding space is needed." },
               { "clear", "Clear the room subject." })
-      CMD_NOEXAMPLES
     },
 
-    { "/affiliation",
-      parse_args_with_freetext, 1, 4, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/affiliation",
+                   parse_args_with_freetext, 1, 4, NULL)
       CMD_MAINFUNC(cmd_affiliation)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -711,12 +668,10 @@ static struct cmd_t command_defs[] = {
               { "list [<affiliation>]", "List all users with the specified affiliation, or all if none specified." },
               { "request", "Request voice."},
               { "register", "Register your nickname with the MUC."})
-      CMD_NOEXAMPLES
     },
 
-    { "/role",
-      parse_args_with_freetext, 1, 4, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/role",
+                   parse_args_with_freetext, 1, 4, NULL)
       CMD_MAINFUNC(cmd_role)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -729,12 +684,10 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "set <role> <nick> [<reason>]", "Set the role of occupant with nick, with an optional reason." },
               { "list [<role>]", "List all occupants with the specified role, or all if none specified." })
-      CMD_NOEXAMPLES
     },
 
-    { "/occupants",
-      parse_args, 1, 3, cons_occupants_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/occupants",
+                   parse_args, 1, 3, cons_occupants_setting)
       CMD_MAINFUNC(cmd_occupants)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT,
@@ -769,12 +722,10 @@ static struct cmd_t command_defs[] = {
               { "header char <char>", "Prefix occupants headers with specified character." },
               { "header char none", "Remove occupants header character prefix." },
               { "wrap on|off", "Enable or disable line wrapping in occupants panel." })
-      CMD_NOEXAMPLES
     },
 
-    { "/form",
-      parse_args, 1, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/form",
+                   parse_args, 1, 2, NULL)
       CMD_MAINFUNC(cmd_form)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -790,12 +741,10 @@ static struct cmd_t command_defs[] = {
               { "submit", "Submit the current form." },
               { "cancel", "Cancel changes to the current form." },
               { "help [<tag>]", "Display help for form, or a specific field." })
-      CMD_NOEXAMPLES
     },
 
-    { "/rooms",
-      parse_args, 0, 4, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/rooms",
+                   parse_args, 0, 4, NULL)
       CMD_MAINFUNC(cmd_rooms)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -821,8 +770,8 @@ static struct cmd_t command_defs[] = {
               "/rooms service conference.jabber.org filter \"News Room\"")
     },
 
-    { "/bookmark",
-      parse_args, 0, 8, NULL,
+    { CMD_PREAMBLE("/bookmark",
+                   parse_args, 0, 8, NULL)
       CMD_SUBFUNCS(
               { "ignore", cmd_bookmark_ignore })
       CMD_MAINFUNC(cmd_bookmark)
@@ -866,9 +815,8 @@ static struct cmd_t command_defs[] = {
               "/bookmark remove room@example.com")
     },
 
-    { "/disco",
-      parse_args, 1, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/disco",
+                   parse_args, 1, 2, NULL)
       CMD_MAINFUNC(cmd_disco)
       CMD_TAGS(
               CMD_TAG_DISCOVERY)
@@ -889,9 +837,8 @@ static struct cmd_t command_defs[] = {
               "/disco info odin@valhalla.edda/laptop")
     },
 
-    { "/sendfile",
-      parse_args_with_freetext, 1, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/sendfile",
+                   parse_args_with_freetext, 1, 1, NULL)
       CMD_MAINFUNC(cmd_sendfile)
       CMD_TAGS(
               CMD_TAG_CHAT,
@@ -907,9 +854,8 @@ static struct cmd_t command_defs[] = {
               "/sendfile ~/images/sweet_cat.jpg")
     },
 
-    { "/lastactivity",
-      parse_args, 1, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/lastactivity",
+                   parse_args, 1, 2, NULL)
       CMD_MAINFUNC(cmd_lastactivity)
       CMD_TAGS(
               CMD_TAG_PRESENCE)
@@ -929,9 +875,8 @@ static struct cmd_t command_defs[] = {
               "/lastactivity get someserver.com")
     },
 
-    { "/nick",
-      parse_args_with_freetext, 1, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/nick",
+                   parse_args_with_freetext, 1, 1, NULL)
       CMD_MAINFUNC(cmd_nick)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT)
@@ -941,12 +886,10 @@ static struct cmd_t command_defs[] = {
               "Change your nickname in the current chat room.")
       CMD_ARGS(
               { "<nickname>", "Your new nickname." })
-      CMD_NOEXAMPLES
     },
 
-    { "/win",
-      parse_args, 1, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/win",
+                   parse_args, 1, 1, NULL)
       CMD_MAINFUNC(cmd_win)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -980,8 +923,8 @@ static struct cmd_t command_defs[] = {
               "/win wikipedia")
     },
 
-    { "/wins",
-      parse_args, 0, 3, NULL,
+    { CMD_PREAMBLE("/wins",
+                   parse_args, 0, 3, NULL)
       CMD_SUBFUNCS(
               { "unread", cmd_wins_unread },
               { "attention", cmd_wins_attention },
@@ -1004,12 +947,10 @@ static struct cmd_t command_defs[] = {
               { "attention", "List windows that have been marked with the attention flag (alt+v). You can toggle between marked windows with alt+m." },
               { "prune", "Close all windows with no unread messages." },
               { "swap <source> <target>", "Swap windows, target may be an empty position." })
-      CMD_NOEXAMPLES
     },
 
-    { "/sub",
-      parse_args, 1, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/sub",
+                   parse_args, 1, 2, NULL)
       CMD_MAINFUNC(cmd_sub)
       CMD_TAGS(
               CMD_TAG_ROSTER)
@@ -1037,9 +978,8 @@ static struct cmd_t command_defs[] = {
               "/sub sent")
     },
 
-    { "/who",
-      parse_args, 0, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/who",
+                   parse_args, 0, 2, NULL)
       CMD_MAINFUNC(cmd_who)
       CMD_TAGS(
               CMD_TAG_CHAT,
@@ -1070,9 +1010,8 @@ static struct cmd_t command_defs[] = {
               "/who admin")
     },
 
-    { "/close",
-      parse_args, 0, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/close",
+                   parse_args, 0, 1, NULL)
       CMD_MAINFUNC(cmd_close)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1097,12 +1036,10 @@ static struct cmd_t command_defs[] = {
               { "xmlconsole", "Close the XML Console window if open." },
               { "all", "Close all windows." },
               { "read", "Close all windows that have no unread messages." })
-      CMD_NOEXAMPLES
     },
 
-    { "/clear",
-      parse_args, 0, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/clear",
+                   parse_args, 0, 2, NULL)
       CMD_MAINFUNC(cmd_clear)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1120,22 +1057,17 @@ static struct cmd_t command_defs[] = {
               "/clear persist_history on")
     },
 
-    { "/quit",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/quit",
+                   parse_args, 0, 0, NULL)
        CMD_MAINFUNC(cmd_quit)
-       CMD_NOTAGS
-       CMD_SYN(
+        CMD_SYN(
                "/quit")
        CMD_DESC(
                "Logout of any current session, and quit Profanity.")
-       CMD_NOARGS
-       CMD_NOEXAMPLES
     },
 
-    { "/privileges",
-      parse_args, 1, 1, &cons_privileges_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/privileges",
+                   parse_args, 1, 1, &cons_privileges_setting)
       CMD_MAINFUNC(cmd_privileges)
       CMD_TAGS(
               CMD_TAG_GROUPCHAT,
@@ -1146,12 +1078,10 @@ static struct cmd_t command_defs[] = {
               "Group occupants panel by role, and show role information in chat rooms.")
       CMD_ARGS(
               { "on|off", "Enable or disable privilege information." })
-      CMD_NOEXAMPLES
     },
 
-    { "/charset",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/charset",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_charset)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1159,13 +1089,10 @@ static struct cmd_t command_defs[] = {
               "/charset")
       CMD_DESC(
               "Display information about the current character set supported by the terminal. ")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/beep",
-      parse_args, 1, 1, &cons_beep_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/beep",
+                   parse_args, 1, 1, &cons_beep_setting)
       CMD_MAINFUNC(cmd_beep)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1177,12 +1104,10 @@ static struct cmd_t command_defs[] = {
               "If the terminal does not support sounds, it may attempt to flash the screen instead.")
       CMD_ARGS(
               { "on|off", "Enable or disable terminal bell." })
-      CMD_NOEXAMPLES
     },
 
-    { "/console",
-      parse_args, 2, 2, &cons_console_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/console",
+                   parse_args, 2, 2, &cons_console_setting)
       CMD_MAINFUNC(cmd_console)
       CMD_TAGS(
               CMD_TAG_UI,
@@ -1206,12 +1131,10 @@ static struct cmd_t command_defs[] = {
               { "private all", "Indicate all new private room messages in the console." },
               { "private first", "Indicate only the first private room message in the console." },
               { "private none", "Do not show any new private room messages in the console window." })
-      CMD_NOEXAMPLES
     },
 
-    { "/presence",
-      parse_args, 2, 2, &cons_presence_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/presence",
+                   parse_args, 2, 2, &cons_presence_setting)
       CMD_MAINFUNC(cmd_presence)
       CMD_TAGS(
               CMD_TAG_UI,
@@ -1242,9 +1165,8 @@ static struct cmd_t command_defs[] = {
               "/presence room all")
     },
 
-    { "/wrap",
-      parse_args, 1, 1, &cons_wrap_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/wrap",
+                   parse_args, 1, 1, &cons_wrap_setting)
       CMD_MAINFUNC(cmd_wrap)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1254,12 +1176,10 @@ static struct cmd_t command_defs[] = {
               "Word wrapping.")
       CMD_ARGS(
               { "on|off", "Enable or disable word wrapping in the main window." })
-      CMD_NOEXAMPLES
     },
 
-    { "/time",
-      parse_args, 1, 3, &cons_time_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/time",
+                   parse_args, 1, 3, &cons_time_setting)
       CMD_MAINFUNC(cmd_time)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1304,9 +1224,8 @@ static struct cmd_t command_defs[] = {
               "/time all set \"%d-%m-%y %H:%M:%S\"")
     },
 
-    { "/inpblock",
-      parse_args, 2, 2, &cons_inpblock_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/inpblock",
+                   parse_args, 2, 2, &cons_inpblock_setting)
       CMD_MAINFUNC(cmd_inpblock)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1318,11 +1237,11 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "timeout <millis>", "Time to wait (1-1000) in milliseconds before reading input from the terminal buffer, default: 1000." },
               { "dynamic on|off", "Start with 0 millis and dynamically increase up to timeout when no activity, default: on." })
-      CMD_NOEXAMPLES },
+    },
 
 
-    { "/titlebar",
-      parse_args, 1, 2, &cons_titlebar_setting,
+    { CMD_PREAMBLE("/titlebar",
+                   parse_args, 1, 2, &cons_titlebar_setting)
       CMD_SUBFUNCS(
               { "show", cmd_titlebar_show_hide },
               { "hide", cmd_titlebar_show_hide })
@@ -1349,9 +1268,8 @@ static struct cmd_t command_defs[] = {
               "/titlebar hide encwarn")
     },
 
-    { "/mainwin",
-      parse_args, 1, 1, &cons_winpos_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/mainwin",
+                   parse_args, 1, 1, &cons_winpos_setting)
       CMD_MAINFUNC(cmd_mainwin)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1363,12 +1281,10 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "up", "Move the main window up the screen." },
               { "down", "Move the main window down the screen." })
-      CMD_NOEXAMPLES
     },
 
-    { "/statusbar",
-      parse_args, 1, 2, &cons_statusbar_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/statusbar",
+                   parse_args, 1, 2, &cons_statusbar_setting)
       CMD_MAINFUNC(cmd_statusbar)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1405,9 +1321,8 @@ static struct cmd_t command_defs[] = {
               "/statusbar hide name")
     },
 
-    { "/inputwin",
-      parse_args, 1, 1, &cons_winpos_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/inputwin",
+                   parse_args, 1, 1, &cons_winpos_setting)
       CMD_MAINFUNC(cmd_inputwin)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1419,12 +1334,10 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "up", "Move the input window up the screen." },
               { "down", "Move the input window down the screen." })
-      CMD_NOEXAMPLES
     },
 
-    { "/notify",
-      parse_args_with_freetext, 0, 4, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/notify",
+                   parse_args_with_freetext, 0, 4, NULL)
       CMD_MAINFUNC(cmd_notify)
       CMD_TAGS(
               CMD_TAG_UI,
@@ -1497,9 +1410,8 @@ static struct cmd_t command_defs[] = {
               "/notify invite on")
     },
 
-    { "/flash",
-      parse_args, 1, 1, &cons_flash_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/flash",
+                   parse_args, 1, 1, &cons_flash_setting)
       CMD_MAINFUNC(cmd_flash)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1510,12 +1422,10 @@ static struct cmd_t command_defs[] = {
               "If the terminal doesn't support flashing, it may attempt to beep.")
       CMD_ARGS(
               { "on|off", "Enable or disable terminal flash." })
-      CMD_NOEXAMPLES
     },
 
-    { "/tray",
-      parse_args, 1, 2, &cons_tray_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/tray",
+                   parse_args, 1, 2, &cons_tray_setting)
       CMD_MAINFUNC(cmd_tray)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1529,12 +1439,10 @@ static struct cmd_t command_defs[] = {
               { "on|off", "Show tray icon." },
               { "read on|off", "Show tray icon when no unread messages." },
               { "timer <seconds>", "Set tray icon timer, seconds must be between 1-10." })
-      CMD_NOEXAMPLES
     },
 
-    { "/intype",
-      parse_args, 2, 2, &cons_intype_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/intype",
+                   parse_args, 2, 2, &cons_intype_setting)
       CMD_MAINFUNC(cmd_intype)
       CMD_TAGS(
               CMD_TAG_UI,
@@ -1546,12 +1454,10 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "titlebar on|off", "Enable or disable contact typing messages notification in titlebar." },
               { "console on|off", "Enable or disable contact typing messages notification in console window." })
-      CMD_NOEXAMPLES
     },
 
-    { "/splash",
-      parse_args, 1, 1, &cons_splash_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/splash",
+                   parse_args, 1, 1, &cons_splash_setting)
       CMD_MAINFUNC(cmd_splash)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1561,12 +1467,10 @@ static struct cmd_t command_defs[] = {
               "Switch on or off the ascii logo on start up and when the /about command is called.")
       CMD_ARGS(
               { "on|off", "Enable or disable splash logo." })
-      CMD_NOEXAMPLES
     },
 
-    { "/autoconnect",
-      parse_args, 1, 2, &cons_autoconnect_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/autoconnect",
+                   parse_args, 1, 2, &cons_autoconnect_setting)
       CMD_MAINFUNC(cmd_autoconnect)
       CMD_TAGS(
               CMD_TAG_CONNECTION)
@@ -1584,8 +1488,8 @@ static struct cmd_t command_defs[] = {
               "/autoconnect off")
     },
 
-    { "/vcard",
-      parse_args, 0, 7, NULL,
+    { CMD_PREAMBLE("/vcard",
+                   parse_args, 0, 7, NULL)
       CMD_SUBFUNCS(
               {"add", cmd_vcard_add},
               {"remove", cmd_vcard_remove},
@@ -1699,12 +1603,10 @@ static struct cmd_t command_defs[] = {
               { "remove <index>", "Remove a element in your vCard by index" },
               { "refresh", "Refreshes the local copy of the current account's vCard (undoes all your unpublished modifications)" },
               { "save", "Save changes to the server" })
-      CMD_NOEXAMPLES
     },
 
-    { "/vercheck",
-      parse_args, 0, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/vercheck",
+                   parse_args, 0, 1, NULL)
       CMD_MAINFUNC(cmd_vercheck)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1714,12 +1616,10 @@ static struct cmd_t command_defs[] = {
               "Check for new versions when Profanity starts, and when the /about command is run.")
       CMD_ARGS(
               { "on|off", "Enable or disable the version check." })
-      CMD_NOEXAMPLES
     },
 
-    { "/wintitle",
-      parse_args, 2, 2, &cons_wintitle_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/wintitle",
+                   parse_args, 2, 2, &cons_wintitle_setting)
       CMD_MAINFUNC(cmd_wintitle)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -1731,14 +1631,11 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "show on|off", "Show current logged in user, and unread messages as the window title." },
               { "goodbye on|off", "Show a message in the title when exiting profanity." })
-      CMD_NOEXAMPLES
     },
 
-    { "/alias",
-      parse_args_with_freetext, 1, 3, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/alias",
+                   parse_args_with_freetext, 1, 3, NULL)
       CMD_MAINFUNC(cmd_alias)
-      CMD_NOTAGS
       CMD_SYN(
               "/alias list",
               "/alias add <name> <value>",
@@ -1757,9 +1654,8 @@ static struct cmd_t command_defs[] = {
               "/alias list")
     },
 
-    { "/logging",
-      parse_args, 2, 3, &cons_logging_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/logging",
+                   parse_args, 2, 3, &cons_logging_setting)
       CMD_MAINFUNC(cmd_logging)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -1778,9 +1674,8 @@ static struct cmd_t command_defs[] = {
               "/logging group off")
     },
 
-    { "/states",
-      parse_args, 1, 1, &cons_states_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/states",
+                   parse_args, 1, 1, &cons_states_setting)
       CMD_MAINFUNC(cmd_states)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -1790,11 +1685,10 @@ static struct cmd_t command_defs[] = {
               "Send chat state notifications to recipient during chat sessions, such as typing, paused, active, gone.")
       CMD_ARGS(
               { "on|off", "Enable or disable sending of chat state notifications." })
-      CMD_NOEXAMPLES },
+    },
 
-    { "/pgp",
-      parse_args, 1, 3, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/pgp",
+                   parse_args, 1, 3, NULL)
       CMD_MAINFUNC(cmd_pgp)
       CMD_TAGS(
               CMD_TAG_CHAT,
@@ -1833,8 +1727,8 @@ static struct cmd_t command_defs[] = {
 
 // XEP-0373: OpenPGP for XMPP
 #ifdef HAVE_LIBGPGME
-    { "/ox",
-      parse_args, 1, 3, NULL,
+    { CMD_PREAMBLE("/ox",
+                   parse_args, 1, 3, NULL)
       CMD_SUBFUNCS(
               { "log", cmd_ox_log })
       CMD_MAINFUNC(cmd_ox)
@@ -1875,8 +1769,8 @@ static struct cmd_t command_defs[] = {
     },
 #endif // HAVE_LIBGPGME
 
-    { "/otr",
-      parse_args, 1, 3, NULL,
+    { CMD_PREAMBLE("/otr",
+                   parse_args, 1, 3, NULL)
       CMD_SUBFUNCS(
               { "char", cmd_otr_char },
               { "log", cmd_otr_log },
@@ -1893,7 +1787,6 @@ static struct cmd_t command_defs[] = {
               { "question", cmd_otr_question },
               { "answer", cmd_otr_answer },
               { "sendfile", cmd_otr_sendfile })
-      CMD_NOMAINFUNC
       CMD_TAGS(
               CMD_TAG_CHAT,
               CMD_TAG_UI)
@@ -1947,9 +1840,8 @@ static struct cmd_t command_defs[] = {
               "/otr char *")
     },
 
-    { "/outtype",
-      parse_args, 1, 1, &cons_outtype_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/outtype",
+                   parse_args, 1, 1, &cons_outtype_setting)
       CMD_MAINFUNC(cmd_outtype)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -1959,12 +1851,10 @@ static struct cmd_t command_defs[] = {
               "Send typing notifications, chat states (/states) will be enabled if this setting is enabled.")
       CMD_ARGS(
               { "on|off", "Enable or disable sending typing notifications." })
-      CMD_NOEXAMPLES
     },
 
-    { "/gone",
-      parse_args, 1, 1, &cons_gone_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/gone",
+                   parse_args, 1, 1, &cons_gone_setting)
       CMD_MAINFUNC(cmd_gone)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -1975,12 +1865,10 @@ static struct cmd_t command_defs[] = {
               "Chat states (/states) will be enabled if this setting is set.")
       CMD_ARGS(
               { "<minutes>", "Number of minutes of inactivity before sending the 'gone' state, a value of 0 will disable sending this state." })
-      CMD_NOEXAMPLES
     },
 
-    { "/history",
-      parse_args, 1, 1, &cons_history_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/history",
+                   parse_args, 1, 1, &cons_history_setting)
       CMD_MAINFUNC(cmd_history)
       CMD_TAGS(
               CMD_TAG_UI,
@@ -1992,14 +1880,11 @@ static struct cmd_t command_defs[] = {
               "When history is enabled, previous messages are shown in chat windows.")
       CMD_ARGS(
               { "on|off", "Enable or disable showing chat history." })
-      CMD_NOEXAMPLES
     },
 
-    { "/log",
-      parse_args, 1, 2, &cons_log_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/log",
+                   parse_args, 1, 2, &cons_log_setting)
       CMD_MAINFUNC(cmd_log)
-      CMD_NOTAGS
       CMD_SYN(
               "/log where",
               "/log rotate on|off",
@@ -2013,13 +1898,11 @@ static struct cmd_t command_defs[] = {
               { "rotate on|off", "Rotate log, default on. Does not take effect if you specified a filename yourself when starting Profanity." },
               { "maxsize <bytes>", "With rotate enabled, specifies the max log size, defaults to 10485760 (10MB)." },
               { "shared on|off", "Share logs between all instances, default: on. When off, the process id will be included in the log filename. Does not take effect if you specified a filename yourself when starting Profanity." },
-              {"level INFO|DEBUG|WARN|EFFOR", "Set the log level. Default is INFO. Only works with default log file, not with user provided log file during startup via -f." })
-      CMD_NOEXAMPLES
+              {"level INFO|DEBUG|WARN|ERROR", "Set the log level. Default is INFO. Only works with default log file, not with user provided log file during startup via -f." })
     },
 
-    { "/carbons",
-      parse_args, 1, 1, &cons_carbons_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/carbons",
+                   parse_args, 1, 1, &cons_carbons_setting)
       CMD_MAINFUNC(cmd_carbons)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -2030,12 +1913,10 @@ static struct cmd_t command_defs[] = {
               "Message carbons ensure that both sides of all conversations are shared with all the user's clients that implement this protocol.")
       CMD_ARGS(
               { "on|off", "Enable or disable message carbons." })
-      CMD_NOEXAMPLES
     },
 
-    { "/receipts",
-      parse_args, 2, 2, &cons_receipts_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/receipts",
+                   parse_args, 2, 2, &cons_receipts_setting)
       CMD_MAINFUNC(cmd_receipts)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -2047,27 +1928,25 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "request on|off", "Whether or not to request a receipt upon sending a message." },
               { "send on|off", "Whether or not to send a receipt if one has been requested with a received message." })
-      CMD_NOEXAMPLES
     },
 
-    { "/reconnect",
-      parse_args, 1, 1, &cons_reconnect_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/reconnect",
+                   parse_args, 1, 1, &cons_reconnect_setting)
       CMD_MAINFUNC(cmd_reconnect)
       CMD_TAGS(
               CMD_TAG_CONNECTION)
       CMD_SYN(
-              "/reconnect <seconds>")
+              "/reconnect <seconds>",
+              "/reconnect now")
       CMD_DESC(
-              "Set the reconnect attempt interval for when the connection is lost.")
+              "Set the reconnect attempt interval for when the connection is lost or immediately trigger a reconnect.")
       CMD_ARGS(
-              { "<seconds>", "Number of seconds before attempting to reconnect, a value of 0 disables reconnect." })
-      CMD_NOEXAMPLES
+              { "<seconds>", "Number of seconds before attempting to reconnect, a value of 0 disables reconnect." },
+              { "now", "Immediately trigger a reconnect." })
     },
 
-    { "/autoping",
-      parse_args, 2, 2, &cons_autoping_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/autoping",
+                   parse_args, 2, 2, &cons_autoping_setting)
       CMD_MAINFUNC(cmd_autoping)
       CMD_TAGS(
               CMD_TAG_CONNECTION)
@@ -2079,12 +1958,10 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "set <seconds>", "Number of seconds between sending pings, a value of 0 disables autoping." },
               { "timeout <seconds>", "Seconds to wait for autoping responses, after which the connection is considered broken." })
-      CMD_NOEXAMPLES
     },
 
-    { "/ping",
-      parse_args, 0, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/ping",
+                   parse_args, 0, 1, NULL)
       CMD_MAINFUNC(cmd_ping)
       CMD_TAGS(
               CMD_TAG_CONNECTION)
@@ -2095,12 +1972,10 @@ static struct cmd_t command_defs[] = {
               "If no JID is supplied, your chat server will be pinged.")
       CMD_ARGS(
               { "<jid>", "The Jabber ID to send the ping request to." })
-      CMD_NOEXAMPLES
     },
 
-    { "/autoaway",
-      parse_args_with_freetext, 2, 3, &cons_autoaway_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/autoaway",
+                   parse_args_with_freetext, 2, 3, &cons_autoaway_setting)
       CMD_MAINFUNC(cmd_autoaway)
       CMD_TAGS(
               CMD_TAG_PRESENCE)
@@ -2131,9 +2006,8 @@ static struct cmd_t command_defs[] = {
               "/autoaway check off")
     },
 
-    { "/priority",
-      parse_args, 1, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/priority",
+                   parse_args, 1, 1, NULL)
       CMD_MAINFUNC(cmd_priority)
       CMD_TAGS(
               CMD_TAG_PRESENCE)
@@ -2144,11 +2018,10 @@ static struct cmd_t command_defs[] = {
               "See the /account command for specific priority settings per presence status.")
       CMD_ARGS(
               { "<priority>", "Number between -128 and 127, default: 0." })
-      CMD_NOEXAMPLES
     },
 
-    { "/account",
-      parse_args, 0, 4, NULL,
+    { CMD_PREAMBLE("/account",
+                   parse_args, 0, 4, NULL)
       CMD_SUBFUNCS(
               { "list", cmd_account_list },
               { "show", cmd_account_show },
@@ -2260,8 +2133,8 @@ static struct cmd_t command_defs[] = {
               "/account clear me pgpkeyid")
     },
 
-    { "/plugins",
-      parse_args, 0, 3, NULL,
+    { CMD_PREAMBLE("/plugins",
+                   parse_args, 0, 3, NULL)
       CMD_SUBFUNCS(
               { "install", cmd_plugins_install },
               { "uninstall", cmd_plugins_uninstall },
@@ -2271,7 +2144,6 @@ static struct cmd_t command_defs[] = {
               { "reload", cmd_plugins_reload },
               { "python_version", cmd_plugins_python_version })
       CMD_MAINFUNC(cmd_plugins)
-      CMD_NOTAGS
       CMD_SYN(
               "/plugins",
               "/plugins install [<path>]",
@@ -2301,11 +2173,9 @@ static struct cmd_t command_defs[] = {
               "/plugins reload wikipedia.py")
     },
 
-    { "/prefs",
-      parse_args, 0, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/prefs",
+                   parse_args, 0, 1, NULL)
       CMD_MAINFUNC(cmd_prefs)
-      CMD_NOTAGS
       CMD_SYN(
               "/prefs [ui|desktop|chat|log|conn|presence|otr|pgp|omemo]")
       CMD_DESC(
@@ -2321,12 +2191,10 @@ static struct cmd_t command_defs[] = {
               { "otr", "Off The Record preferences." },
               { "pgp", "OpenPGP preferences." },
               { "omemo", "OMEMO preferences." })
-      CMD_NOEXAMPLES
     },
 
-    { "/theme",
-      parse_args, 1, 2, &cons_theme_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/theme",
+                   parse_args, 1, 2, &cons_theme_setting)
       CMD_MAINFUNC(cmd_theme)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -2349,9 +2217,8 @@ static struct cmd_t command_defs[] = {
               "/theme load forest")
     },
 
-    { "/xmlconsole",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/xmlconsole",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_xmlconsole)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -2359,15 +2226,11 @@ static struct cmd_t command_defs[] = {
               "/xmlconsole")
       CMD_DESC(
               "Open the XML console to view incoming and outgoing XMPP traffic.")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/script",
-      parse_args, 1, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/script",
+                   parse_args, 1, 2, NULL)
       CMD_MAINFUNC(cmd_script)
-      CMD_NOTAGS
       CMD_SYN(
               "/script run <script>",
               "/script list",
@@ -2385,11 +2248,9 @@ static struct cmd_t command_defs[] = {
               "/script show somescript")
     },
 
-    { "/export",
-      parse_args, 1, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/export",
+                   parse_args, 1, 1, NULL)
       CMD_MAINFUNC(cmd_export)
-      CMD_NOTAGS
       CMD_SYN(
               "/export <filepath>")
       CMD_DESC(
@@ -2401,13 +2262,11 @@ static struct cmd_t command_defs[] = {
               "/export ~/contacts.csv")
     },
 
-    { "/cmd",
-      parse_args, 1, 3, NULL,
+    { CMD_PREAMBLE("/cmd",
+                   parse_args, 1, 3, NULL)
       CMD_SUBFUNCS(
               { "list", cmd_command_list },
               { "exec", cmd_command_exec })
-      CMD_NOMAINFUNC
-      CMD_NOTAGS
       CMD_SYN(
               "/cmd list [<jid>]",
               "/cmd exec <command> [<jid>]")
@@ -2421,8 +2280,8 @@ static struct cmd_t command_defs[] = {
               "/cmd exec ping")
     },
 
-    { "/omemo",
-        parse_args, 1, 3, NULL,
+    { CMD_PREAMBLE("/omemo",
+                   parse_args, 1, 3, NULL)
         CMD_SUBFUNCS(
             { "gen", cmd_omemo_gen },
             { "log", cmd_omemo_log },
@@ -2436,7 +2295,6 @@ static struct cmd_t command_defs[] = {
             { "policy", cmd_omemo_policy },
             { "clear_device_list", cmd_omemo_clear_device_list },
             { "qrcode", cmd_omemo_qrcode })
-        CMD_NOMAINFUNC
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_UI)
@@ -2478,48 +2336,35 @@ static struct cmd_t command_defs[] = {
             "/omemo char *")
     },
 
-    { "/save",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/save",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_save)
-      CMD_NOTAGS
       CMD_SYN(
               "/save")
       CMD_DESC(
               "Save preferences to configuration file.")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/reload",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/reload",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_reload)
-      CMD_NOTAGS
       CMD_SYN(
               "/reload")
       CMD_DESC(
               "Reload preferences from configuration file.")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/paste",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/paste",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_paste)
-      CMD_NOTAGS
       CMD_SYN(
               "/paste")
       CMD_DESC(
               "Paste clipboard.")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/color",
-      parse_args, 1, 2, &cons_color_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/color",
+                   parse_args, 1, 2, &cons_color_setting)
       CMD_MAINFUNC(cmd_color)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -2539,9 +2384,8 @@ static struct cmd_t command_defs[] = {
               "/color own off")
     },
 
-    { "/stamp",
-      parse_args, 0, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/stamp",
+                   parse_args, 0, 2, NULL)
       CMD_MAINFUNC(cmd_stamp)
       CMD_TAGS(
               CMD_TAG_UI)
@@ -2561,9 +2405,8 @@ static struct cmd_t command_defs[] = {
               "/stamp unset incoming")
     },
 
-    { "/avatar",
-      parse_args, 2, 2, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/avatar",
+                   parse_args, 2, 2, NULL)
       CMD_MAINFUNC(cmd_avatar)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -2585,9 +2428,8 @@ static struct cmd_t command_defs[] = {
               "/avatar get thor@valhalla.edda",
               "/avatar open freyja@vanaheimr.edda") },
 
-    { "/os",
-      parse_args, 1, 1, &cons_os_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/os",
+                   parse_args, 1, 1, &cons_os_setting)
       CMD_MAINFUNC(cmd_os)
       CMD_TAGS(
               CMD_TAG_DISCOVERY)
@@ -2597,12 +2439,10 @@ static struct cmd_t command_defs[] = {
               "Choose whether to include the OS name if a user asks for software information (XEP-0092).")
       CMD_ARGS(
               { "on|off", "" })
-      CMD_NOEXAMPLES
     },
 
-    { "/correction",
-      parse_args, 1, 2, &cons_correction_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/correction",
+                   parse_args, 1, 2, &cons_correction_setting)
       CMD_MAINFUNC(cmd_correction)
       CMD_TAGS(
               CMD_TAG_UI,
@@ -2618,12 +2458,10 @@ static struct cmd_t command_defs[] = {
       CMD_ARGS(
               { "on|off", "Enable/Disable support for last message correction." },
               { "char", "Set character that will prefix corrected messages. Default: '+'." })
-      CMD_NOEXAMPLES
     },
 
-    { "/correct",
-      parse_args_as_one, 1, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/correct",
+                   parse_args_as_one, 1, 1, NULL)
       CMD_MAINFUNC(cmd_correct)
       CMD_TAGS(
               CMD_TAG_CHAT,
@@ -2636,12 +2474,10 @@ static struct cmd_t command_defs[] = {
               "For more information on how to configure corrections, see: /help correction.")
       CMD_ARGS(
               { "message", "The corrected message." })
-      CMD_NOEXAMPLES
     },
 
-    { "/slashguard",
-      parse_args, 1, 1, &cons_slashguard_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/slashguard",
+                   parse_args, 1, 1, &cons_slashguard_setting)
       CMD_MAINFUNC(cmd_slashguard)
       CMD_TAGS(
               CMD_TAG_UI,
@@ -2653,12 +2489,10 @@ static struct cmd_t command_defs[] = {
               "It tries to protect you from typing ' /quit' and similar things in chats.")
       CMD_ARGS(
               { "on|off", "Enable or disable slashguard." })
-      CMD_NOEXAMPLES
     },
 
-    { "/serversoftware",
-      parse_args, 1, 1, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/serversoftware",
+                   parse_args, 1, 1, NULL)
       CMD_MAINFUNC(cmd_serversoftware)
       CMD_TAGS(
               CMD_TAG_DISCOVERY)
@@ -2673,15 +2507,14 @@ static struct cmd_t command_defs[] = {
               "/serversoftware xmpp.vanaheimr.edda")
     },
 
-    { "/executable",
-      parse_args, 2, 4, &cons_executable_setting,
+    { CMD_PREAMBLE("/executable",
+                   parse_args, 2, 4, &cons_executable_setting)
       CMD_SUBFUNCS(
               { "avatar",  cmd_executable_avatar },
               { "urlopen", cmd_executable_urlopen },
               { "urlsave", cmd_executable_urlsave },
               { "editor", cmd_executable_editor },
               { "vcard_photo", cmd_executable_vcard_photo })
-      CMD_NOMAINFUNC
       CMD_TAGS(
               CMD_TAG_DISCOVERY)
       CMD_SYN(
@@ -2715,12 +2548,11 @@ static struct cmd_t command_defs[] = {
               "/executable editor set vim")
     },
 
-    { "/url",
-      parse_args, 2, 3, NULL,
+    { CMD_PREAMBLE("/url",
+                   parse_args, 2, 3, NULL)
       CMD_SUBFUNCS(
               { "open", cmd_url_open },
               { "save", cmd_url_save })
-      CMD_NOMAINFUNC
       CMD_TAGS(
               CMD_TAG_CHAT,
               CMD_TAG_GROUPCHAT)
@@ -2737,9 +2569,8 @@ static struct cmd_t command_defs[] = {
               "/url save https://profanity-im.github.io/guide/latest/userguide.html /home/user/Download/")
     },
 
-    { "/mam",
-      parse_args, 1, 1, &cons_mam_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/mam",
+                   parse_args, 1, 1, &cons_mam_setting)
       CMD_MAINFUNC(cmd_mam)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -2751,25 +2582,19 @@ static struct cmd_t command_defs[] = {
               "We are going to work on this in future releases. So far this setting is mostly here for developers.")
       CMD_ARGS(
               { "on|off", "Enable or disable MAM" })
-      CMD_NOEXAMPLES
     },
 
-    { "/changepassword",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/changepassword",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_change_password)
-      CMD_NOTAGS
       CMD_SYN(
               "/changepassword")
       CMD_DESC(
               "Change password of logged in account")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/editor",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/editor",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_editor)
       CMD_TAGS(
               CMD_TAG_CHAT,
@@ -2780,13 +2605,10 @@ static struct cmd_t command_defs[] = {
               "Spawn external editor to edit message. "
               "After editing the inputline may appear empty. Press enter to send the text anyways. "
               "Use /executable to set your favourite editor." )
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/correct-editor",
-      parse_args, 0, 0, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/correct-editor",
+                   parse_args, 0, 0, NULL)
       CMD_MAINFUNC(cmd_correct_editor)
       CMD_TAGS(
               CMD_TAG_CHAT,
@@ -2797,13 +2619,10 @@ static struct cmd_t command_defs[] = {
               "Spawn external editor to correct and resend the last message (XEP-0308). "
               "For more information on how to configure corrections, see: /help correction. "
               "Use /executable to set your favourite editor.")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/silence",
-      parse_args, 1, 1, &cons_silence_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/silence",
+                   parse_args, 1, 1, &cons_silence_setting)
       CMD_MAINFUNC(cmd_silence)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -2811,13 +2630,10 @@ static struct cmd_t command_defs[] = {
               "/silence on|off")
       CMD_DESC(
               "Let's you silence all message attempts from people who are not in your roster.")
-      CMD_NOARGS
-      CMD_NOEXAMPLES
     },
 
-    { "/register",
-      parse_args, 2, 6, NULL,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/register",
+                   parse_args, 2, 6, NULL)
       CMD_MAINFUNC(cmd_register)
       CMD_TAGS(
               CMD_TAG_CONNECTION)
@@ -2841,9 +2657,8 @@ static struct cmd_t command_defs[] = {
               "/register someuser my.xmppserv.er port 5443 tls force")
     },
 
-    { "/mood",
-      parse_args, 1, 3, &cons_mood_setting,
-      CMD_NOSUBFUNCS
+    { CMD_PREAMBLE("/mood",
+                   parse_args, 1, 3, &cons_mood_setting)
       CMD_MAINFUNC(cmd_mood)
       CMD_TAGS(
               CMD_TAG_CHAT)
@@ -2862,6 +2677,24 @@ static struct cmd_t command_defs[] = {
               "/mood set amazed",
               "/mood clear")
     },
+
+    { CMD_PREAMBLE("/strophe",
+                   parse_args, 2, 2, &cons_strophe_setting)
+      CMD_MAINFUNC(cmd_strophe)
+      CMD_TAGS(
+              CMD_TAG_CONNECTION)
+      CMD_SYN(
+              "/strophe verbosity 0-3",
+              "/strophe sm on|no-resend|off")
+      CMD_DESC(
+              "Modify libstrophe settings.")
+      CMD_ARGS(
+              { "verbosity 0-3", "Set libstrophe verbosity level when log level is 'DEBUG'." },
+              { "sm on|no-resend|off", "Enable or disable Stream-Management (SM) as of XEP-0198. The 'no-resend' option enables SM, but won't re-send un-ACK'ed messages on re-connect." })
+      CMD_EXAMPLES(
+              "/strophe verbosity 3",
+              "/strophe sm no-resend")
+    },
     // NEXT-COMMAND (search helper)
 };
 
@@ -2869,8 +2702,8 @@ static struct cmd_t command_defs[] = {
 
 static GHashTable* search_index;
 
-char*
-_cmd_index(Command* cmd)
+static char*
+_cmd_index(const Command* cmd)
 {
     GString* index_source = g_string_new("");
     index_source = g_string_append(index_source, cmd->cmd);
@@ -2878,12 +2711,12 @@ _cmd_index(Command* cmd)
     index_source = g_string_append(index_source, cmd->help.desc);
     index_source = g_string_append(index_source, " ");
 
-    int len = g_strv_length(cmd->help.tags);
+    int len = g_strv_length((gchar**)cmd->help.tags);
     for (int i = 0; i < len; i++) {
         index_source = g_string_append(index_source, cmd->help.tags[i]);
         index_source = g_string_append(index_source, " ");
     }
-    len = g_strv_length(cmd->help.synopsis);
+    len = g_strv_length((gchar**)cmd->help.synopsis);
     for (int i = 0; i < len; i++) {
         index_source = g_string_append(index_source, cmd->help.synopsis[i]);
         index_source = g_string_append(index_source, " ");
@@ -2983,10 +2816,10 @@ cmd_init(void)
     // load command defs into hash table
     commands = g_hash_table_new(g_str_hash, g_str_equal);
     for (unsigned int i = 0; i < ARRAY_SIZE(command_defs); i++) {
-        Command* pcmd = command_defs + i;
+        const Command* pcmd = command_defs + i;
 
         // add to hash
-        g_hash_table_insert(commands, pcmd->cmd, pcmd);
+        g_hash_table_insert(commands, pcmd->cmd, (gpointer)pcmd);
 
         // add to search index
         g_hash_table_insert(search_index, strdup(pcmd->cmd), _cmd_index(pcmd));
@@ -3077,8 +2910,8 @@ command_docgen(void)
     GList* cmds = NULL;
 
     for (unsigned int i = 0; i < ARRAY_SIZE(command_defs); i++) {
-        Command* pcmd = command_defs + i;
-        cmds = g_list_insert_sorted(cmds, pcmd, (GCompareFunc)_cmp_command);
+        const Command* pcmd = command_defs + i;
+        cmds = g_list_insert_sorted(cmds, (gpointer)pcmd, (GCompareFunc)_cmp_command);
     }
 
     FILE* toc_fragment = fopen("toc_fragment.html", "w");
@@ -3162,8 +2995,8 @@ command_mangen(void)
     GList* cmds = NULL;
 
     for (unsigned int i = 0; i < ARRAY_SIZE(command_defs); i++) {
-        Command* pcmd = command_defs + i;
-        cmds = g_list_insert_sorted(cmds, pcmd, (GCompareFunc)_cmp_command);
+        const Command* pcmd = command_defs + i;
+        cmds = g_list_insert_sorted(cmds, (gpointer)pcmd, (GCompareFunc)_cmp_command);
     }
 
     create_dir("docs");
diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c
index da38f405..56a18bdb 100644
--- a/src/command/cmd_funcs.c
+++ b/src/command/cmd_funcs.c
@@ -82,16 +82,17 @@
 #include "plugins/plugins.h"
 #include "ui/ui.h"
 #include "ui/window_list.h"
-#include "xmpp/xmpp.h"
+#include "xmpp/avatar.h"
+#include "xmpp/chat_session.h"
 #include "xmpp/connection.h"
 #include "xmpp/contact.h"
-#include "xmpp/roster_list.h"
 #include "xmpp/jid.h"
 #include "xmpp/muc.h"
-#include "xmpp/chat_session.h"
-#include "xmpp/avatar.h"
+#include "xmpp/roster_list.h"
+#include "xmpp/session.h"
 #include "xmpp/stanza.h"
 #include "xmpp/vcard_funcs.h"
+#include "xmpp/xmpp.h"
 
 #ifdef HAVE_LIBOTR
 #include "otr/otr.h"
@@ -120,8 +121,8 @@
 
 static void _update_presence(const resource_presence_t presence,
                              const char* const show, gchar** args);
-static void _cmd_set_boolean_preference(gchar* arg, const char* const command,
-                                        const char* const display, preference_t pref);
+static gboolean _cmd_set_boolean_preference(gchar* arg, const char* const command,
+                                            const char* const display, preference_t pref);
 static void _who_room(ProfWin* window, const char* const command, gchar** args);
 static void _who_roster(ProfWin* window, const char* const command, gchar** args);
 static gboolean _cmd_execute(ProfWin* window, const char* const command, const char* const inp);
@@ -6517,9 +6518,8 @@ cmd_log(ProfWin* window, const char* const command, gchar** args)
     }
 
     if (strcmp(subcmd, "level") == 0) {
-        if (g_strcmp0(value, "INFO") == 0 || g_strcmp0(value, "DEBUG") == 0 || g_strcmp0(value, "WARN") == 0 || g_strcmp0(value, "ERROR") == 0) {
-
-            log_level_t prof_log_level = log_level_from_string(value);
+        log_level_t prof_log_level;
+        if (log_level_from_string(value, &prof_log_level) == 0) {
             log_close();
             log_init(prof_log_level, NULL);
 
@@ -6540,8 +6540,9 @@ cmd_reconnect(ProfWin* window, const char* const command, gchar** args)
 
     int intval = 0;
     char* err_msg = NULL;
-    gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
-    if (res) {
+    if (g_strcmp0(value, "now") == 0) {
+        session_reconnect_now();
+    } else if (strtoi_range(value, &intval, 0, INT_MAX, &err_msg)) {
         prefs_set_reconnect(intval);
         if (intval == 0) {
             cons_show("Reconnect disabled.", intval);
@@ -8431,23 +8432,23 @@ _cmd_execute(ProfWin* window, const char* const command, const char* const inp)
             ui_invalid_command_usage(cmd->cmd, cmd->setting_func);
             return TRUE;
         }
-        if (args[0] && cmd->sub_funcs[0][0]) {
+        if (args[0] && cmd->sub_funcs[0].cmd) {
             int i = 0;
-            while (cmd->sub_funcs[i][0]) {
-                if (g_strcmp0(args[0], (char*)cmd->sub_funcs[i][0]) == 0) {
-                    gboolean (*func)(ProfWin * window, const char* const command, gchar** args) = cmd->sub_funcs[i][1];
-                    gboolean result = func(window, command, args);
-                    g_strfreev(args);
-                    return result;
+            while (cmd->sub_funcs[i].cmd) {
+                if (g_strcmp0(args[0], (char*)cmd->sub_funcs[i].cmd) == 0) {
+                    result = cmd->sub_funcs[i].func(window, command, args);
+                    goto out;
                 }
                 i++;
             }
         }
         if (!cmd->func) {
             ui_invalid_command_usage(cmd->cmd, cmd->setting_func);
-            return TRUE;
+            result = TRUE;
+            goto out;
         }
-        gboolean result = cmd->func(window, command, args);
+        result = cmd->func(window, command, args);
+out:
         g_strfreev(args);
         return result;
     } else if (plugins_run_command(inp)) {
@@ -8580,31 +8581,24 @@ _update_presence(const resource_presence_t resource_presence,
 }
 
 // helper function for boolean preference commands
-static void
+static gboolean
 _cmd_set_boolean_preference(gchar* arg, const char* const command,
                             const char* const display, preference_t pref)
 {
     if (arg == NULL) {
         cons_bad_cmd_usage(command);
-    } else if (strcmp(arg, "on") == 0) {
-        GString* enabled = g_string_new(display);
-        g_string_append(enabled, " enabled.");
-
-        cons_show(enabled->str);
+        return FALSE;
+    } else if (g_strcmp0(arg, "on") == 0) {
+        cons_show("%s enabled.", display);
         prefs_set_boolean(pref, TRUE);
-
-        g_string_free(enabled, TRUE);
-    } else if (strcmp(arg, "off") == 0) {
-        GString* disabled = g_string_new(display);
-        g_string_append(disabled, " disabled.");
-
-        cons_show(disabled->str);
+    } else if (g_strcmp0(arg, "off") == 0) {
+        cons_show("%s disabled.", display);
         prefs_set_boolean(pref, FALSE);
-
-        g_string_free(disabled, TRUE);
     } else {
         cons_bad_cmd_usage(command);
+        return FALSE;
     }
+    return TRUE;
 }
 
 gboolean
@@ -8894,6 +8888,7 @@ cmd_omemo_fingerprint(ProfWin* window, const char* const command, gchar** args)
         free(formatted_fingerprint);
     }
 
+    jid_destroy(jid);
     g_list_free(fingerprints);
 
     win_println(window, THEME_DEFAULT, "-", "You can trust it with '/omemo trust <fingerprint>'");
@@ -9857,6 +9852,41 @@ cmd_mood(ProfWin* window, const char* const command, gchar** args)
 }
 
 gboolean
+cmd_strophe(ProfWin* window, const char* const command, gchar** args)
+{
+    if (g_strcmp0(args[0], "verbosity") == 0) {
+        int verbosity;
+        auto_gchar gchar* err_msg = NULL;
+        if (string_to_verbosity(args[1], &verbosity, &err_msg)) {
+            xmpp_ctx_set_verbosity(connection_get_ctx(), verbosity);
+            prefs_set_string(PREF_STROPHE_VERBOSITY, args[1]);
+            return TRUE;
+        } else {
+            cons_show(err_msg);
+        }
+    } else if (g_strcmp0(args[0], "sm") == 0) {
+        if (g_strcmp0(args[1], "no-resend") == 0) {
+            cons_show("Stream Management set to 'no-resend'.");
+            prefs_set_boolean(PREF_STROPHE_SM_ENABLED, TRUE);
+            prefs_set_boolean(PREF_STROPHE_SM_RESEND, FALSE);
+            return TRUE;
+        } else if (g_strcmp0(args[1], "on") == 0) {
+            cons_show("Stream Management enabled.");
+            prefs_set_boolean(PREF_STROPHE_SM_ENABLED, TRUE);
+            prefs_set_boolean(PREF_STROPHE_SM_RESEND, TRUE);
+            return TRUE;
+        } else if (g_strcmp0(args[1], "off") == 0) {
+            cons_show("Stream Management disabled.");
+            prefs_set_boolean(PREF_STROPHE_SM_ENABLED, FALSE);
+            prefs_set_boolean(PREF_STROPHE_SM_RESEND, FALSE);
+            return TRUE;
+        }
+    }
+    cons_bad_cmd_usage(command);
+    return FALSE;
+}
+
+gboolean
 cmd_vcard(ProfWin* window, const char* const command, gchar** args)
 {
     if (connection_get_status() != JABBER_CONNECTED) {
diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h
index 597164f3..6d446703 100644
--- a/src/command/cmd_funcs.h
+++ b/src/command/cmd_funcs.h
@@ -68,7 +68,11 @@ typedef struct cmd_t
     int min_args;
     int max_args;
     void (*setting_func)(void);
-    void* sub_funcs[50][2];
+    struct
+    {
+        const char* cmd;
+        gboolean (*func)(ProfWin* window, const char* const command, gchar** args);
+    } sub_funcs[50];
     gboolean (*func)(ProfWin* window, const char* const command, gchar** args);
     CommandHelp help;
 } Command;
@@ -253,6 +257,7 @@ gboolean cmd_correct_editor(ProfWin* window, const char* const command, gchar**
 gboolean cmd_silence(ProfWin* window, const char* const command, gchar** args);
 gboolean cmd_register(ProfWin* window, const char* const command, gchar** args);
 gboolean cmd_mood(ProfWin* window, const char* const command, gchar** args);
+gboolean cmd_strophe(ProfWin* window, const char* const command, gchar** args);
 gboolean cmd_stamp(ProfWin* window, const char* const command, gchar** args);
 gboolean cmd_vcard(ProfWin* window, const char* const command, gchar** args);
 gboolean cmd_vcard_add(ProfWin* window, const char* const command, gchar** args);
diff --git a/src/common.c b/src/common.c
index d00e096f..7888a1dc 100644
--- a/src/common.c
+++ b/src/common.c
@@ -70,6 +70,36 @@ struct curl_data_t
 
 static size_t _data_callback(void* ptr, size_t size, size_t nmemb, void* data);
 
+void
+auto_free_gchar(gchar** str)
+{
+    if (str == NULL)
+        return;
+    g_free(*str);
+}
+
+void
+auto_free_gcharv(gchar*** args)
+{
+    if (args == NULL)
+        return;
+    g_strfreev(*args);
+}
+
+void
+auto_free_char(char** str)
+{
+    if (str == NULL)
+        return;
+    free(*str);
+}
+
+gboolean
+string_to_verbosity(const char* cmd, int* verbosity, gchar** err_msg)
+{
+    return strtoi_range(cmd, verbosity, 0, 3, err_msg);
+}
+
 gboolean
 create_dir(const char* name)
 {
@@ -136,24 +166,24 @@ str_replace(const char* string, const char* substr,
 }
 
 gboolean
-strtoi_range(char* str, int* saveptr, int min, int max, char** err_msg)
+strtoi_range(const char* str, int* saveptr, int min, int max, gchar** err_msg)
 {
     char* ptr;
     int val;
-
+    if (str == NULL) {
+        if (err_msg)
+            *err_msg = g_strdup_printf("'str' input pointer can not be NULL");
+        return FALSE;
+    }
     errno = 0;
     val = (int)strtol(str, &ptr, 0);
     if (errno != 0 || *str == '\0' || *ptr != '\0') {
-        GString* err_str = g_string_new("");
-        g_string_printf(err_str, "Could not convert \"%s\" to a number.", str);
-        *err_msg = err_str->str;
-        g_string_free(err_str, FALSE);
+        if (err_msg)
+            *err_msg = g_strdup_printf("Could not convert \"%s\" to a number.", str);
         return FALSE;
     } else if (val < min || val > max) {
-        GString* err_str = g_string_new("");
-        g_string_printf(err_str, "Value %s out of range. Must be in %d..%d.", str, min, max);
-        *err_msg = err_str->str;
-        g_string_free(err_str, FALSE);
+        if (err_msg)
+            *err_msg = g_strdup_printf("Value %s out of range. Must be in %d..%d.", str, min, max);
         return FALSE;
     }
 
@@ -598,3 +628,10 @@ unique_filename_from_url(const char* url, const char* path)
 
     return unique_filename;
 }
+
+void
+glib_hash_table_free(GHashTable* hash_table)
+{
+    g_hash_table_remove_all(hash_table);
+    g_hash_table_unref(hash_table);
+}
diff --git a/src/common.h b/src/common.h
index 27d1684d..359e313e 100644
--- a/src/common.h
+++ b/src/common.h
@@ -47,6 +47,13 @@
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 
+void auto_free_gchar(gchar** str);
+#define auto_gchar __attribute__((__cleanup__(auto_free_gchar)))
+void auto_free_gcharv(gchar*** args);
+#define auto_gcharv __attribute__((__cleanup__(auto_free_gcharv)))
+void auto_free_char(char** str);
+#define auto_char __attribute__((__cleanup__(auto_free_char)))
+
 // assume malloc stores at most 8 bytes for size of allocated memory
 // and page size is at least 4KB
 #define READ_BUF_SIZE 4088
@@ -80,10 +87,12 @@ typedef enum {
     RESOURCE_XA
 } resource_presence_t;
 
+gboolean string_to_verbosity(const char* cmd, int* verbosity, gchar** err_msg);
+
 gboolean create_dir(const char* name);
 gboolean copy_file(const char* const src, const char* const target, const gboolean overwrite_existing);
 char* str_replace(const char* string, const char* substr, const char* replacement);
-gboolean strtoi_range(char* str, int* saveptr, int min, int max, char** err_msg);
+gboolean strtoi_range(const char* str, int* saveptr, int min, int max, char** err_msg);
 int utf8_display_len(const char* const str);
 
 char* release_get_latest(void);
@@ -109,4 +118,6 @@ gchar** format_call_external_argv(const char* template, const char* url, const c
 gchar* unique_filename_from_url(const char* url, const char* path);
 gchar* get_expanded_path(const char* path);
 
+void glib_hash_table_free(GHashTable* hash_table);
+
 #endif
diff --git a/src/config/account.c b/src/config/account.c
index 238c2ef1..89436f9a 100644
--- a/src/config/account.c
+++ b/src/config/account.c
@@ -49,71 +49,53 @@
 #include "xmpp/resource.h"
 
 ProfAccount*
-account_new(const gchar* const name, const gchar* const jid,
-            const gchar* const password, const gchar* eval_password, gboolean enabled, const gchar* const server,
-            int port, const gchar* const resource, const gchar* const last_presence,
-            const gchar* const login_presence, int priority_online, int priority_chat,
-            int priority_away, int priority_xa, int priority_dnd,
-            const gchar* const muc_service, const gchar* const muc_nick,
-            const gchar* const otr_policy, GList* otr_manual, GList* otr_opportunistic,
-            GList* otr_always, const gchar* const omemo_policy, GList* omemo_enabled,
-            GList* omemo_disabled, GList* ox_enabled, GList* pgp_enabled,
-            const gchar* const pgp_keyid, const char* const startscript, const char* const theme,
-            gchar* tls_policy, gchar* auth_policy)
+account_new(gchar* name, gchar* jid, gchar* password, gchar* eval_password, gboolean enabled,
+            gchar* server, int port, gchar* resource, gchar* last_presence, gchar* login_presence,
+            int priority_online, int priority_chat, int priority_away, int priority_xa, int priority_dnd,
+            gchar* muc_service, gchar* muc_nick,
+            gchar* otr_policy, GList* otr_manual, GList* otr_opportunistic, GList* otr_always,
+            gchar* omemo_policy, GList* omemo_enabled, GList* omemo_disabled,
+            GList* ox_enabled, GList* pgp_enabled, gchar* pgp_keyid,
+            gchar* startscript, gchar* theme, gchar* tls_policy, gchar* auth_policy)
 {
-    ProfAccount* new_account = malloc(sizeof(ProfAccount));
-    memset(new_account, 0, sizeof(ProfAccount));
+    ProfAccount* new_account = calloc(1, sizeof(ProfAccount));
 
-    new_account->name = strdup(name);
+    new_account->name = name;
 
     if (jid) {
-        new_account->jid = strdup(jid);
+        new_account->jid = jid;
     } else {
         new_account->jid = strdup(name);
     }
 
-    if (password) {
-        new_account->password = strdup(password);
-    } else {
-        new_account->password = NULL;
-    }
+    new_account->password = password;
 
-    if (eval_password) {
-        new_account->eval_password = strdup(eval_password);
-    } else {
-        new_account->eval_password = NULL;
-    }
+    new_account->eval_password = eval_password;
 
     new_account->enabled = enabled;
 
-    if (server) {
-        new_account->server = strdup(server);
-    } else {
-        new_account->server = NULL;
-    }
+    new_account->server = server;
 
-    if (resource) {
-        new_account->resource = strdup(resource);
-    } else {
-        new_account->resource = NULL;
-    }
+    new_account->resource = resource;
 
     new_account->port = port;
 
     if (last_presence == NULL || !valid_resource_presence_string(last_presence)) {
         new_account->last_presence = strdup("online");
+        g_free(last_presence);
     } else {
-        new_account->last_presence = strdup(last_presence);
+        new_account->last_presence = last_presence;
     }
 
     if (login_presence == NULL) {
         new_account->login_presence = strdup("online");
     } else if (strcmp(login_presence, "last") == 0) {
-        new_account->login_presence = strdup(login_presence);
+        new_account->login_presence = login_presence;
     } else if (!valid_resource_presence_string(login_presence)) {
         new_account->login_presence = strdup("online");
+        g_free(login_presence);
     } else {
-        new_account->login_presence = strdup(login_presence);
+        new_account->login_presence = login_presence;
     }
 
     new_account->priority_online = priority_online;
@@ -122,72 +104,38 @@ account_new(const gchar* const name, const gchar* const jid,
     new_account->priority_xa = priority_xa;
     new_account->priority_dnd = priority_dnd;
 
-    if (muc_service) {
-        new_account->muc_service = strdup(muc_service);
-    } else {
-        new_account->muc_service = NULL;
-    }
+    new_account->muc_service = muc_service;
 
     if (muc_nick == NULL) {
         Jid* jidp = jid_create(new_account->jid);
         new_account->muc_nick = strdup(jidp->domainpart);
         jid_destroy(jidp);
     } else {
-        new_account->muc_nick = strdup(muc_nick);
+        new_account->muc_nick = muc_nick;
     }
 
-    if (otr_policy) {
-        new_account->otr_policy = strdup(otr_policy);
-    } else {
-        new_account->otr_policy = NULL;
-    }
+    new_account->otr_policy = otr_policy;
 
     new_account->otr_manual = otr_manual;
     new_account->otr_opportunistic = otr_opportunistic;
     new_account->otr_always = otr_always;
 
-    if (omemo_policy) {
-        new_account->omemo_policy = strdup(omemo_policy);
-    } else {
-        new_account->omemo_policy = NULL;
-    }
-
+    new_account->omemo_policy = omemo_policy;
     new_account->omemo_enabled = omemo_enabled;
     new_account->omemo_disabled = omemo_disabled;
 
     new_account->ox_enabled = ox_enabled;
 
     new_account->pgp_enabled = pgp_enabled;
+    new_account->pgp_keyid = pgp_keyid;
 
-    if (pgp_keyid != NULL) {
-        new_account->pgp_keyid = strdup(pgp_keyid);
-    } else {
-        new_account->pgp_keyid = NULL;
-    }
+    new_account->startscript = startscript;
 
-    if (startscript != NULL) {
-        new_account->startscript = strdup(startscript);
-    } else {
-        new_account->startscript = NULL;
-    }
+    new_account->theme = theme;
 
-    if (theme != NULL) {
-        new_account->theme = strdup(theme);
-    } else {
-        new_account->theme = NULL;
-    }
-
-    if (tls_policy != NULL) {
-        new_account->tls_policy = strdup(tls_policy);
-    } else {
-        new_account->tls_policy = NULL;
-    }
+    new_account->tls_policy = tls_policy;
 
-    if (auth_policy != NULL) {
-        new_account->auth_policy = strdup(auth_policy);
-    } else {
-        new_account->auth_policy = NULL;
-    }
+    new_account->auth_policy = auth_policy;
 
     return new_account;
 }
diff --git a/src/config/account.h b/src/config/account.h
index ce49883e..a469e068 100644
--- a/src/config/account.h
+++ b/src/config/account.h
@@ -73,17 +73,14 @@ typedef struct prof_account_t
     gchar* auth_policy;
 } ProfAccount;
 
-ProfAccount* account_new(const gchar* const name, const gchar* const jid,
-                         const gchar* const passord, const gchar* eval_password, gboolean enabled, const gchar* const server,
-                         int port, const gchar* const resource, const gchar* const last_presence,
-                         const gchar* const login_presence, int priority_online, int priority_chat,
-                         int priority_away, int priority_xa, int priority_dnd,
-                         const gchar* const muc_service, const gchar* const muc_nick,
-                         const gchar* const otr_policy, GList* otr_manual, GList* otr_opportunistic,
-                         GList* otr_always, const gchar* const omemo_policy, GList* omemo_enabled,
-                         GList* omemo_disabled, GList* ox_enabled, GList* pgp_enabled, const gchar* const pgp_keyid,
-                         const char* const startscript, const char* const theme, gchar* tls_policy,
-                         gchar* auth_policy);
+ProfAccount* account_new(gchar* name, gchar* jid, gchar* password, gchar* eval_password, gboolean enabled,
+                         gchar* server, int port, gchar* resource, gchar* last_presence, gchar* login_presence,
+                         int priority_online, int priority_chat, int priority_away, int priority_xa, int priority_dnd,
+                         gchar* muc_service, gchar* muc_nick,
+                         gchar* otr_policy, GList* otr_manual, GList* otr_opportunistic, GList* otr_always,
+                         gchar* omemo_policy, GList* omemo_enabled, GList* omemo_disabled,
+                         GList* ox_enabled, GList* pgp_enabled, gchar* pgp_keyid,
+                         gchar* startscript, gchar* theme, gchar* tls_policy, gchar* auth_policy);
 char* account_create_connect_jid(ProfAccount* account);
 gboolean account_eval_password(ProfAccount* account);
 void account_free(ProfAccount* account);
diff --git a/src/config/accounts.c b/src/config/accounts.c
index cf1c1754..9c7eddf9 100644
--- a/src/config/accounts.c
+++ b/src/config/accounts.c
@@ -342,7 +342,7 @@ accounts_get_account(const char* const name)
 
         gchar* auth_policy = g_key_file_get_string(accounts, name, "auth.policy", NULL);
 
-        ProfAccount* new_account = account_new(name, jid, password, eval_password, enabled,
+        ProfAccount* new_account = account_new(g_strdup(name), jid, password, eval_password, enabled,
                                                server, port, resource, last_presence, login_presence,
                                                priority_online, priority_chat, priority_away, priority_xa,
                                                priority_dnd, muc_service, muc_nick, otr_policy, otr_manual,
@@ -350,23 +350,6 @@ accounts_get_account(const char* const name)
                                                omemo_disabled, ox_enabled, pgp_enabled, pgp_keyid,
                                                startscript, theme, tls_policy, auth_policy);
 
-        g_free(jid);
-        g_free(password);
-        g_free(eval_password);
-        g_free(server);
-        g_free(resource);
-        g_free(last_presence);
-        g_free(login_presence);
-        g_free(muc_service);
-        g_free(muc_nick);
-        g_free(otr_policy);
-        g_free(omemo_policy);
-        g_free(pgp_keyid);
-        g_free(startscript);
-        g_free(theme);
-        g_free(tls_policy);
-        g_free(auth_policy);
-
         return new_account;
     }
 }
diff --git a/src/config/preferences.c b/src/config/preferences.c
index de455245..f15952cd 100644
--- a/src/config/preferences.c
+++ b/src/config/preferences.c
@@ -533,7 +533,7 @@ prefs_set_boolean(preference_t pref, gboolean value)
     g_key_file_set_boolean(prefs, group, key, value);
 }
 
-char*
+gchar*
 prefs_get_string(preference_t pref)
 {
     const char* group = _get_group(pref);
@@ -553,14 +553,14 @@ prefs_get_string(preference_t pref)
     }
 }
 
-char*
+gchar*
 prefs_get_string_with_option(preference_t pref, gchar* option)
 {
     const char* group = _get_group(pref);
     const char* key = _get_key(pref);
     char* def = _get_default_string(pref);
 
-    char* result = g_key_file_get_locale_string(prefs, group, key, option, NULL);
+    gchar* result = g_key_file_get_locale_string(prefs, group, key, option, NULL);
 
     if (result == NULL) {
         // check for user set default
@@ -1869,6 +1869,9 @@ _get_group(preference_t pref)
     case PREF_CORRECTION_ALLOW:
     case PREF_MAM:
     case PREF_SILENCE_NON_ROSTER:
+    case PREF_STROPHE_VERBOSITY:
+    case PREF_STROPHE_SM_ENABLED:
+    case PREF_STROPHE_SM_RESEND:
         return PREF_GROUP_CONNECTION;
     case PREF_OTR_LOG:
     case PREF_OTR_POLICY:
@@ -2165,6 +2168,12 @@ _get_key(preference_t pref)
         return "mood";
     case PREF_VCARD_PHOTO_CMD:
         return "vcard.photo.cmd";
+    case PREF_STROPHE_VERBOSITY:
+        return "strophe.verbosity";
+    case PREF_STROPHE_SM_ENABLED:
+        return "strophe.sm.enabled";
+    case PREF_STROPHE_SM_RESEND:
+        return "strophe.sm.resend";
     default:
         return NULL;
     }
@@ -2217,6 +2226,8 @@ _get_default_boolean(preference_t pref)
     case PREF_INTYPE_CONSOLE:
     case PREF_NOTIFY_MENTION_WHOLE_WORD:
     case PREF_MOOD:
+    case PREF_STROPHE_SM_ENABLED:
+    case PREF_STROPHE_SM_RESEND:
         return TRUE;
     default:
         return FALSE;
@@ -2316,6 +2327,8 @@ _get_default_string(preference_t pref)
         return NULL; // Default to built-in method.
     case PREF_OX_LOG:
         return "on";
+    case PREF_STROPHE_VERBOSITY:
+        return "0";
     default:
         return NULL;
     }
diff --git a/src/config/preferences.h b/src/config/preferences.h
index 95a84865..ca8acea4 100644
--- a/src/config/preferences.h
+++ b/src/config/preferences.h
@@ -182,6 +182,9 @@ typedef enum {
     PREF_NOTIFY_ROOM_OFFLINE,
     PREF_OX_LOG,
     PREF_MOOD,
+    PREF_STROPHE_VERBOSITY,
+    PREF_STROPHE_SM_ENABLED,
+    PREF_STROPHE_SM_RESEND,
     PREF_VCARD_PHOTO_CMD,
 } preference_t;
 
@@ -329,8 +332,8 @@ void prefs_save_win_placement(ProfWinPlacement* placement);
 
 gboolean prefs_get_boolean(preference_t pref);
 void prefs_set_boolean(preference_t pref, gboolean value);
-char* prefs_get_string(preference_t pref);
-char* prefs_get_string_with_option(preference_t pref, gchar* option);
+gchar* prefs_get_string(preference_t pref);
+gchar* prefs_get_string_with_option(preference_t pref, gchar* option);
 void prefs_set_string(preference_t pref, char* value);
 void prefs_set_string_with_option(preference_t pref, char* option, char* value);
 void prefs_set_string_list_with_option(preference_t pref, char* option, const gchar* const* values);
diff --git a/src/database.c b/src/database.c
index 13946e8d..ce936170 100644
--- a/src/database.c
+++ b/src/database.c
@@ -57,6 +57,16 @@ static char* _get_db_filename(ProfAccount* account);
 static prof_msg_type_t _get_message_type_type(const char* const type);
 static prof_enc_t _get_message_enc_type(const char* const encstr);
 
+#define auto_sqlite __attribute__((__cleanup__(auto_free_sqlite)))
+
+static void
+auto_free_sqlite(gchar** str)
+{
+    if (str == NULL)
+        return;
+    sqlite3_free(*str);
+}
+
 static char*
 _get_db_filename(ProfAccount* account)
 {
@@ -243,7 +253,6 @@ GSList*
 log_database_get_previous_chat(const gchar* const contact_barejid, char* start_time, char* end_time, gboolean from_start, gboolean flip)
 {
     sqlite3_stmt* stmt = NULL;
-    gchar* query;
     const char* jid = connection_get_fulljid();
     Jid* myjid = jid_create(jid);
     if (!myjid)
@@ -254,7 +263,7 @@ log_database_get_previous_chat(const gchar* const contact_barejid, char* start_t
     gchar* sort2 = !flip ? "ASC" : "DESC";
     GDateTime* now = g_date_time_new_now_local();
     gchar* end_date_fmt = end_time ? end_time : g_date_time_format_iso8601(now);
-    query = sqlite3_mprintf("SELECT * FROM (SELECT COALESCE(B.`message`, A.`message`) AS message, A.`timestamp`, A.`from_jid`, A.`type`, A.`encryption` from `ChatLogs` AS A LEFT JOIN `ChatLogs` AS B ON A.`stanza_id` = B.`replace_id` WHERE A.`replace_id` = '' AND ((A.`from_jid` = '%q' AND A.`to_jid` = '%q') OR (A.`from_jid` = '%q' AND A.`to_jid` = '%q')) AND A.`timestamp` < '%q' AND (%Q IS NULL OR A.`timestamp` > %Q) ORDER BY A.`timestamp` %s LIMIT %d) ORDER BY `timestamp` %s;", contact_barejid, myjid->barejid, myjid->barejid, contact_barejid, end_date_fmt, start_time, start_time, sort1, MESSAGES_TO_RETRIEVE, sort2);
+    auto_sqlite gchar* query = sqlite3_mprintf("SELECT * FROM (SELECT COALESCE(B.`message`, A.`message`) AS message, A.`timestamp`, A.`from_jid`, A.`type`, A.`encryption` from `ChatLogs` AS A LEFT JOIN `ChatLogs` AS B ON A.`stanza_id` = B.`replace_id` WHERE A.`replace_id` = '' AND ((A.`from_jid` = '%q' AND A.`to_jid` = '%q') OR (A.`from_jid` = '%q' AND A.`to_jid` = '%q')) AND A.`timestamp` < '%q' AND (%Q IS NULL OR A.`timestamp` > %Q) ORDER BY A.`timestamp` %s LIMIT %d) ORDER BY `timestamp` %s;", contact_barejid, myjid->barejid, myjid->barejid, contact_barejid, end_date_fmt, start_time, start_time, sort1, MESSAGES_TO_RETRIEVE, sort2);
 
     g_date_time_unref(now);
     g_free(end_date_fmt);
@@ -292,7 +301,6 @@ log_database_get_previous_chat(const gchar* const contact_barejid, char* start_t
         history = g_slist_append(history, msg);
     }
     sqlite3_finalize(stmt);
-    sqlite3_free(query);
 
     return history;
 }
diff --git a/src/log.c b/src/log.c
index 97c1a149..a1b7bb1d 100644
--- a/src/log.c
+++ b/src/log.c
@@ -233,21 +233,25 @@ log_msg(log_level_t level, const char* const area, const char* const msg)
     }
 }
 
-log_level_t
-log_level_from_string(char* log_level)
+int
+log_level_from_string(char* log_level, log_level_t* level)
 {
+    int ret = 0;
     assert(log_level != NULL);
+    assert(level != NULL);
     if (strcmp(log_level, "DEBUG") == 0) {
-        return PROF_LEVEL_DEBUG;
+        *level = PROF_LEVEL_DEBUG;
     } else if (strcmp(log_level, "INFO") == 0) {
-        return PROF_LEVEL_INFO;
+        *level = PROF_LEVEL_INFO;
     } else if (strcmp(log_level, "WARN") == 0) {
-        return PROF_LEVEL_WARN;
+        *level = PROF_LEVEL_WARN;
     } else if (strcmp(log_level, "ERROR") == 0) {
-        return PROF_LEVEL_ERROR;
+        *level = PROF_LEVEL_ERROR;
     } else { // default logging is warn
-        return PROF_LEVEL_WARN;
+        *level = PROF_LEVEL_WARN;
+        ret = -1;
     }
+    return ret;
 }
 
 const char*
diff --git a/src/log.h b/src/log.h
index 2a955c90..3bf092b3 100644
--- a/src/log.h
+++ b/src/log.h
@@ -55,7 +55,7 @@ void log_info(const char* const msg, ...);
 void log_warning(const char* const msg, ...);
 void log_error(const char* const msg, ...);
 void log_msg(log_level_t level, const char* const area, const char* const msg);
-log_level_t log_level_from_string(char* log_level);
+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);
diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c
index 54a8e8c8..87208e9d 100644
--- a/src/omemo/omemo.c
+++ b/src/omemo/omemo.c
@@ -83,7 +83,6 @@ static char* _omemo_fingerprint(ec_public_key* identity, gboolean formatted);
 static unsigned char* _omemo_fingerprint_decode(const char* const fingerprint, size_t* len);
 static char* _omemo_unformat_fingerprint(const char* const fingerprint_formatted);
 static void _cache_device_identity(const char* const jid, uint32_t device_id, ec_public_key* identity);
-static void _g_hash_table_free(GHashTable* hash_table);
 static void _acquire_sender_devices_list(void);
 
 typedef gboolean (*OmemoDeviceListHandler)(const char* const jid, GList* device_list);
@@ -221,7 +220,7 @@ omemo_on_connect(ProfAccount* account)
         .get_local_registration_id = get_local_registration_id,
         .save_identity = save_identity,
         .is_trusted_identity = is_trusted_identity,
-        .destroy_func = NULL,
+        .destroy_func = (void (*)(void*))identity_key_store_destroy,
         .user_data = &omemo_ctx.identity_key_store
     };
     signal_protocol_store_context_set_identity_key_store(omemo_ctx.store, &identity_key_store);
@@ -229,7 +228,7 @@ omemo_on_connect(ProfAccount* account)
     loaded = FALSE;
     omemo_ctx.device_list = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)g_list_free);
     omemo_ctx.device_list_handler = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
-    omemo_ctx.known_devices = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_g_hash_table_free);
+    omemo_ctx.known_devices = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)glib_hash_table_free);
 
     gchar* omemo_dir = files_file_in_account_data_path(DIR_OMEMO, account->jid, NULL);
     if (!omemo_dir) {
@@ -306,9 +305,11 @@ omemo_on_disconnect(void)
         return;
     }
 
-    _g_hash_table_free(omemo_ctx.signed_pre_key_store);
-    _g_hash_table_free(omemo_ctx.pre_key_store);
-    _g_hash_table_free(omemo_ctx.device_list_handler);
+    glib_hash_table_free(omemo_ctx.signed_pre_key_store);
+    glib_hash_table_free(omemo_ctx.pre_key_store);
+    glib_hash_table_free(omemo_ctx.known_devices);
+    glib_hash_table_free(omemo_ctx.device_list_handler);
+    glib_hash_table_free(omemo_ctx.device_list);
 
     g_string_free(omemo_ctx.identity_filename, TRUE);
     g_key_file_free(omemo_ctx.identity_keyfile);
@@ -316,9 +317,18 @@ omemo_on_disconnect(void)
     g_key_file_free(omemo_ctx.trust_keyfile);
     g_string_free(omemo_ctx.sessions_filename, TRUE);
     g_key_file_free(omemo_ctx.sessions_keyfile);
-    _g_hash_table_free(omemo_ctx.session_store);
+    glib_hash_table_free(omemo_ctx.session_store);
     g_string_free(omemo_ctx.known_devices_filename, TRUE);
     g_key_file_free(omemo_ctx.known_devices_keyfile);
+
+    signal_protocol_store_context_destroy(omemo_ctx.store);
+    ec_public_key* pub = ratchet_identity_key_pair_get_public(omemo_ctx.identity_key_pair);
+    ec_private_key* priv = ratchet_identity_key_pair_get_private(omemo_ctx.identity_key_pair);
+    ratchet_identity_key_pair_destroy((signal_type_base*)omemo_ctx.identity_key_pair);
+    ec_private_key_destroy((signal_type_base*)priv);
+    ec_public_key_destroy((signal_type_base*)pub);
+
+    signal_context_destroy(omemo_ctx.signal);
 }
 
 void
@@ -564,7 +574,8 @@ omemo_set_device_list(const char* const from, GList* device_list)
     }
 
     // OMEMO trustmode ToFu
-    if (g_strcmp0(prefs_get_string(PREF_OMEMO_TRUST_MODE), "firstusage") == 0) {
+    auto_gchar gchar* trust_mode = prefs_get_string(PREF_OMEMO_TRUST_MODE);
+    if (g_strcmp0(trust_mode, "firstusage") == 0) {
         log_debug("[OMEMO] Checking firstusage state for %s", jid->barejid);
         GHashTable* trusted = g_hash_table_lookup(omemo_ctx.identity_key_store.trusted, jid->barejid);
         if (trusted) {
@@ -660,20 +671,26 @@ omemo_start_device_session(const char* const jid, uint32_t device_id,
                            const unsigned char* const identity_key_raw, size_t identity_key_len)
 {
     log_debug("[OMEMO] Starting device session for %s with device %d", jid, device_id);
-    signal_protocol_address address = {
+    signal_protocol_address jid_address = {
         .name = jid,
         .name_len = strlen(jid),
         .device_id = device_id,
     };
 
+    signal_protocol_address* address = NULL;
+    session_pre_key_bundle* bundle = NULL;
+    ec_public_key* prekey_public = NULL;
+    ec_public_key* signed_prekey = NULL;
+    session_builder* builder = NULL;
     ec_public_key* identity_key;
     curve_decode_point(&identity_key, identity_key_raw, identity_key_len, omemo_ctx.signal);
     _cache_device_identity(jid, device_id, identity_key);
 
-    gboolean trusted = is_trusted_identity(&address, (uint8_t*)identity_key_raw, identity_key_len, &omemo_ctx.identity_key_store);
+    gboolean trusted = is_trusted_identity(&jid_address, (uint8_t*)identity_key_raw, identity_key_len, &omemo_ctx.identity_key_store);
     log_debug("[OMEMO] Trust %s (%d): %d", jid, device_id, trusted);
 
-    if ((g_strcmp0(prefs_get_string(PREF_OMEMO_TRUST_MODE), "blind") == 0) && !trusted) {
+    auto_gchar gchar* trust_mode = prefs_get_string(PREF_OMEMO_TRUST_MODE);
+    if ((g_strcmp0(trust_mode, "blind") == 0) && !trusted) {
         char* fp = _omemo_fingerprint(identity_key, TRUE);
         cons_show("Blind trust for %s device %d (%s)", jid, device_id, fp);
         omemo_trust(jid, fp);
@@ -686,18 +703,15 @@ omemo_start_device_session(const char* const jid, uint32_t device_id,
         goto out;
     }
 
-    if (!contains_session(&address, omemo_ctx.session_store)) {
-        log_debug("[OMEMO] There is no Session for %s ( %d) ,... building session.", address.name, address.device_id);
+    if (!contains_session(&jid_address, omemo_ctx.session_store)) {
+        log_debug("[OMEMO] There is no Session for %s ( %d) ,... building session.", jid_address.name, jid_address.device_id);
         int res;
-        session_pre_key_bundle* bundle;
-        signal_protocol_address* address;
 
         address = malloc(sizeof(signal_protocol_address));
         address->name = strdup(jid);
         address->name_len = strlen(jid);
         address->device_id = device_id;
 
-        session_builder* builder;
         res = session_builder_create(&builder, omemo_ctx.store, address, omemo_ctx.signal);
         if (res != 0) {
             log_error("[OMEMO] cannot create session builder for %s device %d", jid, device_id);
@@ -709,9 +723,7 @@ omemo_start_device_session(const char* const jid, uint32_t device_id,
         prekey_index %= g_list_length(prekeys);
         omemo_key_t* prekey = g_list_nth_data(prekeys, prekey_index);
 
-        ec_public_key* prekey_public;
         curve_decode_point(&prekey_public, prekey->data, prekey->length, omemo_ctx.signal);
-        ec_public_key* signed_prekey;
         curve_decode_point(&signed_prekey, signed_prekey_raw, signed_prekey_len, omemo_ctx.signal);
 
         res = session_pre_key_bundle_create(&bundle, 0, device_id, prekey->id, prekey_public, signed_prekey_id, signed_prekey, signature, signature_len, identity_key);
@@ -732,6 +744,16 @@ omemo_start_device_session(const char* const jid, uint32_t device_id,
     }
 
 out:
+    if (bundle)
+        session_pre_key_bundle_destroy((signal_type_base*)bundle);
+    if (signed_prekey)
+        ec_public_key_destroy((signal_type_base*)signed_prekey);
+    if (prekey_public)
+        ec_public_key_destroy((signal_type_base*)prekey_public);
+    session_builder_free(builder);
+    if (address)
+        free((void*)address->name);
+    free(address);
     SIGNAL_UNREF(identity_key);
 }
 
@@ -1009,6 +1031,7 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid,
         ec_public_key_serialize(&identity_buffer, their_identity_key);
         *trusted = is_trusted_identity(&address, signal_buffer_data(identity_buffer),
                                        signal_buffer_len(identity_buffer), &omemo_ctx.identity_key_store);
+        signal_buffer_free(identity_buffer);
 
         /* Replace used pre_key in bundle */
         uint32_t pre_key_id = pre_key_signal_message_get_pre_key_id(message);
@@ -1729,13 +1752,6 @@ _cache_device_identity(const char* const jid, uint32_t device_id, ec_public_key*
 }
 
 static void
-_g_hash_table_free(GHashTable* hash_table)
-{
-    g_hash_table_remove_all(hash_table);
-    g_hash_table_unref(hash_table);
-}
-
-static void
 _generate_pre_keys(int count)
 {
     unsigned int start;
diff --git a/src/omemo/store.c b/src/omemo/store.c
index e0fc41ed..3825c95d 100644
--- a/src/omemo/store.c
+++ b/src/omemo/store.c
@@ -40,12 +40,10 @@
 #include "omemo/omemo.h"
 #include "omemo/store.h"
 
-static void _g_hash_table_free(GHashTable* hash_table);
-
 GHashTable*
 session_store_new(void)
 {
-    return g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_g_hash_table_free);
+    return g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)glib_hash_table_free);
 }
 
 GHashTable*
@@ -63,11 +61,19 @@ signed_pre_key_store_new(void)
 void
 identity_key_store_new(identity_key_store_t* identity_key_store)
 {
-    identity_key_store->trusted = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)signal_buffer_free);
+    identity_key_store->trusted = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)glib_hash_table_free);
     identity_key_store->private = NULL;
     identity_key_store->public = NULL;
 }
 
+void
+identity_key_store_destroy(identity_key_store_t* identity_key_store)
+{
+    signal_buffer_bzero_free(identity_key_store->private);
+    signal_buffer_bzero_free(identity_key_store->public);
+    glib_hash_table_free(identity_key_store->trusted);
+}
+
 int
 load_session(signal_buffer** record, signal_buffer** user_record,
              const signal_protocol_address* address, void* user_data)
@@ -450,10 +456,3 @@ load_sender_key(signal_buffer** record, signal_buffer** user_record,
 {
     return SG_SUCCESS;
 }
-
-static void
-_g_hash_table_free(GHashTable* hash_table)
-{
-    g_hash_table_remove_all(hash_table);
-    g_hash_table_unref(hash_table);
-}
diff --git a/src/omemo/store.h b/src/omemo/store.h
index bafe2576..b6a9a74d 100644
--- a/src/omemo/store.h
+++ b/src/omemo/store.h
@@ -57,6 +57,7 @@ GHashTable* session_store_new(void);
 GHashTable* pre_key_store_new(void);
 GHashTable* signed_pre_key_store_new(void);
 void identity_key_store_new(identity_key_store_t* identity_key_store);
+void identity_key_store_destroy(identity_key_store_t* identity_key_store);
 
 /**
  * Returns a copy of the serialized session record corresponding to the
diff --git a/src/profanity.c b/src/profanity.c
index 49adc4a0..869ab561 100644
--- a/src/profanity.c
+++ b/src/profanity.c
@@ -175,7 +175,8 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name)
 
     pthread_mutex_lock(&lock);
     files_create_directories();
-    log_level_t prof_log_level = log_level_from_string(log_level);
+    log_level_t prof_log_level;
+    log_level_from_string(log_level, &prof_log_level);
     prefs_load(config_file);
     log_init(prof_log_level, log_file);
     log_stderr_init(PROF_LEVEL_ERROR);
diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c
index 9450b98f..2f1acc1f 100644
--- a/src/tools/autocomplete.c
+++ b/src/tools/autocomplete.c
@@ -367,34 +367,20 @@ char*
 autocomplete_param_no_with_func(const char* const input, char* command, int arg_number, autocomplete_func func, gboolean previous, void* context)
 {
     if (strncmp(input, command, strlen(command)) == 0) {
-        GString* result_str = NULL;
-
         // count tokens properly
         int num_tokens = count_tokens(input);
 
         // if correct number of tokens, then candidate for autocompletion of last param
         if (num_tokens == arg_number) {
-            gchar* start_str = get_start(input, arg_number);
-            gchar* comp_str = g_strdup(&input[strlen(start_str)]);
+            auto_gchar gchar* start_str = get_start(input, arg_number);
+            auto_gchar gchar* comp_str = g_strdup(&input[strlen(start_str)]);
 
             // autocomplete param
             if (comp_str) {
-                char* found = func(comp_str, previous, context);
+                auto_gchar gchar* found = func(comp_str, previous, context);
                 if (found) {
-                    result_str = g_string_new("");
-                    g_string_append(result_str, start_str);
-                    g_string_append(result_str, found);
-
-                    free(start_str);
-                    free(comp_str);
-
-                    char* result = result_str->str;
-                    g_string_free(result_str, FALSE);
-
-                    return result;
+                    return g_strdup_printf("%s%s", start_str, found);
                 }
-            } else {
-                free(start_str);
             }
         }
     }
@@ -418,14 +404,12 @@ autocomplete_remove_older_than_max_reverse(Autocomplete ac, int maxsize)
 static gchar*
 _search(Autocomplete ac, GList* curr, gboolean quote, search_direction direction)
 {
-    gchar* search_str_ascii = g_str_to_ascii(ac->search_str, NULL);
-    gchar* search_str_lower = g_ascii_strdown(search_str_ascii, -1);
-    g_free(search_str_ascii);
+    auto_gchar gchar* search_str_ascii = g_str_to_ascii(ac->search_str, NULL);
+    auto_gchar gchar* search_str_lower = g_ascii_strdown(search_str_ascii, -1);
 
     while (curr) {
-        gchar* curr_ascii = g_str_to_ascii(curr->data, NULL);
-        gchar* curr_lower = g_ascii_strdown(curr_ascii, -1);
-        g_free(curr_ascii);
+        auto_gchar gchar* curr_ascii = g_str_to_ascii(curr->data, NULL);
+        auto_gchar gchar* curr_lower = g_ascii_strdown(curr_ascii, -1);
 
         // match found
         if (strncmp(curr_lower, search_str_lower, strlen(search_str_lower)) == 0) {
@@ -435,27 +419,13 @@ _search(Autocomplete ac, GList* curr, gboolean quote, search_direction direction
 
             // if contains space, quote before returning
             if (quote && g_strrstr(curr->data, " ")) {
-                GString* quoted = g_string_new("\"");
-                g_string_append(quoted, curr->data);
-                g_string_append(quoted, "\"");
-
-                gchar* result = quoted->str;
-                g_string_free(quoted, FALSE);
-
-                g_free(search_str_lower);
-                g_free(curr_lower);
-                return result;
-
+                return g_strdup_printf("\"%s\"", (gchar*)curr->data);
                 // otherwise just return the string
             } else {
-                g_free(search_str_lower);
-                g_free(curr_lower);
                 return strdup(curr->data);
             }
         }
 
-        g_free(curr_lower);
-
         if (direction == PREVIOUS) {
             curr = g_list_previous(curr);
         } else {
@@ -463,6 +433,5 @@ _search(Autocomplete ac, GList* curr, gboolean quote, search_direction direction
         }
     }
 
-    g_free(search_str_lower);
     return NULL;
 }
diff --git a/src/tools/editor.c b/src/tools/editor.c
index 4ac88a95..350fb5b1 100644
--- a/src/tools/editor.c
+++ b/src/tools/editor.c
@@ -56,7 +56,7 @@ get_message_from_editor(gchar* message, gchar** returned_message)
 
     gchar* filename = NULL;
     GError* glib_error = NULL;
-    char* jid = connection_get_barejid();
+    auto_char char* jid = connection_get_barejid();
     if (jid) {
         filename = files_file_in_account_data_path(DIR_EDITOR, jid, "compose.md");
     } else {
diff --git a/src/ui/console.c b/src/ui/console.c
index 5937a42a..b1720415 100644
--- a/src/ui/console.c
+++ b/src/ui/console.c
@@ -2311,6 +2311,7 @@ cons_show_connection_prefs(void)
     cons_autoping_setting();
     cons_autoconnect_setting();
     cons_rooms_cache_setting();
+    cons_strophe_setting();
 
     cons_alert(NULL);
 }
@@ -2994,3 +2995,18 @@ cons_mood_setting(void)
         cons_show("Display user mood (/mood)                 : OFF");
     }
 }
+
+void
+cons_strophe_setting(void)
+{
+    const char* sm_setting = "OFF";
+    if (prefs_get_boolean(PREF_STROPHE_SM_ENABLED)) {
+        if (prefs_get_boolean(PREF_STROPHE_SM_RESEND)) {
+            sm_setting = "ON";
+        } else {
+            sm_setting = "NO-RESEND";
+        }
+    }
+    cons_show("XEP-0198 Stream-Management                : %s", sm_setting);
+    cons_show("libstrophe Verbosity                      : %s", prefs_get_string(PREF_STROPHE_VERBOSITY));
+}
diff --git a/src/ui/ui.h b/src/ui/ui.h
index 94d1c716..d9534ed5 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -341,6 +341,7 @@ void cons_slashguard_setting(void);
 void cons_mam_setting(void);
 void cons_silence_setting(void);
 void cons_mood_setting(void);
+void cons_strophe_setting(void);
 void cons_show_contact_online(PContact contact, Resource* resource, GDateTime* last_activity);
 void cons_show_contact_offline(PContact contact, char* resource, char* status);
 void cons_theme_properties(void);
diff --git a/src/ui/window.c b/src/ui/window.c
index 18445f57..9d7b779e 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -1470,7 +1470,7 @@ win_print_outgoing(ProfWin* window, const char* show_char, const char* const id,
     if (replace_id) {
         _win_correct(window, message, id, replace_id, myjid);
     } else {
-        char* outgoing_str = prefs_get_string(PREF_OUTGOING_STAMP);
+        auto_char gchar* outgoing_str = prefs_get_string(PREF_OUTGOING_STAMP);
         _win_printf(window, show_char, 0, timestamp, 0, THEME_TEXT_ME, outgoing_str, myjid, id, "%s", message);
     }
 
diff --git a/src/xmpp/chat_session.c b/src/xmpp/chat_session.c
index f62f090c..56a782f1 100644
--- a/src/xmpp/chat_session.c
+++ b/src/xmpp/chat_session.c
@@ -120,11 +120,11 @@ chat_session_get_jid(const char* const barejid)
     return jid;
 }
 
-char*
+const char*
 chat_session_get_state(const char* const barejid)
 {
     ChatSession* session = chat_session_get(barejid);
-    char* state = NULL;
+    const char* state = NULL;
     if (session) {
         if (prefs_get_boolean(PREF_STATES) && session->send_states) {
             state = STANZA_NAME_ACTIVE;
diff --git a/src/xmpp/chat_session.h b/src/xmpp/chat_session.h
index e0144874..619750e4 100644
--- a/src/xmpp/chat_session.h
+++ b/src/xmpp/chat_session.h
@@ -59,7 +59,7 @@ void chat_session_recipient_paused(const char* const barejid, const char* const
 void chat_session_recipient_gone(const char* const barejid, const char* const resource);
 void chat_session_recipient_inactive(const char* const barejid, const char* const resource);
 char* chat_session_get_jid(const char* const barejid);
-char* chat_session_get_state(const char* const barejid);
+const char* chat_session_get_state(const char* const barejid);
 
 void chat_session_remove(const char* const barejid);
 
diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c
index 2de4a842..d57a1376 100644
--- a/src/xmpp/connection.c
+++ b/src/xmpp/connection.c
@@ -140,6 +140,14 @@ connection_init(void)
     conn.requested_features = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
 
     conn.xmpp_ctx = xmpp_ctx_new(&prof_mem, &prof_log);
+    auto_gchar gchar* v = prefs_get_string(PREF_STROPHE_VERBOSITY);
+    auto_gchar gchar* err_msg = NULL;
+    int verbosity;
+    if (string_to_verbosity(v, &verbosity, &err_msg)) {
+        xmpp_ctx_set_verbosity(conn.xmpp_ctx, verbosity);
+    } else {
+        cons_show(err_msg);
+    }
     conn.xmpp_conn = xmpp_conn_new(conn.xmpp_ctx);
 
     _random_bytes_init();
@@ -1000,13 +1008,15 @@ _connection_handler(xmpp_conn_t* const xmpp_conn, const xmpp_conn_event_t status
 
         // lost connection for unknown reason
         if (conn.conn_status == JABBER_CONNECTED) {
-            int send_queue_len = xmpp_conn_send_queue_len(conn.xmpp_conn);
-            log_debug("Connection handler: Lost connection for unknown reason");
-            conn.sm_state = xmpp_conn_get_sm_state(conn.xmpp_conn);
-            if (send_queue_len > 0) {
-                conn.queued_messages = calloc(send_queue_len + 1, sizeof(*conn.queued_messages));
-                for (int n = 0; n < send_queue_len && conn.queued_messages[n]; ++n) {
-                    conn.queued_messages[n] = xmpp_conn_send_queue_drop_element(conn.xmpp_conn, XMPP_QUEUE_OLDEST);
+            if (prefs_get_boolean(PREF_STROPHE_SM_ENABLED)) {
+                int send_queue_len = xmpp_conn_send_queue_len(conn.xmpp_conn);
+                log_debug("Connection handler: Lost connection for unknown reason");
+                conn.sm_state = xmpp_conn_get_sm_state(conn.xmpp_conn);
+                if (send_queue_len > 0 && prefs_get_boolean(PREF_STROPHE_SM_RESEND)) {
+                    conn.queued_messages = calloc(send_queue_len + 1, sizeof(*conn.queued_messages));
+                    for (int n = 0; n < send_queue_len && conn.queued_messages[n]; ++n) {
+                        conn.queued_messages[n] = xmpp_conn_send_queue_drop_element(conn.xmpp_conn, XMPP_QUEUE_OLDEST);
+                    }
                 }
             }
             session_lost_connection();
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index 4d0ee281..89511176 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -2187,6 +2187,7 @@ _room_info_response_id_handler(xmpp_stanza_t* const stanza, void* const userdata
                             identity->name = strdup(name);
                             ProfMucWin* mucwin = wins_get_muc(cb_data->room);
                             if (mucwin) {
+                                free(mucwin->room_name);
                                 mucwin->room_name = strdup(name);
                             }
                         } else {
@@ -2607,6 +2608,8 @@ _mam_buffer_commit_handler(xmpp_stanza_t* const stanza, void* const userdata)
     return 0;
 }
 
+static const gchar* mam_timestamp_format_string = "%FT%T.%f%:z";
+
 void
 iq_mam_request_older(ProfChatWin* win)
 {
@@ -2623,7 +2626,7 @@ iq_mam_request_older(ProfChatWin* win)
     // If first message found
     if (first_msg->timestamp) {
         firstid = first_msg->stanzaid;
-        enddate = g_date_time_format(first_msg->timestamp, "%FT%T.%f%:z");
+        enddate = g_date_time_format(first_msg->timestamp, mam_timestamp_format_string);
     } else {
         return;
     }
@@ -2647,6 +2650,8 @@ _iq_mam_request(ProfChatWin* win, GDateTime* startdate, GDateTime* enddate)
     if (connection_supports(XMPP_FEATURE_MAM2) == FALSE) {
         log_warning("Server doesn't advertise %s feature.", XMPP_FEATURE_MAM2);
         cons_show_error("Server doesn't support MAM (%s).", XMPP_FEATURE_MAM2);
+        g_date_time_unref(startdate);
+        g_date_time_unref(enddate);
         return;
     }
 
@@ -2656,18 +2661,18 @@ _iq_mam_request(ProfChatWin* win, GDateTime* startdate, GDateTime* enddate)
     gboolean fetch_next = FALSE;
 
     if (startdate) {
-        startdate_str = g_date_time_format(startdate, "%FT%T.%f%:z");
+        startdate_str = g_date_time_format(startdate, mam_timestamp_format_string);
         fetch_next = TRUE;
         g_date_time_unref(startdate);
-    } else if (!enddate) {
-        GDateTime* now = g_date_time_new_now_utc();
-        enddate_str = g_date_time_format(now, "%FT%T.%f%:z");
-        g_date_time_unref(now);
     }
 
     if (enddate) {
-        enddate_str = g_date_time_format(enddate, "%FT%T.%f%:z");
+        enddate_str = g_date_time_format(enddate, mam_timestamp_format_string);
         g_date_time_unref(enddate);
+    } else {
+        GDateTime* now = g_date_time_new_now_utc();
+        enddate_str = g_date_time_format(now, mam_timestamp_format_string);
+        g_date_time_unref(now);
     }
 
     xmpp_ctx_t* const ctx = connection_get_ctx();
@@ -2695,15 +2700,15 @@ void
 iq_mam_request(ProfChatWin* win, GDateTime* enddate)
 {
     ProfMessage* last_msg = log_database_get_limits_info(win->barejid, TRUE);
-    GDateTime* startdate = last_msg->timestamp ? g_date_time_add_seconds(last_msg->timestamp, 0) : NULL; // copy timestamp
+    GDateTime* startdate = g_date_time_add_seconds(last_msg->timestamp, 0);
     message_free(last_msg);
 
     // Save request for later if disco items haven't been received yet
     if (!received_disco_items) {
         LateDeliveryUserdata* cur_del_data = malloc(sizeof(LateDeliveryUserdata));
         cur_del_data->win = win;
-        cur_del_data->enddate = enddate;
-        cur_del_data->startdate = startdate;
+        cur_del_data->enddate = g_date_time_ref(enddate);
+        cur_del_data->startdate = g_date_time_ref(startdate);
         late_delivery_windows = g_slist_append(late_delivery_windows, cur_del_data);
     }
 
diff --git a/src/xmpp/jid.c b/src/xmpp/jid.c
index 33c3d19f..af0a606b 100644
--- a/src/xmpp/jid.c
+++ b/src/xmpp/jid.c
@@ -76,6 +76,7 @@ jid_create(const gchar* const str)
     result->resourcepart = NULL;
     result->barejid = NULL;
     result->fulljid = NULL;
+    result->refcnt = 1;
 
     gchar* atp = g_utf8_strchr(trimmed, -1, '@');
     gchar* slashp = g_utf8_strchr(trimmed, -1, '/');
@@ -120,11 +121,29 @@ jid_create_from_bare_and_resource(const char* const barejid, const char* const r
 }
 
 void
+jid_auto_destroy(Jid** jid)
+{
+    if (jid == NULL)
+        return;
+    jid_destroy(*jid);
+}
+
+void
+jid_ref(Jid* jid)
+{
+    jid->refcnt++;
+}
+
+void
 jid_destroy(Jid* jid)
 {
     if (jid == NULL) {
         return;
     }
+    if (jid->refcnt > 1) {
+        jid->refcnt--;
+        return;
+    }
 
     g_free(jid->str);
     g_free(jid->localpart);
diff --git a/src/xmpp/jid.h b/src/xmpp/jid.h
index dae6cb2d..e55ea0c7 100644
--- a/src/xmpp/jid.h
+++ b/src/xmpp/jid.h
@@ -40,6 +40,7 @@
 
 struct jid_t
 {
+    unsigned int refcnt;
     char* str;
     char* localpart;
     char* domainpart;
@@ -53,6 +54,10 @@ typedef struct jid_t Jid;
 Jid* jid_create(const gchar* const str);
 Jid* jid_create_from_bare_and_resource(const char* const barejid, const char* const resource);
 void jid_destroy(Jid* jid);
+void jid_ref(Jid* jid);
+
+void jid_auto_destroy(Jid** str);
+#define auto_jid __attribute__((__cleanup__(jid_auto_destroy)))
 
 gboolean jid_is_valid_room_form(Jid* jid);
 char* create_fulljid(const char* const barejid, const char* const resource);
diff --git a/src/xmpp/message.c b/src/xmpp/message.c
index 306b9be7..bc716b24 100644
--- a/src/xmpp/message.c
+++ b/src/xmpp/message.c
@@ -424,7 +424,7 @@ message_send_chat(const char* const barejid, const char* const msg, const char*
 {
     xmpp_ctx_t* const ctx = connection_get_ctx();
 
-    char* state = chat_session_get_state(barejid);
+    const char* state = chat_session_get_state(barejid);
     char* jid = chat_session_get_jid(barejid);
     char* id = connection_create_stanza_id();
 
@@ -459,7 +459,7 @@ message_send_chat_pgp(const char* const barejid, const char* const msg, gboolean
 {
     xmpp_ctx_t* const ctx = connection_get_ctx();
 
-    char* state = chat_session_get_state(barejid);
+    const char* state = chat_session_get_state(barejid);
     char* jid = chat_session_get_jid(barejid);
     char* id = connection_create_stanza_id();
 
@@ -468,7 +468,7 @@ message_send_chat_pgp(const char* const barejid, const char* const msg, gboolean
     char* account_name = session_get_account_name();
     ProfAccount* account = accounts_get_account(account_name);
     if (account->pgp_keyid) {
-        Jid* jidp = jid_create(jid);
+        auto_jid Jid* jidp = jid_create(jid);
         char* encrypted = p_gpg_encrypt(jidp->barejid, msg, account->pgp_keyid);
         if (encrypted) {
             message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
@@ -487,7 +487,6 @@ message_send_chat_pgp(const char* const barejid, const char* const msg, gboolean
             message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
             xmpp_message_set_body(message, msg);
         }
-        jid_destroy(jidp);
     } else {
         message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
         xmpp_message_set_body(message, msg);
@@ -525,12 +524,11 @@ message_send_chat_ox(const char* const barejid, const char* const msg, gboolean
 #ifdef HAVE_LIBGPGME
     xmpp_ctx_t* const ctx = connection_get_ctx();
 
-    char* state = chat_session_get_state(barejid);
-    char* jid = chat_session_get_jid(barejid);
+    const char* state = chat_session_get_state(barejid);
+    auto_char char* jid = chat_session_get_jid(barejid);
     char* id = connection_create_stanza_id();
 
     xmpp_stanza_t* message = NULL;
-    Jid* jidp = jid_create(jid);
 
     char* account_name = session_get_account_name();
     ProfAccount* account = accounts_get_account(account_name);
@@ -561,8 +559,6 @@ message_send_chat_ox(const char* const barejid, const char* const msg, gboolean
     xmpp_stanza_to_text(message, &c, &s);
 
     account_free(account);
-    jid_destroy(jidp);
-    free(jid);
 
     if (state) {
         stanza_attach_state(ctx, message, state);
@@ -589,7 +585,7 @@ message_send_chat_otr(const char* const barejid, const char* const msg, gboolean
 {
     xmpp_ctx_t* const ctx = connection_get_ctx();
 
-    char* state = chat_session_get_state(barejid);
+    const char* state = chat_session_get_state(barejid);
     char* jid = chat_session_get_jid(barejid);
     char* id = connection_create_stanza_id();
 
@@ -627,7 +623,7 @@ message_send_chat_omemo(const char* const jid, uint32_t sid, GList* keys,
                         const unsigned char* const ciphertext, size_t ciphertext_len,
                         gboolean request_receipt, gboolean muc, const char* const replace_id)
 {
-    char* state = chat_session_get_state(jid);
+    const char* state = chat_session_get_state(jid);
     xmpp_ctx_t* const ctx = connection_get_ctx();
     char* id;
     xmpp_stanza_t* message;
@@ -888,10 +884,9 @@ _handle_error(xmpp_stanza_t* const stanza)
         ui_handle_error(err_msg);
     } else {
         if (type && (strcmp(type, "cancel") == 0)) {
-            Jid* jidp = jid_create(jid);
+            auto_jid Jid* jidp = jid_create(jid);
             if (jidp) {
                 chat_session_remove(jidp->barejid);
-                jid_destroy(jidp);
             }
         }
         ui_handle_recipient_error(jid, err_msg);
@@ -928,7 +923,7 @@ _handle_muc_user(xmpp_stanza_t* const stanza)
         return;
     }
 
-    Jid* jidp = jid_create(invitor_jid);
+    auto_jid Jid* jidp = jid_create(invitor_jid);
     if (!jidp) {
         return;
     }
@@ -947,7 +942,6 @@ _handle_muc_user(xmpp_stanza_t* const stanza)
     }
 
     sv_ev_room_invite(INVITE_MEDIATED, invitor, room, reason, password);
-    jid_destroy(jidp);
     if (reason) {
         xmpp_free(ctx, reason);
     }
@@ -974,7 +968,7 @@ _handle_conference(xmpp_stanza_t* const stanza)
             return;
         }
 
-        Jid* jidp = jid_create(from);
+        auto_jid Jid* jidp = jid_create(from);
         if (!jidp) {
             return;
         }
@@ -984,7 +978,6 @@ _handle_conference(xmpp_stanza_t* const stanza)
         const char* password = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_PASSWORD);
 
         sv_ev_room_invite(INVITE_DIRECT, jidp->barejid, room, reason, password);
-        jid_destroy(jidp);
     }
 }
 
@@ -1040,7 +1033,7 @@ _handle_groupchat(xmpp_stanza_t* const stanza)
     if (!room_jid) {
         return;
     }
-    Jid* from_jid = jid_create(room_jid);
+    auto_jid Jid* from_jid = jid_create(room_jid);
     if (!from_jid) {
         return;
     }
@@ -1053,7 +1046,6 @@ _handle_groupchat(xmpp_stanza_t* const stanza)
         sv_ev_room_subject(from_jid->barejid, from_jid->resourcepart, subject_text);
         xmpp_free(ctx, subject_text);
 
-        jid_destroy(from_jid);
         return;
     }
 
@@ -1084,31 +1076,28 @@ _handle_groupchat(xmpp_stanza_t* const stanza)
                 }
             }
 
-            jid_destroy(from_jid);
             return;
         }
 
         sv_ev_room_broadcast(room_jid, broadcast);
         xmpp_free(ctx, broadcast);
 
-        jid_destroy(from_jid);
         return;
     }
 
     if (!jid_is_valid_room_form(from_jid)) {
         log_error("Invalid room JID: %s", from_jid->str);
-        jid_destroy(from_jid);
         return;
     }
 
     // room not active in profanity
     if (!muc_active(from_jid->barejid)) {
         log_error("Message received for inactive chat room: %s", from_jid->str);
-        jid_destroy(from_jid);
         return;
     }
 
     ProfMessage* message = message_init();
+    jid_ref(from_jid);
     message->from_jid = from_jid;
     message->type = PROF_MSG_TYPE_MUC;
 
@@ -1234,13 +1223,12 @@ _handle_receipt_received(xmpp_stanza_t* const stanza)
             return;
         }
 
-        Jid* jidp = jid_create(fulljid);
+        auto_jid Jid* jidp = jid_create(fulljid);
         if (!jidp) {
             return;
         }
 
         sv_ev_message_receipt(jidp->barejid, id);
-        jid_destroy(jidp);
     }
 }
 
@@ -1268,10 +1256,9 @@ _receipt_request_handler(xmpp_stanza_t* const stanza)
 
     const gchar* from = xmpp_stanza_get_from(stanza);
     if (from) {
-        Jid* jid = jid_create(from);
+        auto_jid Jid* jid = jid_create(from);
         if (jid) {
             _message_send_receipt(jid->fulljid, id);
-            jid_destroy(jid);
         }
     }
 }
@@ -1388,7 +1375,7 @@ _handle_chat(xmpp_stanza_t* const stanza, gboolean is_mam, gboolean is_carbon, c
     if (!from) {
         return;
     }
-    Jid* jid = jid_create(from);
+    auto_jid Jid* jid = jid_create(from);
     if (!jid) {
         return;
     }
@@ -1396,13 +1383,13 @@ _handle_chat(xmpp_stanza_t* const stanza, gboolean is_mam, gboolean is_carbon, c
     // private message from chat room use full jid (room/nick)
     if (muc_active(jid->barejid)) {
         _handle_muc_private_message(stanza);
-        jid_destroy(jid);
         return;
     }
 
     // standard chat message, use jid without resource
     ProfMessage* message = message_init();
     message->is_mam = is_mam;
+    jid_ref(jid);
     message->from_jid = jid;
     const gchar* to = xmpp_stanza_get_to(stanza);
     if (to) {
@@ -1761,9 +1748,8 @@ _should_ignore_based_on_silence(xmpp_stanza_t* const stanza)
 {
     if (prefs_get_boolean(PREF_SILENCE_NON_ROSTER)) {
         const char* const from = xmpp_stanza_get_from(stanza);
-        Jid* from_jid = jid_create(from);
+        auto_jid Jid* from_jid = jid_create(from);
         PContact contact = roster_get_contact(from_jid->barejid);
-        jid_destroy(from_jid);
         if (!contact) {
             log_debug("[Silence] Ignoring message from: %s", from);
             return TRUE;
diff --git a/src/xmpp/session.c b/src/xmpp/session.c
index 3bec1ab2..c4ea3f24 100644
--- a/src/xmpp/session.c
+++ b/src/xmpp/session.c
@@ -96,8 +96,6 @@ static activity_state_t activity_state;
 static resource_presence_t saved_presence;
 static char* saved_status;
 
-static void _session_reconnect(void);
-
 static void _session_free_internals(void);
 static void _session_free_saved_details(void);
 
@@ -268,12 +266,12 @@ session_process_events(void)
         if ((reconnect_sec != 0) && reconnect_timer) {
             int elapsed_sec = g_timer_elapsed(reconnect_timer, NULL);
             if (elapsed_sec > reconnect_sec) {
-                _session_reconnect();
+                session_reconnect_now();
             }
         }
         break;
     case JABBER_RECONNECT:
-        _session_reconnect();
+        session_reconnect_now();
         break;
     default:
         break;
@@ -307,7 +305,7 @@ _receive_mood(xmpp_stanza_t* const stanza, void* const userdata)
                         const char* m = xmpp_stanza_get_name(c);
                         xmpp_stanza_t* t = xmpp_stanza_get_child_by_name(mood, STANZA_NAME_TEXT);
                         if (t) {
-                            const char* text = xmpp_stanza_get_text(t);
+                            auto_char char* text = xmpp_stanza_get_text(t);
                             cons_show("Mood from %s %s (%s)", from, m, text);
                         } else {
                             cons_show("Mood from %s %s", from, m);
@@ -557,8 +555,8 @@ session_reconnect(gchar* altdomain, unsigned short altport)
     reconnect.altport = altport;
 }
 
-static void
-_session_reconnect(void)
+void
+session_reconnect_now(void)
 {
     // reconnect with account.
     ProfAccount* account = accounts_get_account(saved_account.name);
diff --git a/src/xmpp/session.h b/src/xmpp/session.h
index d8565fa4..e6facb93 100644
--- a/src/xmpp/session.h
+++ b/src/xmpp/session.h
@@ -47,5 +47,6 @@ void session_init_activity(void);
 void session_check_autoaway(void);
 
 void session_reconnect(gchar* altdomain, unsigned short altport);
+void session_reconnect_now(void);
 
 #endif
diff --git a/tests/unittests/log/stub_log.c b/tests/unittests/log/stub_log.c
index dfa2619a..18d05eca 100644
--- a/tests/unittests/log/stub_log.c
+++ b/tests/unittests/log/stub_log.c
@@ -67,10 +67,10 @@ get_log_file_location(void)
     return mock_ptr_type(char*);
 }
 
-log_level_t
-log_level_from_string(char* log_level)
+int
+log_level_from_string(char* log_level, log_level_t* level)
 {
-    return mock_type(log_level_t);
+    return mock_type(int);
 }
 
 void
diff --git a/tests/unittests/test_cmd_account.c b/tests/unittests/test_cmd_account.c
index 04215e88..57949470 100644
--- a/tests/unittests/test_cmd_account.c
+++ b/tests/unittests/test_cmd_account.c
@@ -33,7 +33,7 @@ cmd_account_shows_usage_when_not_connected_and_no_args(void** state)
 void
 cmd_account_shows_account_when_connected_and_no_args(void** state)
 {
-    ProfAccount* account = account_new("jabber_org", "me@jabber.org", NULL, NULL,
+    ProfAccount* account = account_new(g_strdup("jabber_org"), g_strdup("me@jabber.org"), NULL, NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
     gchar* args[] = { NULL };
 
@@ -97,7 +97,7 @@ void
 cmd_account_show_shows_account_when_exists(void** state)
 {
     gchar* args[] = { "show", "account_name", NULL };
-    ProfAccount* account = account_new("jabber_org", "me@jabber.org", NULL, NULL,
+    ProfAccount* account = account_new(g_strdup("jabber_org"), g_strdup("me@jabber.org"), NULL, NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     expect_any(accounts_get_account, name);
@@ -436,7 +436,7 @@ void
 cmd_account_set_password_sets_password(void** state)
 {
     gchar* args[] = { "set", "a_account", "password", "a_password", NULL };
-    ProfAccount* account = account_new("a_account", NULL, NULL, NULL,
+    ProfAccount* account = account_new(g_strdup("a_account"), NULL, NULL, NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     expect_any(accounts_account_exists, account_name);
@@ -459,7 +459,7 @@ void
 cmd_account_set_eval_password_sets_eval_password(void** state)
 {
     gchar* args[] = { "set", "a_account", "eval_password", "a_password", NULL };
-    ProfAccount* account = account_new("a_account", NULL, NULL, NULL,
+    ProfAccount* account = account_new(g_strdup("a_account"), NULL, NULL, NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     expect_any(accounts_account_exists, account_name);
@@ -482,7 +482,7 @@ void
 cmd_account_set_password_when_eval_password_set(void** state)
 {
     gchar* args[] = { "set", "a_account", "password", "a_password", NULL };
-    ProfAccount* account = account_new("a_account", NULL, NULL, "a_password",
+    ProfAccount* account = account_new(g_strdup("a_account"), NULL, NULL, g_strdup("a_password"),
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     expect_any(accounts_account_exists, account_name);
@@ -501,7 +501,7 @@ void
 cmd_account_set_eval_password_when_password_set(void** state)
 {
     gchar* args[] = { "set", "a_account", "eval_password", "a_password", NULL };
-    ProfAccount* account = account_new("a_account", NULL, "a_password", NULL,
+    ProfAccount* account = account_new(g_strdup("a_account"), NULL, g_strdup("a_password"), NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     expect_any(accounts_account_exists, account_name);
@@ -852,7 +852,7 @@ cmd_account_set_priority_updates_presence_when_account_connected_with_presence(v
     will_return(session_get_account_name, "a_account");
 
 #ifdef HAVE_LIBGPGME
-    ProfAccount* account = account_new("a_account", "a_jid", NULL, NULL, TRUE, NULL, 5222, "a_resource",
+    ProfAccount* account = account_new(g_strdup("a_account"), g_strdup("a_jid"), NULL, NULL, TRUE, NULL, 5222, g_strdup("a_resource"),
                                        NULL, NULL, 10, 10, 10, 10, 10, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     will_return(session_get_account_name, "a_account");
diff --git a/tests/unittests/test_cmd_connect.c b/tests/unittests/test_cmd_connect.c
index d167a5e9..0f6480a0 100644
--- a/tests/unittests/test_cmd_connect.c
+++ b/tests/unittests/test_cmd_connect.c
@@ -123,7 +123,7 @@ void
 cmd_connect_lowercases_argument_with_account(void** state)
 {
     gchar* args[] = { "Jabber_org", NULL };
-    ProfAccount* account = account_new("Jabber_org", "me@jabber.org", "password", NULL,
+    ProfAccount* account = account_new(g_strdup("Jabber_org"), g_strdup("me@jabber.org"), g_strdup("password"), NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     will_return(connection_get_status, JABBER_DISCONNECTED);
@@ -144,7 +144,7 @@ void
 cmd_connect_asks_password_when_not_in_account(void** state)
 {
     gchar* args[] = { "jabber_org", NULL };
-    ProfAccount* account = account_new("jabber_org", "me@jabber.org", NULL, NULL,
+    ProfAccount* account = account_new(g_strdup("jabber_org"), g_strdup("me@jabber.org"), NULL, NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     will_return(connection_get_status, JABBER_DISCONNECTED);
@@ -407,8 +407,8 @@ void
 cmd_connect_shows_message_when_connecting_with_account(void** state)
 {
     gchar* args[] = { "jabber_org", NULL };
-    ProfAccount* account = account_new("jabber_org", "user@jabber.org", "password", NULL,
-                                       TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    ProfAccount* account = account_new(g_strdup("jabber_org"), g_strdup("user@jabber.org"), g_strdup("password"), NULL,
+                                       TRUE, NULL, 0, g_strdup("laptop"), NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     will_return(connection_get_status, JABBER_DISCONNECTED);
 
@@ -428,7 +428,7 @@ void
 cmd_connect_connects_with_account(void** state)
 {
     gchar* args[] = { "jabber_org", NULL };
-    ProfAccount* account = account_new("jabber_org", "me@jabber.org", "password", NULL,
+    ProfAccount* account = account_new(g_strdup("jabber_org"), g_strdup("me@jabber.org"), g_strdup("password"), NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     will_return(connection_get_status, JABBER_DISCONNECTED);
diff --git a/tests/unittests/test_cmd_join.c b/tests/unittests/test_cmd_join.c
index 92766cea..cd187b07 100644
--- a/tests/unittests/test_cmd_join.c
+++ b/tests/unittests/test_cmd_join.c
@@ -64,14 +64,14 @@ cmd_join_shows_error_message_when_invalid_room_jid(void** state)
 void
 cmd_join_uses_account_mucservice_when_no_service_specified(void** state)
 {
-    char* account_name = "an_account";
+    char* account_name = g_strdup("an_account");
     char* room = "room";
     char* nick = "bob";
-    char* account_service = "conference.server.org";
+    char* account_service = g_strdup("conference.server.org");
     char* expected_room = "room@conference.server.org";
     gchar* args[] = { room, "nick", nick, NULL };
-    ProfAccount* account = account_new(account_name, "user@server.org", NULL, NULL,
-                                       TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, account_service, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    ProfAccount* account = account_new(account_name, g_strdup("user@server.org"), NULL, NULL,
+                                       TRUE, NULL, 0, g_strdup("laptop"), NULL, NULL, 0, 0, 0, 0, 0, account_service, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     muc_init();
 
@@ -94,12 +94,12 @@ cmd_join_uses_account_mucservice_when_no_service_specified(void** state)
 void
 cmd_join_uses_supplied_nick(void** state)
 {
-    char* account_name = "an_account";
+    char* account_name = g_strdup("an_account");
     char* room = "room@conf.server.org";
     char* nick = "bob";
     gchar* args[] = { room, "nick", nick, NULL };
-    ProfAccount* account = account_new(account_name, "user@server.org", NULL, NULL,
-                                       TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    ProfAccount* account = account_new(account_name, g_strdup("user@server.org"), NULL, NULL,
+                                       TRUE, NULL, 0, g_strdup("laptop"), NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     muc_init();
 
@@ -122,12 +122,12 @@ cmd_join_uses_supplied_nick(void** state)
 void
 cmd_join_uses_account_nick_when_not_supplied(void** state)
 {
-    char* account_name = "an_account";
+    char* account_name = g_strdup("an_account");
     char* room = "room2@conf.server.org";
-    char* account_nick = "a_nick";
+    char* account_nick = g_strdup("a_nick");
     gchar* args[] = { room, NULL };
-    ProfAccount* account = account_new(account_name, "user@server.org", NULL, NULL,
-                                       TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, account_nick, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    ProfAccount* account = account_new(account_name, g_strdup("user@server.org"), NULL, NULL,
+                                       TRUE, NULL, 0, g_strdup("laptop"), NULL, NULL, 0, 0, 0, 0, 0, NULL, account_nick, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     muc_init();
 
@@ -150,15 +150,15 @@ cmd_join_uses_account_nick_when_not_supplied(void** state)
 void
 cmd_join_uses_password_when_supplied(void** state)
 {
-    char* account_name = "an_account";
+    char* account_name = g_strdup("an_account");
     char* room = "room";
     char* password = "a_password";
-    char* account_nick = "a_nick";
-    char* account_service = "a_service";
+    char* account_nick = g_strdup("a_nick");
+    char* account_service = g_strdup("a_service");
     char* expected_room = "room@a_service";
     gchar* args[] = { room, "password", password, NULL };
-    ProfAccount* account = account_new(account_name, "user@server.org", NULL, NULL,
-                                       TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, account_service, account_nick, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    ProfAccount* account = account_new(account_name, g_strdup("user@server.org"), NULL, NULL,
+                                       TRUE, NULL, 0, g_strdup("laptop"), NULL, NULL, 0, 0, 0, 0, 0, account_service, account_nick, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     muc_init();
 
diff --git a/tests/unittests/test_cmd_otr.c b/tests/unittests/test_cmd_otr.c
index 9fd822ae..ccd219de 100644
--- a/tests/unittests/test_cmd_otr.c
+++ b/tests/unittests/test_cmd_otr.c
@@ -194,8 +194,8 @@ void
 cmd_otr_gen_generates_key_for_connected_account(void** state)
 {
     gchar* args[] = { "gen", NULL };
-    char* account_name = "myaccount";
-    ProfAccount* account = account_new(account_name, "me@jabber.org", NULL, NULL,
+    char* account_name = g_strdup("myaccount");
+    ProfAccount* account = account_new(account_name, g_strdup("me@jabber.org"), NULL, NULL,
                                        TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     will_return(connection_get_status, JABBER_CONNECTED);
diff --git a/tests/unittests/test_cmd_rooms.c b/tests/unittests/test_cmd_rooms.c
index 22c16435..10e8bf2f 100644
--- a/tests/unittests/test_cmd_rooms.c
+++ b/tests/unittests/test_cmd_rooms.c
@@ -50,8 +50,8 @@ cmd_rooms_uses_account_default_when_no_arg(void** state)
 {
     gchar* args[] = { NULL };
 
-    ProfAccount* account = account_new("testaccount", NULL, NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL,
-                                       0, 0, 0, 0, 0, "default_conf_server", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    ProfAccount* account = account_new(g_strdup("testaccount"), NULL, NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL,
+                                       0, 0, 0, 0, 0, g_strdup("default_conf_server"), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     will_return(connection_get_status, JABBER_CONNECTED);
     will_return(session_get_account_name, "account_name");
@@ -90,8 +90,8 @@ cmd_rooms_filter_arg_used_when_passed(void** state)
 {
     gchar* args[] = { "filter", "text", NULL };
 
-    ProfAccount* account = account_new("testaccount", NULL, NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL,
-                                       0, 0, 0, 0, 0, "default_conf_server", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    ProfAccount* account = account_new(g_strdup("testaccount"), NULL, NULL, NULL, TRUE, NULL, 0, NULL, NULL, NULL,
+                                       0, 0, 0, 0, 0, g_strdup("default_conf_server"), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
     will_return(connection_get_status, JABBER_CONNECTED);
     will_return(session_get_account_name, "account_name");
diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c
index 204a8c35..d8272aab 100644
--- a/tests/unittests/ui/stub_ui.c
+++ b/tests/unittests/ui/stub_ui.c
@@ -1156,6 +1156,11 @@ cons_mood_setting(void)
 }
 
 void
+cons_strophe_setting(void)
+{
+}
+
+void
 cons_show_bookmarks_ignore(gchar** list, gsize len)
 {
 }
diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c
index f79aeb55..a7dc9ebf 100644
--- a/tests/unittests/xmpp/stub_xmpp.c
+++ b/tests/unittests/xmpp/stub_xmpp.c
@@ -39,6 +39,10 @@ session_connect_with_account(const ProfAccount* const account)
 }
 
 void
+session_reconnect_now(void)
+{
+}
+void
 session_disconnect(void)
 {
 }