about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/command/command.c411
-rw-r--r--src/command/commands.c1715
-rw-r--r--src/command/commands.h49
3 files changed, 1347 insertions, 828 deletions
diff --git a/src/command/command.c b/src/command/command.c
index 1ac87374..906f2708 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -137,6 +137,11 @@ GHashTable *commands = NULL;
 #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 },
@@ -152,7 +157,9 @@ GHashTable *commands = NULL;
 static struct cmd_t command_defs[] =
 {
     { "/help",
-        cmd_help, parse_args, 0, 2, NULL,
+        parse_args, 0, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_help)
         CMD_NOTAGS
         CMD_SYN(
             "/help [<area>|<command>]")
@@ -173,7 +180,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/about",
-        cmd_about, parse_args, 0, 0, NULL,
+        parse_args, 0, 0, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_about)
         CMD_NOTAGS
         CMD_SYN(
             "/about")
@@ -184,7 +193,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/connect",
-        cmd_connect, parse_args, 0, 7, NULL,
+        parse_args, 0, 7, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_connect)
         CMD_TAGS(
             CMD_TAG_CONNECTION)
         CMD_SYN(
@@ -211,7 +222,15 @@ static struct cmd_t command_defs[] =
         },
 
     { "/tls",
-        cmd_tls, parse_args, 1, 3, NULL,
+        parse_args, 1, 3, NULL,
+        CMD_SUBFUNCS(
+            { "certpath",   cmd_tls_certpath },
+            { "trust",      cmd_tls_trust },
+            { "trusted",    cmd_tls_trusted },
+            { "revoke",     cmd_tls_revoke },
+            { "show",       cmd_tls_show },
+            { "cert",       cmd_tls_cert })
+        CMD_NOMAINFUNC
         CMD_TAGS(
             CMD_TAG_CONNECTION,
             CMD_TAG_UI)
@@ -246,7 +265,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/disconnect",
-        cmd_disconnect, parse_args, 0, 0, NULL,
+        parse_args, 0, 0, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_disconnect)
         CMD_TAGS(
             CMD_TAG_CONNECTION)
         CMD_SYN(
@@ -258,7 +279,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/msg",
-        cmd_msg, parse_args_with_freetext, 1, 2, NULL,
+        parse_args_with_freetext, 1, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_msg)
         CMD_TAGS(
             CMD_TAG_CHAT)
         CMD_SYN(
@@ -281,7 +304,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/roster",
-        cmd_roster, parse_args_with_freetext, 0, 4, NULL,
+        parse_args_with_freetext, 0, 4, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_roster)
         CMD_TAGS(
             CMD_TAG_ROSTER,
             CMD_TAG_UI)
@@ -399,7 +424,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/group",
-        cmd_group, parse_args_with_freetext, 0, 3, NULL,
+        parse_args_with_freetext, 0, 3, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_group)
         CMD_TAGS(
             CMD_TAG_ROSTER,
             CMD_TAG_UI)
@@ -424,7 +451,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/info",
-        cmd_info, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_info)
         CMD_TAGS(
             CMD_TAG_ROSTER,
             CMD_TAG_CHAT,
@@ -445,7 +474,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/caps",
-        cmd_caps, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_caps)
         CMD_TAGS(
             CMD_TAG_DISCOVERY,
             CMD_TAG_CHAT,
@@ -466,7 +497,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/software",
-        cmd_software, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_software)
         CMD_TAGS(
             CMD_TAG_DISCOVERY,
             CMD_TAG_CHAT,
@@ -488,7 +521,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/status",
-        cmd_status, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_status)
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_GROUPCHAT)
@@ -507,7 +542,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/resource",
-        cmd_resource, parse_args, 1, 2, &cons_resource_setting,
+        parse_args, 1, 2, &cons_resource_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_resource)
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_UI)
@@ -527,7 +564,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/join",
-        cmd_join, parse_args, 0, 5, NULL,
+        parse_args, 0, 5, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_join)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -552,7 +591,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/leave",
-        cmd_leave, parse_args, 0, 0, NULL,
+        parse_args, 0, 0, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_leave)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -564,7 +605,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/invite",
-        cmd_invite, parse_args_with_freetext, 1, 2, NULL,
+        parse_args_with_freetext, 1, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_invite)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -578,7 +621,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/invites",
-        cmd_invites, parse_args_with_freetext, 0, 0, NULL,
+        parse_args_with_freetext, 0, 0, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_invites)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -590,7 +635,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/decline",
-        cmd_decline, parse_args_with_freetext, 1, 1, NULL,
+        parse_args_with_freetext, 1, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_decline)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -603,7 +650,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/room",
-        cmd_room, parse_args, 1, 1, NULL,
+        parse_args, 1, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_room)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -618,7 +667,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/kick",
-        cmd_kick, parse_args_with_freetext, 1, 2, NULL,
+        parse_args_with_freetext, 1, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_kick)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -632,7 +683,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/ban",
-        cmd_ban, parse_args_with_freetext, 1, 2, NULL,
+        parse_args_with_freetext, 1, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_ban)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -646,7 +699,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/subject",
-        cmd_subject, parse_args_with_freetext, 0, 2, NULL,
+        parse_args_with_freetext, 0, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_subject)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -667,7 +722,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/affiliation",
-        cmd_affiliation, parse_args_with_freetext, 1, 4, NULL,
+        parse_args_with_freetext, 1, 4, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_affiliation)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -683,7 +740,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/role",
-        cmd_role, parse_args_with_freetext, 1, 4, NULL,
+        parse_args_with_freetext, 1, 4, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_role)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -699,7 +758,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/occupants",
-        cmd_occupants, parse_args, 1, 3, cons_occupants_setting,
+        parse_args, 1, 3, cons_occupants_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_occupants)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT,
             CMD_TAG_UI)
@@ -721,7 +782,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/form",
-        cmd_form, parse_args, 1, 2, NULL,
+        parse_args, 1, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_form)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -740,7 +803,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/rooms",
-        cmd_rooms, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_rooms)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -755,7 +820,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/bookmark",
-        cmd_bookmark, parse_args, 0, 8, NULL,
+        parse_args, 0, 8, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_bookmark)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -781,7 +848,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/disco",
-        cmd_disco, parse_args, 1, 2, NULL,
+        parse_args, 1, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_disco)
         CMD_TAGS(
             CMD_TAG_DISCOVERY)
         CMD_SYN(
@@ -801,7 +870,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/sendfile",
-        cmd_sendfile, parse_args_with_freetext, 1, 1, NULL,
+        parse_args_with_freetext, 1, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_sendfile)
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_GROUPCHAT)
@@ -817,7 +888,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/lastactivity",
-        cmd_lastactivity, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_lastactivity)
         CMD_TAGS(
             CMD_TAG_PRESENCE)
         CMD_SYN(
@@ -837,7 +910,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/nick",
-        cmd_nick, parse_args_with_freetext, 1, 1, NULL,
+        parse_args_with_freetext, 1, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_nick)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -850,7 +925,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/win",
-        cmd_win, parse_args, 1, 1, NULL,
+        parse_args, 1, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_win)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -881,7 +958,14 @@ static struct cmd_t command_defs[] =
     },
 
     { "/wins",
-        cmd_wins, parse_args, 0, 3, NULL,
+        parse_args, 0, 3, NULL,
+        CMD_SUBFUNCS(
+            { "unread",     cmd_wins_unread },
+            { "tidy",       cmd_wins_tidy },
+            { "prune",      cmd_wins_prune },
+            { "swap",       cmd_wins_swap },
+            { "autotidy",   cmd_wins_autotidy })
+        CMD_MAINFUNC(cmd_wins)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -904,7 +988,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/sub",
-        cmd_sub, parse_args, 1, 2, NULL,
+        parse_args, 1, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_sub)
         CMD_TAGS(
             CMD_TAG_ROSTER)
         CMD_SYN(
@@ -932,7 +1018,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/tiny",
-        cmd_tiny, parse_args, 1, 1, NULL,
+        parse_args, 1, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_tiny)
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_GROUPCHAT)
@@ -947,7 +1035,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/who",
-        cmd_who, parse_args, 0, 2, NULL,
+        parse_args, 0, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_who)
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_GROUPCHAT,
@@ -978,7 +1068,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/close",
-        cmd_close, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_close)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1006,7 +1098,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/clear",
-        cmd_clear, parse_args, 0, 0, NULL,
+        parse_args, 0, 0, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_clear)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1018,7 +1112,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/quit",
-        cmd_quit, parse_args, 0, 0, NULL,
+        parse_args, 0, 0, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_quit)
         CMD_NOTAGS
         CMD_SYN(
             "/quit")
@@ -1029,7 +1125,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/privileges",
-        cmd_privileges, parse_args, 1, 1, &cons_privileges_setting,
+        parse_args, 1, 1, &cons_privileges_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_privileges)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT,
             CMD_TAG_UI)
@@ -1043,7 +1141,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/charset",
-        cmd_charset, parse_args, 0, 0, NULL,
+        parse_args, 0, 0, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_charset)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1055,7 +1155,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/beep",
-        cmd_beep, parse_args, 1, 1, &cons_beep_setting,
+        parse_args, 1, 1, &cons_beep_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_beep)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1070,7 +1172,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/console",
-        cmd_console, parse_args, 2, 2, &cons_console_setting,
+        parse_args, 2, 2, &cons_console_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_console)
         CMD_TAGS(
             CMD_TAG_UI,
             CMD_TAG_CHAT,
@@ -1096,7 +1200,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/encwarn",
-        cmd_encwarn, parse_args, 1, 1, &cons_encwarn_setting,
+        parse_args, 1, 1, &cons_encwarn_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_encwarn)
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_UI)
@@ -1110,7 +1216,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/presence",
-        cmd_presence, parse_args, 1, 1, &cons_presence_setting,
+        parse_args, 1, 1, &cons_presence_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_presence)
         CMD_TAGS(
             CMD_TAG_UI,
             CMD_TAG_CHAT)
@@ -1124,7 +1232,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/wrap",
-        cmd_wrap, parse_args, 1, 1, &cons_wrap_setting,
+        parse_args, 1, 1, &cons_wrap_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_wrap)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1137,7 +1247,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/time",
-        cmd_time, parse_args, 1, 3, &cons_time_setting,
+        parse_args, 1, 3, &cons_time_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_time)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1177,7 +1289,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/inpblock",
-        cmd_inpblock, parse_args, 2, 2, &cons_inpblock_setting,
+        parse_args, 2, 2, &cons_inpblock_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_inpblock)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1192,7 +1306,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/notify",
-        cmd_notify, parse_args_with_freetext, 0, 4, NULL,
+        parse_args_with_freetext, 0, 4, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_notify)
         CMD_TAGS(
             CMD_TAG_UI,
             CMD_TAG_CHAT,
@@ -1261,7 +1377,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/flash",
-        cmd_flash, parse_args, 1, 1, &cons_flash_setting,
+        parse_args, 1, 1, &cons_flash_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_flash)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1275,7 +1393,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/tray",
-        cmd_tray, parse_args, 1, 1, &cons_tray_setting,
+        parse_args, 1, 1, &cons_tray_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_tray)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1288,7 +1408,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/intype",
-        cmd_intype, parse_args, 1, 1, &cons_intype_setting,
+        parse_args, 1, 1, &cons_intype_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_intype)
         CMD_TAGS(
             CMD_TAG_UI,
             CMD_TAG_CHAT)
@@ -1302,7 +1424,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/splash",
-        cmd_splash, parse_args, 1, 1, &cons_splash_setting,
+        parse_args, 1, 1, &cons_splash_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_splash)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1315,7 +1439,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/autoconnect",
-        cmd_autoconnect, parse_args, 1, 2, &cons_autoconnect_setting,
+        parse_args, 1, 2, &cons_autoconnect_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_autoconnect)
         CMD_TAGS(
             CMD_TAG_CONNECTION)
         CMD_SYN(
@@ -1333,7 +1459,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/vercheck",
-        cmd_vercheck, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_vercheck)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1346,7 +1474,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/titlebar",
-        cmd_titlebar, parse_args, 2, 2, &cons_titlebar_setting,
+        parse_args, 2, 2, &cons_titlebar_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_titlebar)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1361,7 +1491,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/alias",
-        cmd_alias, parse_args_with_freetext, 1, 3, NULL,
+        parse_args_with_freetext, 1, 3, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_alias)
         CMD_NOTAGS
         CMD_SYN(
             "/alias list",
@@ -1382,7 +1514,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/chlog",
-        cmd_chlog, parse_args, 1, 1, &cons_chlog_setting,
+        parse_args, 1, 1, &cons_chlog_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_chlog)
         CMD_TAGS(
             CMD_TAG_CHAT)
         CMD_SYN(
@@ -1398,7 +1532,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/grlog",
-        cmd_grlog, parse_args, 1, 1, &cons_grlog_setting,
+        parse_args, 1, 1, &cons_grlog_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_grlog)
         CMD_TAGS(
             CMD_TAG_GROUPCHAT)
         CMD_SYN(
@@ -1412,7 +1548,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/states",
-        cmd_states, parse_args, 1, 1, &cons_states_setting,
+        parse_args, 1, 1, &cons_states_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_states)
         CMD_TAGS(
             CMD_TAG_CHAT)
         CMD_SYN(
@@ -1425,7 +1563,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/pgp",
-        cmd_pgp, parse_args, 1, 3, NULL,
+        parse_args, 1, 3, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_pgp)
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_UI)
@@ -1460,7 +1600,23 @@ static struct cmd_t command_defs[] =
     },
 
     { "/otr",
-        cmd_otr, parse_args, 1, 3, NULL,
+        parse_args, 1, 3, NULL,
+        CMD_SUBFUNCS(
+            { "char",       cmd_otr_char },
+            { "log",        cmd_otr_log },
+            { "libver",     cmd_otr_libver },
+            { "policy",     cmd_otr_policy },
+            { "gen",        cmd_otr_gen },
+            { "myfp",       cmd_otr_myfp },
+            { "theirfp",    cmd_otr_theirfp },
+            { "start",      cmd_otr_start },
+            { "end",        cmd_otr_end },
+            { "trust",      cmd_otr_trust },
+            { "untrust",    cmd_otr_untrust },
+            { "secret",     cmd_otr_secret },
+            { "question",   cmd_otr_question },
+            { "answer",     cmd_otr_answer })
+        CMD_NOMAINFUNC
         CMD_TAGS(
             CMD_TAG_CHAT,
             CMD_TAG_UI)
@@ -1513,7 +1669,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/outtype",
-        cmd_outtype, parse_args, 1, 1, &cons_outtype_setting,
+        parse_args, 1, 1, &cons_outtype_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_outtype)
         CMD_TAGS(
             CMD_TAG_CHAT)
         CMD_SYN(
@@ -1526,7 +1684,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/gone",
-        cmd_gone, parse_args, 1, 1, &cons_gone_setting,
+        parse_args, 1, 1, &cons_gone_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_gone)
         CMD_TAGS(
             CMD_TAG_CHAT)
         CMD_SYN(
@@ -1540,7 +1700,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/history",
-        cmd_history, parse_args, 1, 1, &cons_history_setting,
+        parse_args, 1, 1, &cons_history_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_history)
         CMD_TAGS(
             CMD_TAG_UI,
             CMD_TAG_CHAT)
@@ -1555,7 +1717,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/log",
-        cmd_log, parse_args, 1, 2, &cons_log_setting,
+        parse_args, 1, 2, &cons_log_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_log)
         CMD_NOTAGS
         CMD_SYN(
             "/log where",
@@ -1573,7 +1737,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/carbons",
-        cmd_carbons, parse_args, 1, 1, &cons_carbons_setting,
+        parse_args, 1, 1, &cons_carbons_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_carbons)
         CMD_TAGS(
             CMD_TAG_CHAT)
         CMD_SYN(
@@ -1587,7 +1753,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/receipts",
-        cmd_receipts, parse_args, 2, 2, &cons_receipts_setting,
+        parse_args, 2, 2, &cons_receipts_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_receipts)
         CMD_TAGS(
             CMD_TAG_CHAT)
         CMD_SYN(
@@ -1602,7 +1770,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/reconnect",
-        cmd_reconnect, parse_args, 1, 1, &cons_reconnect_setting,
+        parse_args, 1, 1, &cons_reconnect_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_reconnect)
         CMD_TAGS(
             CMD_TAG_CONNECTION)
         CMD_SYN(
@@ -1615,7 +1785,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/autoping",
-        cmd_autoping, parse_args, 2, 2, &cons_autoping_setting,
+        parse_args, 2, 2, &cons_autoping_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_autoping)
         CMD_TAGS(
             CMD_TAG_CONNECTION)
         CMD_SYN(
@@ -1630,7 +1802,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/ping",
-        cmd_ping, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_ping)
         CMD_TAGS(
             CMD_TAG_CONNECTION)
         CMD_SYN(
@@ -1644,7 +1818,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/autoaway",
-        cmd_autoaway, parse_args_with_freetext, 2, 3, &cons_autoaway_setting,
+        parse_args_with_freetext, 2, 3, &cons_autoaway_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_autoaway)
         CMD_TAGS(
             CMD_TAG_PRESENCE)
         CMD_SYN(
@@ -1675,7 +1851,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/priority",
-        cmd_priority, parse_args, 1, 1, NULL,
+        parse_args, 1, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_priority)
         CMD_TAGS(
             CMD_TAG_PRESENCE)
         CMD_SYN(
@@ -1689,7 +1867,19 @@ static struct cmd_t command_defs[] =
     },
 
     { "/account",
-        cmd_account, parse_args, 0, 4, NULL,
+        parse_args, 0, 4, NULL,
+        CMD_SUBFUNCS(
+            { "list",       cmd_account_list },
+            { "show",       cmd_account_show },
+            { "add",        cmd_account_add },
+            { "remove",     cmd_account_remove },
+            { "enable",     cmd_account_enable },
+            { "disable",    cmd_account_disable },
+            { "rename",     cmd_account_rename },
+            { "default",    cmd_account_default },
+            { "set",        cmd_account_set },
+            { "clear",      cmd_account_clear })
+        CMD_MAINFUNC(cmd_account)
         CMD_TAGS(
             CMD_TAG_CONNECTION
             CMD_TAG_PRESENCE,
@@ -1780,7 +1970,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/plugins",
-        cmd_plugins, parse_args, 0, 2, NULL,
+        parse_args, 0, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_plugins)
         CMD_NOTAGS
         CMD_SYN(
             "/plugins",
@@ -1794,7 +1986,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/prefs",
-        cmd_prefs, parse_args, 0, 1, NULL,
+        parse_args, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_prefs)
         CMD_NOTAGS
         CMD_SYN(
             "/prefs [ui|desktop|chat|log|conn|presence|otr|pgp]")
@@ -1814,7 +2008,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/theme",
-        cmd_theme, parse_args, 1, 2, &cons_theme_setting,
+        parse_args, 1, 2, &cons_theme_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_theme)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1835,7 +2031,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/statuses",
-        cmd_statuses, parse_args, 2, 2, &cons_statuses_setting,
+        parse_args, 2, 2, &cons_statuses_setting,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_statuses)
         CMD_TAGS(
             CMD_TAG_UI,
             CMD_TAG_CHAT,
@@ -1859,7 +2057,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/xmlconsole",
-        cmd_xmlconsole, parse_args, 0, 0, NULL,
+        parse_args, 0, 0, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_xmlconsole)
         CMD_TAGS(
             CMD_TAG_UI)
         CMD_SYN(
@@ -1871,7 +2071,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/away",
-        cmd_away, parse_args_with_freetext, 0, 1, NULL,
+        parse_args_with_freetext, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_away)
         CMD_TAGS(
             CMD_TAG_PRESENCE)
         CMD_SYN(
@@ -1886,7 +2088,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/chat",
-        cmd_chat, parse_args_with_freetext, 0, 1, NULL,
+        parse_args_with_freetext, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_chat)
         CMD_TAGS(
             CMD_TAG_PRESENCE)
         CMD_SYN(
@@ -1901,7 +2105,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/dnd",
-        cmd_dnd, parse_args_with_freetext, 0, 1, NULL,
+        parse_args_with_freetext, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_dnd)
         CMD_TAGS(
             CMD_TAG_PRESENCE)
         CMD_SYN(
@@ -1916,7 +2122,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/online",
-        cmd_online, parse_args_with_freetext, 0, 1, NULL,
+        parse_args_with_freetext, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_online)
         CMD_TAGS(
             CMD_TAG_PRESENCE)
         CMD_SYN(
@@ -1931,7 +2139,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/xa",
-        cmd_xa, parse_args_with_freetext, 0, 1, NULL,
+        parse_args_with_freetext, 0, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_xa)
         CMD_TAGS(
             CMD_TAG_PRESENCE)
         CMD_SYN(
@@ -1946,7 +2156,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/script",
-        cmd_script, parse_args, 1, 2, NULL,
+        parse_args, 1, 2, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_script)
         CMD_NOTAGS
         CMD_SYN(
             "/script run <script>",
@@ -1966,7 +2178,9 @@ static struct cmd_t command_defs[] =
     },
 
     { "/export",
-        cmd_export, parse_args, 1, 1, NULL,
+        parse_args, 1, 1, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_export)
         CMD_NOTAGS
         CMD_SYN(
             "/export <filepath>")
@@ -3073,11 +3287,26 @@ _cmd_execute(ProfWin *window, const char *const command, const char *const inp)
         if (result == FALSE) {
             ui_invalid_command_usage(cmd->cmd, cmd->setting_func);
             return TRUE;
-        } else {
-            gboolean result = cmd->func(window, command, args);
-            g_strfreev(args);
-            return result;
         }
+        if (args[0] && cmd->sub_funcs) {
+            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;
+                }
+                i++;
+            }
+        }
+        if (!cmd->func) {
+            ui_invalid_command_usage(cmd->cmd, cmd->setting_func);
+            return TRUE;
+        }
+        gboolean result = cmd->func(window, command, args);
+        g_strfreev(args);
+        return result;
     } else if (plugins_run_command(inp)) {
         return TRUE;
     } else {
diff --git a/src/command/commands.c b/src/command/commands.c
index 257b8b5c..7e2825e8 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -184,155 +184,171 @@ cmd_execute_alias(ProfWin *window, const char *const inp, gboolean *ran)
 }
 
 gboolean
-cmd_tls(ProfWin *window, const char *const command, gchar **args)
+cmd_tls_certpath(ProfWin *window, const char *const command, gchar **args)
 {
-    if (g_strcmp0(args[0], "certpath") == 0) {
 #ifdef HAVE_LIBMESODE
-        if (g_strcmp0(args[1], "set") == 0) {
-            if (args[2] == NULL) {
-                cons_bad_cmd_usage(command);
-                return TRUE;
-            }
-
-            if (g_file_test(args[2], G_FILE_TEST_IS_DIR)) {
-                prefs_set_string(PREF_TLS_CERTPATH, args[2]);
-                cons_show("Certificate path set to: %s", args[2]);
-            } else {
-                cons_show("Directory %s does not exist.", args[2]);
-            }
-            return TRUE;
-        } else if (g_strcmp0(args[1], "clear") == 0) {
-            prefs_set_string(PREF_TLS_CERTPATH, NULL);
-            cons_show("Certificate path cleared");
-            return TRUE;
-        } else if (args[1] == NULL) {
-            char *path = prefs_get_string(PREF_TLS_CERTPATH);
-            if (path) {
-                cons_show("Trusted certificate path: %s", path);
-                prefs_free_string(path);
-            } else {
-                cons_show("No trusted certificate path set.");
-            }
-            return TRUE;
-        } else {
+    if (g_strcmp0(args[1], "set") == 0) {
+        if (args[2] == NULL) {
             cons_bad_cmd_usage(command);
             return TRUE;
         }
-#else
-        cons_show("Certificate path setting only supported when built with libmesode.");
+
+        if (g_file_test(args[2], G_FILE_TEST_IS_DIR)) {
+            prefs_set_string(PREF_TLS_CERTPATH, args[2]);
+            cons_show("Certificate path set to: %s", args[2]);
+        } else {
+            cons_show("Directory %s does not exist.", args[2]);
+        }
+        return TRUE;
+    } else if (g_strcmp0(args[1], "clear") == 0) {
+        prefs_set_string(PREF_TLS_CERTPATH, NULL);
+        cons_show("Certificate path cleared");
+        return TRUE;
+    } else if (args[1] == NULL) {
+        char *path = prefs_get_string(PREF_TLS_CERTPATH);
+        if (path) {
+            cons_show("Trusted certificate path: %s", path);
+            prefs_free_string(path);
+        } else {
+            cons_show("No trusted certificate path set.");
+        }
+        return TRUE;
+    } else {
+        cons_bad_cmd_usage(command);
         return TRUE;
+    }
+#else
+    cons_show("Certificate path setting only supported when built with libmesode.");
+    return TRUE;
 #endif
-    } else if (g_strcmp0(args[0], "trust") == 0) {
+
+}
+
+gboolean
+cmd_tls_trust(ProfWin *window, const char *const command, gchar **args)
+{
 #ifdef HAVE_LIBMESODE
-        jabber_conn_status_t conn_status = jabber_get_connection_status();
-        if (conn_status != JABBER_CONNECTED) {
-            cons_show("You are not currently connected.");
-            return TRUE;
-        }
-        if (!jabber_conn_is_secured()) {
-            cons_show("No TLS connection established");
-            return TRUE;
-        }
-        TLSCertificate *cert = jabber_get_tls_peer_cert();
-        if (!cert) {
-            cons_show("Error getting TLS certificate.");
-            return TRUE;
-        }
-        if (tlscerts_exists(cert->fingerprint)) {
-            cons_show("Certificate %s already trusted.", cert->fingerprint);
-            tlscerts_free(cert);
-            return TRUE;
-        }
-        cons_show("Adding %s to trusted certificates.", cert->fingerprint);
-        tlscerts_add(cert);
+    jabber_conn_status_t conn_status = jabber_get_connection_status();
+    if (conn_status != JABBER_CONNECTED) {
+        cons_show("You are not currently connected.");
+        return TRUE;
+    }
+    if (!jabber_conn_is_secured()) {
+        cons_show("No TLS connection established");
+        return TRUE;
+    }
+    TLSCertificate *cert = jabber_get_tls_peer_cert();
+    if (!cert) {
+        cons_show("Error getting TLS certificate.");
+        return TRUE;
+    }
+    if (tlscerts_exists(cert->fingerprint)) {
+        cons_show("Certificate %s already trusted.", cert->fingerprint);
         tlscerts_free(cert);
         return TRUE;
+    }
+    cons_show("Adding %s to trusted certificates.", cert->fingerprint);
+    tlscerts_add(cert);
+    tlscerts_free(cert);
+    return TRUE;
 #else
-        cons_show("Manual certificate trust only supported when built with libmesode.");
-        return TRUE;
+    cons_show("Manual certificate trust only supported when built with libmesode.");
+    return TRUE;
 #endif
-    } else if (g_strcmp0(args[0], "trusted") == 0) {
+}
+
+gboolean
+cmd_tls_trusted(ProfWin *window, const char *const command, gchar **args)
+{
 #ifdef HAVE_LIBMESODE
-        GList *certs = tlscerts_list();
-        GList *curr = certs;
+    GList *certs = tlscerts_list();
+    GList *curr = certs;
 
-        if (curr) {
-            cons_show("Trusted certificates:");
-            cons_show("");
-        } else {
-            cons_show("No trusted certificates found.");
-        }
-        while (curr) {
-            TLSCertificate *cert = curr->data;
-            cons_show_tlscert_summary(cert);
-            cons_show("");
-            curr = g_list_next(curr);
-        }
-        g_list_free_full(certs, (GDestroyNotify)tlscerts_free);
-        return TRUE;
+    if (curr) {
+        cons_show("Trusted certificates:");
+        cons_show("");
+    } else {
+        cons_show("No trusted certificates found.");
+    }
+    while (curr) {
+        TLSCertificate *cert = curr->data;
+        cons_show_tlscert_summary(cert);
+        cons_show("");
+        curr = g_list_next(curr);
+    }
+    g_list_free_full(certs, (GDestroyNotify)tlscerts_free);
+    return TRUE;
 #else
-        cons_show("Manual certificate trust only supported when built with libmesode.");
-        return TRUE;
+    cons_show("Manual certificate trust only supported when built with libmesode.");
+    return TRUE;
 #endif
-    } else if (g_strcmp0(args[0], "revoke") == 0) {
+}
+
+gboolean
+cmd_tls_revoke(ProfWin *window, const char *const command, gchar **args)
+{
 #ifdef HAVE_LIBMESODE
-        if (args[1] == NULL) {
-            cons_bad_cmd_usage(command);
+    if (args[1] == NULL) {
+        cons_bad_cmd_usage(command);
+    } else {
+        gboolean res = tlscerts_revoke(args[1]);
+        if (res) {
+            cons_show("Trusted certificate revoked: %s", args[1]);
         } else {
-            gboolean res = tlscerts_revoke(args[1]);
-            if (res) {
-                cons_show("Trusted certificate revoked: %s", args[1]);
-            } else {
-                cons_show("Could not find certificate: %s", args[0]);
-            }
+            cons_show("Could not find certificate: %s", args[0]);
         }
-        return TRUE;
+    }
+    return TRUE;
 #else
-        cons_show("Manual certificate trust only supported when built with libmesode.");
-        return TRUE;
+    cons_show("Manual certificate trust only supported when built with libmesode.");
+    return TRUE;
 #endif
-    } else if (g_strcmp0(args[0], "show") == 0) {
-        _cmd_set_boolean_preference(args[1], command, "TLS titlebar indicator", PREF_TLS_SHOW);
-        return TRUE;
-    } else if (g_strcmp0(args[0], "cert") == 0) {
+}
+
+gboolean
+cmd_tls_show(ProfWin *window, const char *const command, gchar **args)
+{
+    _cmd_set_boolean_preference(args[1], command, "TLS titlebar indicator", PREF_TLS_SHOW);
+    return TRUE;
+}
+
+gboolean
+cmd_tls_cert(ProfWin *window, const char *const command, gchar **args)
+{
 #ifdef HAVE_LIBMESODE
-        if (args[1]) {
-            TLSCertificate *cert = tlscerts_get_trusted(args[1]);
-            if (!cert) {
-                cons_show("No such certificate.");
-            } else {
-                cons_show_tlscert(cert);
-                tlscerts_free(cert);
-            }
-            return TRUE;
+    if (args[1]) {
+        TLSCertificate *cert = tlscerts_get_trusted(args[1]);
+        if (!cert) {
+            cons_show("No such certificate.");
         } else {
-            jabber_conn_status_t conn_status = jabber_get_connection_status();
-            if (conn_status != JABBER_CONNECTED) {
-                cons_show("You are not currently connected.");
-                return TRUE;
-            }
-            if (!jabber_conn_is_secured()) {
-                cons_show("No TLS connection established");
-                return TRUE;
-            }
-            TLSCertificate *cert = jabber_get_tls_peer_cert();
-            if (!cert) {
-                cons_show("Error getting TLS certificate.");
-                return TRUE;
-            }
             cons_show_tlscert(cert);
-            cons_show("");
             tlscerts_free(cert);
-            return TRUE;
         }
-#else
-        cons_show("Certificate fetching not supported.");
         return TRUE;
-#endif
     } else {
-        cons_bad_cmd_usage(command);
+        jabber_conn_status_t conn_status = jabber_get_connection_status();
+        if (conn_status != JABBER_CONNECTED) {
+            cons_show("You are not currently connected.");
+            return TRUE;
+        }
+        if (!jabber_conn_is_secured()) {
+            cons_show("No TLS connection established");
+            return TRUE;
+        }
+        TLSCertificate *cert = jabber_get_tls_peer_cert();
+        if (!cert) {
+            cons_show("Error getting TLS certificate.");
+            return TRUE;
+        }
+        cons_show_tlscert(cert);
+        cons_show("");
+        tlscerts_free(cert);
         return TRUE;
     }
+#else
+    cons_show("Certificate fetching not supported.");
+    return TRUE;
+#endif
 }
 
 gboolean
@@ -450,386 +466,452 @@ cmd_connect(ProfWin *window, const char *const command, gchar **args)
 }
 
 gboolean
-cmd_account(ProfWin *window, const char *const command, gchar **args)
+cmd_account_list(ProfWin *window, const char *const command, gchar **args)
 {
-    char *subcmd = args[0];
+    gchar **accounts = accounts_get_list();
+    cons_show_account_list(accounts);
+    g_strfreev(accounts);
 
-    if (subcmd == NULL) {
-        if (jabber_get_connection_status() != JABBER_CONNECTED) {
-            cons_bad_cmd_usage(command);
+    return TRUE;
+}
+
+gboolean
+cmd_account_show(ProfWin *window, const char *const command, gchar **args)
+{
+    char *account_name = args[1];
+    if (account_name == NULL) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    ProfAccount *account = accounts_get_account(account_name);
+    if (account == NULL) {
+        cons_show("No such account.");
+        cons_show("");
+    } else {
+        cons_show_account(account);
+        account_free(account);
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_account_add(ProfWin *window, const char *const command, gchar **args)
+{
+    char *account_name = args[1];
+    if (account_name == NULL) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    accounts_add(account_name, NULL, 0, NULL);
+    cons_show("Account created.");
+    cons_show("");
+
+    return TRUE;
+}
+
+gboolean
+cmd_account_remove(ProfWin *window, const char *const command, gchar **args)
+{
+    char *account_name = args[1];
+    if(!account_name) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
+    if(accounts_remove(account_name)){
+        cons_show("Account %s removed.", account_name);
+        if(def && strcmp(def, account_name) == 0){
+            prefs_set_string(PREF_DEFAULT_ACCOUNT, NULL);
+            cons_show("Default account removed because the corresponding account was removed.");
+        }
+    } else {
+        cons_show("Failed to remove account %s.", account_name);
+        cons_show("Either the account does not exist, or an unknown error occurred.");
+    }
+    cons_show("");
+    g_free(def);
+
+    return TRUE;
+}
+
+gboolean
+cmd_account_enable(ProfWin *window, const char *const command, gchar **args)
+{
+    char *account_name = args[1];
+    if (account_name == NULL) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    if (accounts_enable(account_name)) {
+        cons_show("Account enabled.");
+        cons_show("");
+    } else {
+        cons_show("No such account: %s", account_name);
+        cons_show("");
+    }
+
+    return TRUE;
+}
+gboolean
+cmd_account_disable(ProfWin *window, const char *const command, gchar **args)
+{
+    char *account_name = args[1];
+    if (account_name == NULL) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    if (accounts_disable(account_name)) {
+        cons_show("Account disabled.");
+        cons_show("");
+    } else {
+        cons_show("No such account: %s", account_name);
+        cons_show("");
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_account_rename(ProfWin *window, const char *const command, gchar **args)
+{
+    if (g_strv_length(args) != 3) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    char *account_name = args[1];
+    char *new_name = args[2];
+
+    if (accounts_rename(account_name, new_name)) {
+        cons_show("Account renamed.");
+        cons_show("");
+    } else {
+        cons_show("Either account %s doesn't exist, or account %s already exists.", account_name, new_name);
+        cons_show("");
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_account_default(ProfWin *window, const char *const command, gchar **args)
+{
+    if (g_strv_length(args) == 1) {
+        char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
+        if (def) {
+            cons_show("The default account is %s.", def);
+            free(def);
         } else {
-            ProfAccount *account = accounts_get_account(jabber_get_account_name());
-            cons_show_account(account);
-            account_free(account);
+            cons_show("No default account.");
         }
-    } else if (strcmp(subcmd, "list") == 0) {
-        gchar **accounts = accounts_get_list();
-        cons_show_account_list(accounts);
-        g_strfreev(accounts);
-    } else if (strcmp(subcmd, "show") == 0) {
-        char *account_name = args[1];
-        if (account_name == NULL) {
-            cons_bad_cmd_usage(command);
+    } else if (g_strv_length(args) == 2) {
+        if (strcmp(args[1], "off") == 0) {
+            prefs_set_string(PREF_DEFAULT_ACCOUNT, NULL);
+            cons_show("Removed default account.");
         } else {
-            ProfAccount *account = accounts_get_account(account_name);
-            if (account == NULL) {
-                cons_show("No such account.");
-                cons_show("");
+            cons_bad_cmd_usage(command);
+        }
+    } else if (g_strv_length(args) == 3) {
+        if (strcmp(args[1], "set") == 0) {
+            if (accounts_get_account(args[2])) {
+                prefs_set_string(PREF_DEFAULT_ACCOUNT, args[2]);
+                cons_show("Default account set to %s.", args[2]);
             } else {
-                cons_show_account(account);
-                account_free(account);
+                cons_show("Account %s does not exist.", args[2]);
             }
-        }
-    } else if (strcmp(subcmd, "add") == 0) {
-        char *account_name = args[1];
-        if (account_name == NULL) {
+        } else {
             cons_bad_cmd_usage(command);
+        }
+    } else {
+        cons_bad_cmd_usage(command);
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_account_set(ProfWin *window, const char *const command, gchar **args)
+{
+    if (g_strv_length(args) != 4) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    char *account_name = args[1];
+    char *property = args[2];
+    char *value = args[3];
+
+    if (!accounts_account_exists(account_name)) {
+        cons_show("Account %s doesn't exist", account_name);
+        cons_show("");
+        return TRUE;
+    }
+
+    if (strcmp(property, "jid") == 0) {
+        Jid *jid = jid_create(args[3]);
+        if (jid == NULL) {
+            cons_show("Malformed jid: %s", value);
         } else {
-            accounts_add(account_name, NULL, 0, NULL);
-            cons_show("Account created.");
+            accounts_set_jid(account_name, jid->barejid);
+            cons_show("Updated jid for account %s: %s", account_name, jid->barejid);
+            if (jid->resourcepart) {
+                accounts_set_resource(account_name, jid->resourcepart);
+                cons_show("Updated resource for account %s: %s", account_name, jid->resourcepart);
+            }
             cons_show("");
         }
-    } else if (strcmp(subcmd, "remove") == 0) {
-        char *account_name = args[1];
-        if(!account_name) {
-            cons_bad_cmd_usage(command);
+        jid_destroy(jid);
+    } else if (strcmp(property, "server") == 0) {
+        accounts_set_server(account_name, value);
+        cons_show("Updated server for account %s: %s", account_name, value);
+        cons_show("");
+    } else if (strcmp(property, "port") == 0) {
+        int port;
+        char *err_msg = NULL;
+        gboolean res = strtoi_range(value, &port, 1, 65535, &err_msg);
+        if (!res) {
+            cons_show(err_msg);
+            cons_show("");
+            free(err_msg);
+            return TRUE;
         } else {
-            char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
-            if(accounts_remove(account_name)){
-                cons_show("Account %s removed.", account_name);
-                if(def && strcmp(def, account_name) == 0){
-                    prefs_set_string(PREF_DEFAULT_ACCOUNT, NULL);
-                    cons_show("Default account removed because the corresponding account was removed.");
-                }
-            } else {
-                cons_show("Failed to remove account %s.", account_name);
-                cons_show("Either the account does not exist, or an unknown error occurred.");
-            }
+            accounts_set_port(account_name, port);
+            cons_show("Updated port for account %s: %s", account_name, value);
             cons_show("");
-            g_free(def);
         }
-    } else if (strcmp(subcmd, "enable") == 0) {
-        char *account_name = args[1];
-        if (account_name == NULL) {
-            cons_bad_cmd_usage(command);
+    } else if (strcmp(property, "resource") == 0) {
+        accounts_set_resource(account_name, value);
+        if (jabber_get_connection_status() == JABBER_CONNECTED) {
+            cons_show("Updated resource for account %s: %s, you will need to reconnect to pick up the change.", account_name, value);
         } else {
-            if (accounts_enable(account_name)) {
-                cons_show("Account enabled.");
-                cons_show("");
-            } else {
-                cons_show("No such account: %s", account_name);
-                cons_show("");
-            }
+            cons_show("Updated resource for account %s: %s", account_name, value);
         }
-    } else if (strcmp(subcmd, "disable") == 0) {
-        char *account_name = args[1];
-        if (account_name == NULL) {
-            cons_bad_cmd_usage(command);
+        cons_show("");
+    } else if (strcmp(property, "password") == 0) {
+        if(accounts_get_account(account_name)->eval_password) {
+            cons_show("Cannot set password when eval_password is set.");
         } else {
-            if (accounts_disable(account_name)) {
-                cons_show("Account disabled.");
-                cons_show("");
-            } else {
-                cons_show("No such account: %s", account_name);
-                cons_show("");
-            }
+            accounts_set_password(account_name, value);
+            cons_show("Updated password for account %s", account_name);
+            cons_show("");
         }
-    } else if (strcmp(subcmd, "rename") == 0) {
-        if (g_strv_length(args) != 3) {
-            cons_bad_cmd_usage(command);
+    } else if (strcmp(property, "eval_password") == 0) {
+        if(accounts_get_account(account_name)->password) {
+            cons_show("Cannot set eval_password when password is set.");
         } else {
-            char *account_name = args[1];
-            char *new_name = args[2];
-
-            if (accounts_rename(account_name, new_name)) {
-                cons_show("Account renamed.");
-                cons_show("");
-            } else {
-                cons_show("Either account %s doesn't exist, or account %s already exists.", account_name, new_name);
-                cons_show("");
-            }
+            accounts_set_eval_password(account_name, value);
+            cons_show("Updated eval_password for account %s", account_name);
+            cons_show("");
         }
-    } else if (strcmp(subcmd, "default") == 0) {
-        if(g_strv_length(args) == 1){
-            char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
-
-            if(def){
-                cons_show("The default account is %s.", def);
-                free(def);
-            } else {
-                cons_show("No default account.");
-            }
-        } else if(g_strv_length(args) == 2){
-            if(strcmp(args[1], "off") == 0){
-                prefs_set_string(PREF_DEFAULT_ACCOUNT, NULL);
-                cons_show("Removed default account.");
-            } else {
-                cons_bad_cmd_usage(command);
-            }
-        } else if(g_strv_length(args) == 3) {
-            if(strcmp(args[1], "set") == 0){
-                if(accounts_get_account(args[2])){
-                    prefs_set_string(PREF_DEFAULT_ACCOUNT, args[2]);
-                    cons_show("Default account set to %s.", args[2]);
-                } else {
-                    cons_show("Account %s does not exist.", args[2]);
-                }
-            } else {
-                cons_bad_cmd_usage(command);
-            }
+    } else if (strcmp(property, "muc") == 0) {
+        accounts_set_muc_service(account_name, value);
+        cons_show("Updated muc service for account %s: %s", account_name, value);
+        cons_show("");
+    } else if (strcmp(property, "nick") == 0) {
+        accounts_set_muc_nick(account_name, value);
+        cons_show("Updated muc nick for account %s: %s", account_name, value);
+        cons_show("");
+    } else if (strcmp(property, "otr") == 0) {
+        if ((g_strcmp0(value, "manual") != 0)
+                && (g_strcmp0(value, "opportunistic") != 0)
+                && (g_strcmp0(value, "always") != 0)) {
+            cons_show("OTR policy must be one of: manual, opportunistic or always.");
         } else {
-            cons_bad_cmd_usage(command);
+            accounts_set_otr_policy(account_name, value);
+            cons_show("Updated OTR policy for account %s: %s", account_name, value);
+            cons_show("");
         }
-    } else if (strcmp(subcmd, "set") == 0) {
-        if (g_strv_length(args) != 4) {
-            cons_bad_cmd_usage(command);
+    } else if (strcmp(property, "status") == 0) {
+        if (!valid_resource_presence_string(value) && (strcmp(value, "last") != 0)) {
+            cons_show("Invalid status: %s", value);
         } else {
-            char *account_name = args[1];
-            char *property = args[2];
-            char *value = args[3];
-
-            if (!accounts_account_exists(account_name)) {
-                cons_show("Account %s doesn't exist", account_name);
-                cons_show("");
-            } else {
-                if (strcmp(property, "jid") == 0) {
-                    Jid *jid = jid_create(args[3]);
-                    if (jid == NULL) {
-                        cons_show("Malformed jid: %s", value);
-                    } else {
-                        accounts_set_jid(account_name, jid->barejid);
-                        cons_show("Updated jid for account %s: %s", account_name, jid->barejid);
-                        if (jid->resourcepart) {
-                            accounts_set_resource(account_name, jid->resourcepart);
-                            cons_show("Updated resource for account %s: %s", account_name, jid->resourcepart);
-                        }
-                        cons_show("");
-                    }
-                    jid_destroy(jid);
-                } else if (strcmp(property, "server") == 0) {
-                    accounts_set_server(account_name, value);
-                    cons_show("Updated server for account %s: %s", account_name, value);
-                    cons_show("");
-                } else if (strcmp(property, "port") == 0) {
-                    int port;
-                    char *err_msg = NULL;
-                    gboolean res = strtoi_range(value, &port, 1, 65535, &err_msg);
-                    if (!res) {
-                        cons_show(err_msg);
-                        cons_show("");
-                        free(err_msg);
-                        return TRUE;
-                    } else {
-                        accounts_set_port(account_name, port);
-                        cons_show("Updated port for account %s: %s", account_name, value);
-                        cons_show("");
-                    }
-                } else if (strcmp(property, "resource") == 0) {
-                    accounts_set_resource(account_name, value);
-                    if (jabber_get_connection_status() == JABBER_CONNECTED) {
-                        cons_show("Updated resource for account %s: %s, you will need to reconnect to pick up the change.", account_name, value);
-                    } else {
-                        cons_show("Updated resource for account %s: %s", account_name, value);
-                    }
-                    cons_show("");
-                } else if (strcmp(property, "password") == 0) {
-                    if(accounts_get_account(account_name)->eval_password) {
-                        cons_show("Cannot set password when eval_password is set.");
-                    } else {
-                        accounts_set_password(account_name, value);
-                        cons_show("Updated password for account %s", account_name);
-                        cons_show("");
-                    }
-                } else if (strcmp(property, "eval_password") == 0) {
-                    if(accounts_get_account(account_name)->password) {
-                        cons_show("Cannot set eval_password when password is set.");
-                    } else {
-                        accounts_set_eval_password(account_name, value);
-                        cons_show("Updated eval_password for account %s", account_name);
-                        cons_show("");
-                    }
-                } else if (strcmp(property, "muc") == 0) {
-                    accounts_set_muc_service(account_name, value);
-                    cons_show("Updated muc service for account %s: %s", account_name, value);
-                    cons_show("");
-                } else if (strcmp(property, "nick") == 0) {
-                    accounts_set_muc_nick(account_name, value);
-                    cons_show("Updated muc nick for account %s: %s", account_name, value);
-                    cons_show("");
-                } else if (strcmp(property, "otr") == 0) {
-                    if ((g_strcmp0(value, "manual") != 0)
-                            && (g_strcmp0(value, "opportunistic") != 0)
-                            && (g_strcmp0(value, "always") != 0)) {
-                        cons_show("OTR policy must be one of: manual, opportunistic or always.");
-                    } else {
-                        accounts_set_otr_policy(account_name, value);
-                        cons_show("Updated OTR policy for account %s: %s", account_name, value);
-                        cons_show("");
-                    }
-                } else if (strcmp(property, "status") == 0) {
-                    if (!valid_resource_presence_string(value) && (strcmp(value, "last") != 0)) {
-                        cons_show("Invalid status: %s", value);
-                    } else {
-                        accounts_set_login_presence(account_name, value);
-                        cons_show("Updated login status for account %s: %s", account_name, value);
-                    }
-                    cons_show("");
-                } else if (strcmp(property, "pgpkeyid") == 0) {
+            accounts_set_login_presence(account_name, value);
+            cons_show("Updated login status for account %s: %s", account_name, value);
+        }
+        cons_show("");
+    } else if (strcmp(property, "pgpkeyid") == 0) {
 #ifdef HAVE_LIBGPGME
-                    char *err_str = NULL;
-                    if (!p_gpg_valid_key(value, &err_str)) {
-                        cons_show("Invalid PGP key ID specified: %s, see /pgp keys", err_str);
-                    } else {
-                        accounts_set_pgp_keyid(account_name, value);
-                        cons_show("Updated PGP key ID for account %s: %s", account_name, value);
-                    }
-                    free(err_str);
+        char *err_str = NULL;
+        if (!p_gpg_valid_key(value, &err_str)) {
+            cons_show("Invalid PGP key ID specified: %s, see /pgp keys", err_str);
+        } else {
+            accounts_set_pgp_keyid(account_name, value);
+            cons_show("Updated PGP key ID for account %s: %s", account_name, value);
+        }
+        free(err_str);
 #else
-                    cons_show("PGP support is not included in this build.");
+        cons_show("PGP support is not included in this build.");
 #endif
-                    cons_show("");
-                } else if (strcmp(property, "startscript") == 0) {
-                    accounts_set_script_start(account_name, value);
-                    cons_show("Updated start script for account %s: %s", account_name, value);
-                } else if (strcmp(property, "theme") == 0) {
-                    if (theme_exists(value)) {
-                        accounts_set_theme(account_name, value);
-                        if (jabber_get_connection_status() == JABBER_CONNECTED) {
-                            ProfAccount *account = accounts_get_account(jabber_get_account_name());
-                            if (account) {
-                                if (g_strcmp0(account->name, account_name) == 0) {
-                                    theme_load(value);
-                                    ui_load_colours();
-                                    if (prefs_get_boolean(PREF_ROSTER)) {
-                                        ui_show_roster();
-                                    } else {
-                                        ui_hide_roster();
-                                    }
-                                    if (prefs_get_boolean(PREF_OCCUPANTS)) {
-                                        ui_show_all_room_rosters();
-                                    } else {
-                                        ui_hide_all_room_rosters();
-                                    }
-                                    ui_redraw();
-                                }
-                                account_free(account);
-                            }
-                        }
-                        cons_show("Updated theme for account %s: %s", account_name, value);
-                    } else {
-                        cons_show("Theme does not exist: %s", value);
-                    }
-                } else if (strcmp(property, "tls") == 0) {
-                    if ((g_strcmp0(value, "force") != 0)
-                            && (g_strcmp0(value, "allow") != 0)
-                            && (g_strcmp0(value, "disable") != 0)) {
-                        cons_show("TLS policy must be one of: force, allow or disable.");
-                    } else {
-                        accounts_set_tls_policy(account_name, value);
-                        cons_show("Updated TLS policy for account %s: %s", account_name, value);
-                        cons_show("");
-                    }
-                } else if (valid_resource_presence_string(property)) {
-                    int intval;
-                    char *err_msg = NULL;
-                    gboolean res = strtoi_range(value, &intval, -128, 127, &err_msg);
-                    if (res) {
-                        resource_presence_t presence_type = resource_presence_from_string(property);
-                        switch (presence_type)
-                        {
-                            case (RESOURCE_ONLINE):
-                                accounts_set_priority_online(account_name, intval);
-                                break;
-                            case (RESOURCE_CHAT):
-                                accounts_set_priority_chat(account_name, intval);
-                                break;
-                            case (RESOURCE_AWAY):
-                                accounts_set_priority_away(account_name, intval);
-                                break;
-                            case (RESOURCE_XA):
-                                accounts_set_priority_xa(account_name, intval);
-                                break;
-                            case (RESOURCE_DND):
-                                accounts_set_priority_dnd(account_name, intval);
-                                break;
+        cons_show("");
+    } else if (strcmp(property, "startscript") == 0) {
+        accounts_set_script_start(account_name, value);
+        cons_show("Updated start script for account %s: %s", account_name, value);
+    } else if (strcmp(property, "theme") == 0) {
+        if (theme_exists(value)) {
+            accounts_set_theme(account_name, value);
+            if (jabber_get_connection_status() == JABBER_CONNECTED) {
+                ProfAccount *account = accounts_get_account(jabber_get_account_name());
+                if (account) {
+                    if (g_strcmp0(account->name, account_name) == 0) {
+                        theme_load(value);
+                        ui_load_colours();
+                        if (prefs_get_boolean(PREF_ROSTER)) {
+                            ui_show_roster();
+                        } else {
+                            ui_hide_roster();
                         }
-
-                        jabber_conn_status_t conn_status = jabber_get_connection_status();
-                        if (conn_status == JABBER_CONNECTED) {
-                            char *connected_account = jabber_get_account_name();
-                            resource_presence_t last_presence = accounts_get_last_presence(connected_account);
-
-                            if (presence_type == last_presence) {
-                                char *message = jabber_get_presence_message();
-                                cl_ev_presence_send(last_presence, message, 0);
-                            }
+                        if (prefs_get_boolean(PREF_OCCUPANTS)) {
+                            ui_show_all_room_rosters();
+                        } else {
+                            ui_hide_all_room_rosters();
                         }
-                        cons_show("Updated %s priority for account %s: %s", property, account_name, value);
-                        cons_show("");
-                    } else {
-                        cons_show(err_msg);
-                        free(err_msg);
+                        ui_redraw();
                     }
-                } else {
-                    cons_show("Invalid property: %s", property);
-                    cons_show("");
+                    account_free(account);
                 }
             }
+            cons_show("Updated theme for account %s: %s", account_name, value);
+        } else {
+            cons_show("Theme does not exist: %s", value);
         }
-    } else if (strcmp(subcmd, "clear") == 0) {
-        if (g_strv_length(args) != 3) {
-            cons_bad_cmd_usage(command);
+    } else if (strcmp(property, "tls") == 0) {
+        if ((g_strcmp0(value, "force") != 0)
+                && (g_strcmp0(value, "allow") != 0)
+                && (g_strcmp0(value, "disable") != 0)) {
+            cons_show("TLS policy must be one of: force, allow or disable.");
         } else {
-            char *account_name = args[1];
-            char *property = args[2];
+            accounts_set_tls_policy(account_name, value);
+            cons_show("Updated TLS policy for account %s: %s", account_name, value);
+            cons_show("");
+        }
+    } else if (valid_resource_presence_string(property)) {
+        int intval;
+        char *err_msg = NULL;
+        gboolean res = strtoi_range(value, &intval, -128, 127, &err_msg);
+        if (res) {
+            resource_presence_t presence_type = resource_presence_from_string(property);
+            switch (presence_type)
+            {
+            case (RESOURCE_ONLINE):
+                accounts_set_priority_online(account_name, intval);
+                break;
+            case (RESOURCE_CHAT):
+                accounts_set_priority_chat(account_name, intval);
+                break;
+            case (RESOURCE_AWAY):
+                accounts_set_priority_away(account_name, intval);
+                break;
+            case (RESOURCE_XA):
+                accounts_set_priority_xa(account_name, intval);
+                break;
+            case (RESOURCE_DND):
+                accounts_set_priority_dnd(account_name, intval);
+                break;
+            }
 
-            if (!accounts_account_exists(account_name)) {
-                cons_show("Account %s doesn't exist", account_name);
-                cons_show("");
-            } else {
-                if (strcmp(property, "password") == 0) {
-                    accounts_clear_password(account_name);
-                    cons_show("Removed password for account %s", account_name);
-                    cons_show("");
-                } else if (strcmp(property, "eval_password") == 0) {
-                    accounts_clear_eval_password(account_name);
-                    cons_show("Removed eval password for account %s", account_name);
-                    cons_show("");
-                } else if (strcmp(property, "server") == 0) {
-                    accounts_clear_server(account_name);
-                    cons_show("Removed server for account %s", account_name);
-                    cons_show("");
-                } else if (strcmp(property, "port") == 0) {
-                    accounts_clear_port(account_name);
-                    cons_show("Removed port for account %s", account_name);
-                    cons_show("");
-                } else if (strcmp(property, "otr") == 0) {
-                    accounts_clear_otr(account_name);
-                    cons_show("OTR policy removed for account %s", account_name);
-                    cons_show("");
-                } else if (strcmp(property, "pgpkeyid") == 0) {
-                    accounts_clear_pgp_keyid(account_name);
-                    cons_show("Removed PGP key ID for account %s", account_name);
-                    cons_show("");
-                } else if (strcmp(property, "startscript") == 0) {
-                    accounts_clear_script_start(account_name);
-                    cons_show("Removed start script for account %s", account_name);
-                    cons_show("");
-                } else if (strcmp(property, "theme") == 0) {
-                    accounts_clear_theme(account_name);
-                    cons_show("Removed theme for account %s", account_name);
-                    cons_show("");
-                } else {
-                    cons_show("Invalid property: %s", property);
-                    cons_show("");
+            jabber_conn_status_t conn_status = jabber_get_connection_status();
+            if (conn_status == JABBER_CONNECTED) {
+                char *connected_account = jabber_get_account_name();
+                resource_presence_t last_presence = accounts_get_last_presence(connected_account);
+                if (presence_type == last_presence) {
+                    char *message = jabber_get_presence_message();
+                    cl_ev_presence_send(last_presence, message, 0);
                 }
             }
+            cons_show("Updated %s priority for account %s: %s", property, account_name, value);
+            cons_show("");
+        } else {
+            cons_show(err_msg);
+            free(err_msg);
         }
     } else {
+        cons_show("Invalid property: %s", property);
+        cons_show("");
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_account_clear(ProfWin *window, const char *const command, gchar **args)
+{
+    if (g_strv_length(args) != 3) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    char *account_name = args[1];
+    if (!accounts_account_exists(account_name)) {
+        cons_show("Account %s doesn't exist", account_name);
+        cons_show("");
+        return TRUE;
+    }
+
+    char *property = args[2];
+    if (strcmp(property, "password") == 0) {
+        accounts_clear_password(account_name);
+        cons_show("Removed password for account %s", account_name);
+        cons_show("");
+    } else if (strcmp(property, "eval_password") == 0) {
+        accounts_clear_eval_password(account_name);
+        cons_show("Removed eval password for account %s", account_name);
+        cons_show("");
+    } else if (strcmp(property, "server") == 0) {
+        accounts_clear_server(account_name);
+        cons_show("Removed server for account %s", account_name);
+        cons_show("");
+    } else if (strcmp(property, "port") == 0) {
+        accounts_clear_port(account_name);
+        cons_show("Removed port for account %s", account_name);
+        cons_show("");
+    } else if (strcmp(property, "otr") == 0) {
+        accounts_clear_otr(account_name);
+        cons_show("OTR policy removed for account %s", account_name);
+        cons_show("");
+    } else if (strcmp(property, "pgpkeyid") == 0) {
+        accounts_clear_pgp_keyid(account_name);
+        cons_show("Removed PGP key ID for account %s", account_name);
+        cons_show("");
+    } else if (strcmp(property, "startscript") == 0) {
+        accounts_clear_script_start(account_name);
+        cons_show("Removed start script for account %s", account_name);
+        cons_show("");
+    } else if (strcmp(property, "theme") == 0) {
+        accounts_clear_theme(account_name);
+        cons_show("Removed theme for account %s", account_name);
+        cons_show("");
+    } else {
+        cons_show("Invalid property: %s", property);
+        cons_show("");
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_account(ProfWin *window, const char *const command, gchar **args)
+{
+    if (args[0] != NULL) {
         cons_bad_cmd_usage(command);
         cons_show("");
+        return TRUE;
+    }
+
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
     }
 
+    ProfAccount *account = accounts_get_account(jabber_get_account_name());
+    cons_show_account(account);
+    account_free(account);
+
     return TRUE;
 }
 
@@ -1082,56 +1164,84 @@ cmd_quit(ProfWin *window, const char *const command, gchar **args)
 }
 
 gboolean
-cmd_wins(ProfWin *window, const char *const command, gchar **args)
+cmd_wins_unread(ProfWin *window, const char *const command, gchar **args)
 {
-    if (args[0] == NULL) {
-        cons_show_wins(FALSE);
-    } else if (strcmp(args[0], "unread") == 0) {
-        cons_show_wins(TRUE);
-    } else if (strcmp(args[0], "tidy") == 0) {
-        if (wins_tidy()) {
-            cons_show("Windows tidied.");
-        } else {
-            cons_show("No tidy needed.");
-        }
-    } else if (strcmp(args[0], "prune") == 0) {
-        ui_prune_wins();
-    } else if (strcmp(args[0], "swap") == 0) {
-        if ((args[1] == NULL) || (args[2] == NULL)) {
-            cons_bad_cmd_usage(command);
-        } else {
-            int source_win = atoi(args[1]);
-            int target_win = atoi(args[2]);
-            if ((source_win == 1) || (target_win == 1)) {
-                cons_show("Cannot move console window.");
-            } else if (source_win == 10 || target_win == 10) {
-                cons_show("Window 10 does not exist");
-            } else if (source_win != target_win) {
-                gboolean swapped = wins_swap(source_win, target_win);
-                if (swapped) {
-                    cons_show("Swapped windows %d <-> %d", source_win, target_win);
-                } else {
-                    cons_show("Window %d does not exist", source_win);
-                }
-            } else {
-                cons_show("Same source and target window supplied.");
-            }
-        }
-    } else if (strcmp(args[0], "autotidy") == 0) {
-        if (g_strcmp0(args[1], "on") == 0) {
-            cons_show("Window autotidy enabled");
-            prefs_set_boolean(PREF_WINS_AUTO_TIDY, TRUE);
-            wins_tidy();
-        } else if (g_strcmp0(args[1], "off") == 0) {
-            cons_show("Window autotidy disabled");
-            prefs_set_boolean(PREF_WINS_AUTO_TIDY, FALSE);
+    cons_show_wins(TRUE);
+    return TRUE;
+}
+
+gboolean
+cmd_wins_tidy(ProfWin *window, const char *const command, gchar **args)
+{
+    if (wins_tidy()) {
+        cons_show("Windows tidied.");
+    } else {
+        cons_show("No tidy needed.");
+    }
+    return TRUE;
+}
+
+gboolean
+cmd_wins_prune(ProfWin *window, const char *const command, gchar **args)
+{
+    ui_prune_wins();
+    return TRUE;
+}
+
+gboolean
+cmd_wins_swap(ProfWin *window, const char *const command, gchar **args)
+{
+    if ((args[1] == NULL) || (args[2] == NULL)) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    int source_win = atoi(args[1]);
+    int target_win = atoi(args[2]);
+    if ((source_win == 1) || (target_win == 1)) {
+        cons_show("Cannot move console window.");
+    } else if (source_win == 10 || target_win == 10) {
+        cons_show("Window 10 does not exist");
+    } else if (source_win != target_win) {
+        gboolean swapped = wins_swap(source_win, target_win);
+        if (swapped) {
+            cons_show("Swapped windows %d <-> %d", source_win, target_win);
         } else {
-            cons_bad_cmd_usage(command);
+            cons_show("Window %d does not exist", source_win);
         }
     } else {
+        cons_show("Same source and target window supplied.");
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_wins_autotidy(ProfWin *window, const char *const command, gchar **args)
+{
+    if (g_strcmp0(args[1], "on") == 0) {
+        cons_show("Window autotidy enabled");
+        prefs_set_boolean(PREF_WINS_AUTO_TIDY, TRUE);
+        wins_tidy();
+    } else if (g_strcmp0(args[1], "off") == 0) {
+        cons_show("Window autotidy disabled");
+        prefs_set_boolean(PREF_WINS_AUTO_TIDY, FALSE);
+    } else {
+        cons_bad_cmd_usage(command);
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_wins(ProfWin *window, const char *const command, gchar **args)
+{
+    if (args[0] != NULL) {
         cons_bad_cmd_usage(command);
+        return TRUE;
     }
 
+    cons_show_wins(FALSE);
     return TRUE;
 }
 
@@ -6019,319 +6129,458 @@ cmd_pgp(ProfWin *window, const char *const command, gchar **args)
 }
 
 gboolean
-cmd_otr(ProfWin *window, const char *const command, gchar **args)
+cmd_otr_char(ProfWin *window, const char *const command, gchar **args)
 {
 #ifdef HAVE_LIBOTR
-    if (args[0] == NULL) {
+    if (args[1] == NULL) {
         cons_bad_cmd_usage(command);
-        return TRUE;
+    } else if (strlen(args[1]) != 1) {
+        cons_bad_cmd_usage(command);
+    } else {
+        prefs_set_otr_char(args[1][0]);
+        cons_show("OTR char set to %c.", args[1][0]);
     }
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
-    if (strcmp(args[0], "char") == 0) {
-        if (args[1] == NULL) {
-            cons_bad_cmd_usage(command);
-        } else if (strlen(args[1]) != 1) {
-            cons_bad_cmd_usage(command);
-        } else {
-            prefs_set_otr_char(args[1][0]);
-            cons_show("OTR char set to %c.", args[1][0]);
-        }
-        return TRUE;
-    } else if (strcmp(args[0], "log") == 0) {
-        char *choice = args[1];
-        if (g_strcmp0(choice, "on") == 0) {
-            prefs_set_string(PREF_OTR_LOG, "on");
-            cons_show("OTR messages will be logged as plaintext.");
-            if (!prefs_get_boolean(PREF_CHLOG)) {
-                cons_show("Chat logging is currently disabled, use '/chlog on' to enable.");
-            }
-        } else if (g_strcmp0(choice, "off") == 0) {
-            prefs_set_string(PREF_OTR_LOG, "off");
-            cons_show("OTR message logging disabled.");
-        } else if (g_strcmp0(choice, "redact") == 0) {
-            prefs_set_string(PREF_OTR_LOG, "redact");
-            cons_show("OTR messages will be logged as '[redacted]'.");
-            if (!prefs_get_boolean(PREF_CHLOG)) {
-                cons_show("Chat logging is currently disabled, use '/chlog on' to enable.");
-            }
-        } else {
-            cons_bad_cmd_usage(command);
+gboolean
+cmd_otr_log(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    char *choice = args[1];
+    if (g_strcmp0(choice, "on") == 0) {
+        prefs_set_string(PREF_OTR_LOG, "on");
+        cons_show("OTR messages will be logged as plaintext.");
+        if (!prefs_get_boolean(PREF_CHLOG)) {
+            cons_show("Chat logging is currently disabled, use '/chlog on' to enable.");
+        }
+    } else if (g_strcmp0(choice, "off") == 0) {
+        prefs_set_string(PREF_OTR_LOG, "off");
+        cons_show("OTR message logging disabled.");
+    } else if (g_strcmp0(choice, "redact") == 0) {
+        prefs_set_string(PREF_OTR_LOG, "redact");
+        cons_show("OTR messages will be logged as '[redacted]'.");
+        if (!prefs_get_boolean(PREF_CHLOG)) {
+            cons_show("Chat logging is currently disabled, use '/chlog on' to enable.");
         }
+    } else {
+        cons_bad_cmd_usage(command);
+    }
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
+
+gboolean
+cmd_otr_libver(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    char *version = otr_libotr_version();
+    cons_show("Using libotr version %s", version);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
+
+gboolean
+cmd_otr_policy(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (args[1] == NULL) {
+        char *policy = prefs_get_string(PREF_OTR_POLICY);
+        cons_show("OTR policy is now set to: %s", policy);
+        prefs_free_string(policy);
         return TRUE;
+    }
 
-    } else if (strcmp(args[0], "libver") == 0) {
-        char *version = otr_libotr_version();
-        cons_show("Using libotr version %s", version);
+    char *choice = args[1];
+    if ((g_strcmp0(choice, "manual") != 0) &&
+            (g_strcmp0(choice, "opportunistic") != 0) &&
+            (g_strcmp0(choice, "always") != 0)) {
+        cons_show("OTR policy can be set to: manual, opportunistic or always.");
         return TRUE;
+    }
 
-    } else if (strcmp(args[0], "policy") == 0) {
-        if (args[1] == NULL) {
-            char *policy = prefs_get_string(PREF_OTR_POLICY);
-            cons_show("OTR policy is now set to: %s", policy);
-            prefs_free_string(policy);
-            return TRUE;
-        }
+    char *contact = args[2];
+    if (contact == NULL) {
+        prefs_set_string(PREF_OTR_POLICY, choice);
+        cons_show("OTR policy is now set to: %s", choice);
+        return TRUE;
+    }
 
-        char *choice = args[1];
-        if ((g_strcmp0(choice, "manual") != 0) &&
-                (g_strcmp0(choice, "opportunistic") != 0) &&
-                (g_strcmp0(choice, "always") != 0)) {
-            cons_show("OTR policy can be set to: manual, opportunistic or always.");
-            return TRUE;
-        }
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected to set the OTR policy for a contact.");
+        return TRUE;
+    }
 
-        char *contact = args[2];
-        if (contact == NULL) {
-            prefs_set_string(PREF_OTR_POLICY, choice);
-            cons_show("OTR policy is now set to: %s", choice);
-            return TRUE;
-        } else {
-            if (jabber_get_connection_status() != JABBER_CONNECTED) {
-                cons_show("You must be connected to set the OTR policy for a contact.");
-                return TRUE;
-            }
-            char *contact_jid = roster_barejid_from_name(contact);
-            if (contact_jid == NULL) {
-                contact_jid = contact;
-            }
-            accounts_add_otr_policy(jabber_get_account_name(), contact_jid, choice);
-            cons_show("OTR policy for %s set to: %s", contact_jid, choice);
-            return TRUE;
-        }
+    char *contact_jid = roster_barejid_from_name(contact);
+    if (contact_jid == NULL) {
+        contact_jid = contact;
     }
+    accounts_add_otr_policy(jabber_get_account_name(), contact_jid, choice);
+    cons_show("OTR policy for %s set to: %s", contact_jid, choice);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
+gboolean
+cmd_otr_gen(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
     if (jabber_get_connection_status() != JABBER_CONNECTED) {
         cons_show("You must be connected with an account to load OTR information.");
         return TRUE;
     }
 
-    if (strcmp(args[0], "gen") == 0) {
-        ProfAccount *account = accounts_get_account(jabber_get_account_name());
-        otr_keygen(account);
-        account_free(account);
-        return TRUE;
-
-    } else if (strcmp(args[0], "myfp") == 0) {
-        if (!otr_key_loaded()) {
-            ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'");
-            return TRUE;
-        }
+    ProfAccount *account = accounts_get_account(jabber_get_account_name());
+    otr_keygen(account);
+    account_free(account);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
-        char *fingerprint = otr_get_my_fingerprint();
-        ui_current_print_formatted_line('!', 0, "Your OTR fingerprint: %s", fingerprint);
-        free(fingerprint);
+gboolean
+cmd_otr_myfp(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
         return TRUE;
+    }
 
-    } else if (strcmp(args[0], "theirfp") == 0) {
-        if (window->type != WIN_CHAT) {
-            ui_current_print_line("You must be in a regular chat window to view a recipient's fingerprint.");
-            return TRUE;
-        }
+    if (!otr_key_loaded()) {
+        ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'");
+        return TRUE;
+    }
 
-        ProfChatWin *chatwin = (ProfChatWin*)window;
-        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        if (chatwin->is_otr == FALSE) {
-            ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
-            return TRUE;
-        }
+    char *fingerprint = otr_get_my_fingerprint();
+    ui_current_print_formatted_line('!', 0, "Your OTR fingerprint: %s", fingerprint);
+    free(fingerprint);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
-        char *fingerprint = otr_get_their_fingerprint(chatwin->barejid);
-        ui_current_print_formatted_line('!', 0, "%s's OTR fingerprint: %s", chatwin->barejid, fingerprint);
-        free(fingerprint);
+gboolean
+cmd_otr_theirfp(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
         return TRUE;
+    }
 
-    } else if (strcmp(args[0], "start") == 0) {
-        // recipient supplied
-        if (args[1]) {
-            char *contact = args[1];
-            char *barejid = roster_barejid_from_name(contact);
-            if (barejid == NULL) {
-                barejid = contact;
-            }
+    if (window->type != WIN_CHAT) {
+        ui_current_print_line("You must be in a regular chat window to view a recipient's fingerprint.");
+        return TRUE;
+    }
 
-            ProfChatWin *chatwin = wins_get_chat(barejid);
-            if (!chatwin) {
-                chatwin = chatwin_new(barejid);
-            }
-            ui_focus_win((ProfWin*)chatwin);
+    ProfChatWin *chatwin = (ProfChatWin*)window;
+    assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+    if (chatwin->is_otr == FALSE) {
+        ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        return TRUE;
+    }
 
-            if (chatwin->pgp_send) {
-                ui_current_print_formatted_line('!', 0, "You must disable PGP encryption before starting an OTR session.");
-                return TRUE;
-            }
+    char *fingerprint = otr_get_their_fingerprint(chatwin->barejid);
+    ui_current_print_formatted_line('!', 0, "%s's OTR fingerprint: %s", chatwin->barejid, fingerprint);
+    free(fingerprint);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
-            if (chatwin->is_otr) {
-                ui_current_print_formatted_line('!', 0, "You are already in an OTR session.");
-                return TRUE;
-            }
+gboolean
+cmd_otr_start(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
+        return TRUE;
+    }
 
-            if (!otr_key_loaded()) {
-                ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'");
-                return TRUE;
-            }
+    // recipient supplied
+    if (args[1]) {
+        char *contact = args[1];
+        char *barejid = roster_barejid_from_name(contact);
+        if (barejid == NULL) {
+            barejid = contact;
+        }
 
-            if (!otr_is_secure(barejid)) {
-                char *otr_query_message = otr_start_query();
-                char *id = message_send_chat_otr(barejid, otr_query_message);
-                free(id);
-                return TRUE;
-            }
+        ProfChatWin *chatwin = wins_get_chat(barejid);
+        if (!chatwin) {
+            chatwin = chatwin_new(barejid);
+        }
+        ui_focus_win((ProfWin*)chatwin);
 
-            chatwin_otr_secured(chatwin, otr_is_trusted(barejid));
+        if (chatwin->pgp_send) {
+            ui_current_print_formatted_line('!', 0, "You must disable PGP encryption before starting an OTR session.");
             return TRUE;
+        }
 
-        // no recipient, use current chat
-        } else {
-            if (window->type != WIN_CHAT) {
-                ui_current_print_line("You must be in a regular chat window to start an OTR session.");
-                return TRUE;
-            }
-
-            ProfChatWin *chatwin = (ProfChatWin*)window;
-            assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-            if (chatwin->pgp_send) {
-                ui_current_print_formatted_line('!', 0, "You must disable PGP encryption before starting an OTR session.");
-                return TRUE;
-            }
-
-            if (chatwin->is_otr) {
-                ui_current_print_formatted_line('!', 0, "You are already in an OTR session.");
-                return TRUE;
-            }
-
-            if (!otr_key_loaded()) {
-                ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'");
-                return TRUE;
-            }
-
-            char *otr_query_message = otr_start_query();
-            char *id = message_send_chat_otr(chatwin->barejid, otr_query_message);
-            free(id);
+        if (chatwin->is_otr) {
+            ui_current_print_formatted_line('!', 0, "You are already in an OTR session.");
             return TRUE;
         }
 
-    } else if (strcmp(args[0], "end") == 0) {
-        if (window->type != WIN_CHAT) {
-            ui_current_print_line("You must be in a regular chat window to use OTR.");
+        if (!otr_key_loaded()) {
+            ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'");
             return TRUE;
         }
 
-        ProfChatWin *chatwin = (ProfChatWin*)window;
-        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        if (chatwin->is_otr == FALSE) {
-            ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        if (!otr_is_secure(barejid)) {
+            char *otr_query_message = otr_start_query();
+            char *id = message_send_chat_otr(barejid, otr_query_message);
+            free(id);
             return TRUE;
         }
 
-        chatwin_otr_unsecured(chatwin);
-        otr_end_session(chatwin->barejid);
+        chatwin_otr_secured(chatwin, otr_is_trusted(barejid));
         return TRUE;
 
-    } else if (strcmp(args[0], "trust") == 0) {
+    // no recipient, use current chat
+    } else {
         if (window->type != WIN_CHAT) {
-            ui_current_print_line("You must be in an OTR session to trust a recipient.");
+            ui_current_print_line("You must be in a regular chat window to start an OTR session.");
             return TRUE;
         }
 
         ProfChatWin *chatwin = (ProfChatWin*)window;
         assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        if (chatwin->is_otr == FALSE) {
-            ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        if (chatwin->pgp_send) {
+            ui_current_print_formatted_line('!', 0, "You must disable PGP encryption before starting an OTR session.");
             return TRUE;
         }
 
-        chatwin_otr_trust(chatwin);
-        otr_trust(chatwin->barejid);
-        return TRUE;
-
-    } else if (strcmp(args[0], "untrust") == 0) {
-        if (window->type != WIN_CHAT) {
-            ui_current_print_line("You must be in an OTR session to untrust a recipient.");
+        if (chatwin->is_otr) {
+            ui_current_print_formatted_line('!', 0, "You are already in an OTR session.");
             return TRUE;
         }
 
-        ProfChatWin *chatwin = (ProfChatWin*)window;
-        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        if (chatwin->is_otr == FALSE) {
-            ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        if (!otr_key_loaded()) {
+            ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'");
             return TRUE;
         }
 
-        chatwin_otr_untrust(chatwin);
-        otr_untrust(chatwin->barejid);
+        char *otr_query_message = otr_start_query();
+        char *id = message_send_chat_otr(chatwin->barejid, otr_query_message);
+        free(id);
         return TRUE;
+    }
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
-    } else if (strcmp(args[0], "secret") == 0) {
-        if (window->type != WIN_CHAT) {
-            ui_current_print_line("You must be in an OTR session to trust a recipient.");
-            return TRUE;
-        }
+gboolean
+cmd_otr_end(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
+        return TRUE;
+    }
 
-        ProfChatWin *chatwin = (ProfChatWin*)window;
-        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        if (chatwin->is_otr == FALSE) {
-            ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
-            return TRUE;
-        }
+    if (window->type != WIN_CHAT) {
+        ui_current_print_line("You must be in a regular chat window to use OTR.");
+        return TRUE;
+    }
 
-        char *secret = args[1];
-        if (secret == NULL) {
-            cons_bad_cmd_usage(command);
-            return TRUE;
-        }
+    ProfChatWin *chatwin = (ProfChatWin*)window;
+    assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+    if (chatwin->is_otr == FALSE) {
+        ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        return TRUE;
+    }
+
+    chatwin_otr_unsecured(chatwin);
+    otr_end_session(chatwin->barejid);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
-        otr_smp_secret(chatwin->barejid, secret);
+gboolean
+cmd_otr_trust(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
         return TRUE;
+    }
 
-    } else if (strcmp(args[0], "question") == 0) {
-        char *question = args[1];
-        char *answer = args[2];
-        if (question == NULL || answer == NULL) {
-            cons_bad_cmd_usage(command);
-            return TRUE;
-        }
+    if (window->type != WIN_CHAT) {
+        ui_current_print_line("You must be in an OTR session to trust a recipient.");
+        return TRUE;
+    }
 
-        if (window->type != WIN_CHAT) {
-            ui_current_print_line("You must be in an OTR session to trust a recipient.");
-            return TRUE;
-        }
+    ProfChatWin *chatwin = (ProfChatWin*)window;
+    assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+    if (chatwin->is_otr == FALSE) {
+        ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        return TRUE;
+    }
 
-        ProfChatWin *chatwin = (ProfChatWin*)window;
-        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        if (chatwin->is_otr == FALSE) {
-            ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
-            return TRUE;
-        }
+    chatwin_otr_trust(chatwin);
+    otr_trust(chatwin->barejid);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
-        otr_smp_question(chatwin->barejid, question, answer);
+gboolean
+cmd_otr_untrust(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
         return TRUE;
+    }
 
-    } else if (strcmp(args[0], "answer") == 0) {
-        if (window->type != WIN_CHAT) {
-            ui_current_print_line("You must be in an OTR session to trust a recipient.");
-            return TRUE;
-        }
+    if (window->type != WIN_CHAT) {
+        ui_current_print_line("You must be in an OTR session to untrust a recipient.");
+        return TRUE;
+    }
 
-        ProfChatWin *chatwin = (ProfChatWin*)window;
-        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        if (chatwin->is_otr == FALSE) {
-            ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
-            return TRUE;
-        }
+    ProfChatWin *chatwin = (ProfChatWin*)window;
+    assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+    if (chatwin->is_otr == FALSE) {
+        ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        return TRUE;
+    }
 
-        char *answer = args[1];
-        if (answer == NULL) {
-            cons_bad_cmd_usage(command);
-            return TRUE;
-        }
+    chatwin_otr_untrust(chatwin);
+    otr_untrust(chatwin->barejid);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
 
-        otr_smp_answer(chatwin->barejid, answer);
+gboolean
+cmd_otr_secret(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
         return TRUE;
+    }
 
-    } else {
+    if (window->type != WIN_CHAT) {
+        ui_current_print_line("You must be in an OTR session to trust a recipient.");
+        return TRUE;
+    }
+
+    ProfChatWin *chatwin = (ProfChatWin*)window;
+    assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+    if (chatwin->is_otr == FALSE) {
+        ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        return TRUE;
+    }
+
+    char *secret = args[1];
+    if (secret == NULL) {
         cons_bad_cmd_usage(command);
         return TRUE;
     }
+
+    otr_smp_secret(chatwin->barejid, secret);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
+
+gboolean
+cmd_otr_question(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
+        return TRUE;
+    }
+
+    char *question = args[1];
+    char *answer = args[2];
+    if (question == NULL || answer == NULL) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    if (window->type != WIN_CHAT) {
+        ui_current_print_line("You must be in an OTR session to trust a recipient.");
+        return TRUE;
+    }
+
+    ProfChatWin *chatwin = (ProfChatWin*)window;
+    assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+    if (chatwin->is_otr == FALSE) {
+        ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        return TRUE;
+    }
+
+    otr_smp_question(chatwin->barejid, question, answer);
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OTR support enabled");
+    return TRUE;
+#endif
+}
+
+gboolean
+cmd_otr_answer(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_LIBOTR
+    if (jabber_get_connection_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OTR information.");
+        return TRUE;
+    }
+
+    if (window->type != WIN_CHAT) {
+        ui_current_print_line("You must be in an OTR session to trust a recipient.");
+        return TRUE;
+    }
+
+    ProfChatWin *chatwin = (ProfChatWin*)window;
+    assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+    if (chatwin->is_otr == FALSE) {
+        ui_current_print_formatted_line('!', 0, "You are not currently in an OTR session.");
+        return TRUE;
+    }
+
+    char *answer = args[1];
+    if (answer == NULL) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    otr_smp_answer(chatwin->barejid, answer);
+    return TRUE;
 #else
     cons_show("This version of Profanity has not been built with OTR support enabled");
     return TRUE;
diff --git a/src/command/commands.h b/src/command/commands.h
index da958bea..68d3947f 100644
--- a/src/command/commands.h
+++ b/src/command/commands.h
@@ -58,19 +58,31 @@ typedef struct cmd_help_t {
  */
 typedef struct cmd_t {
     gchar *cmd;
-    gboolean (*func)(ProfWin *window, const char *const command, gchar **args);
     gchar** (*parser)(const char *const inp, int min, int max, gboolean *result);
     int min_args;
     int max_args;
     void (*setting_func)(void);
+    void *sub_funcs[50][2];
+    gboolean (*func)(ProfWin *window, const char *const command, gchar **args);
     CommandHelp help;
 } Command;
 
 gboolean cmd_execute_alias(ProfWin *window, const char *const inp, gboolean *ran);
 gboolean cmd_execute_default(ProfWin *window, const char *inp);
-
 gboolean cmd_about(ProfWin *window, const char *const command, gchar **args);
+
 gboolean cmd_account(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_list(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_show(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_add(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_remove(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_enable(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_disable(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_rename(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_default(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_set(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_account_clear(ProfWin *window, const char *const command, gchar **args);
+
 gboolean cmd_autoaway(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_autoconnect(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_autoping(ProfWin *window, const char *const command, gchar **args);
@@ -82,7 +94,14 @@ gboolean cmd_chlog(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_clear(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_close(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_connect(ProfWin *window, const char *const command, gchar **args);
-gboolean cmd_tls(ProfWin *window, const char *const command, gchar **args);
+
+gboolean cmd_tls_certpath(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_tls_trust(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_tls_trusted(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_tls_revoke(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_tls_show(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_tls_cert(ProfWin *window, const char *const command, gchar **args);
+
 gboolean cmd_decline(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_disco(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_sendfile(ProfWin *window, const char *const command, gchar **args);
@@ -109,7 +128,22 @@ gboolean cmd_msg(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_nick(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_notify(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_online(ProfWin *window, const char *const command, gchar **args);
-gboolean cmd_otr(ProfWin *window, const char *const command, gchar **args);
+
+gboolean cmd_otr_char(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_log(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_libver(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_policy(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_gen(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_myfp(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_theirfp(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_start(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_end(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_trust(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_untrust(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_secret(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_question(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_otr_answer(ProfWin *window, const char *const command, gchar **args);
+
 gboolean cmd_pgp(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_outtype(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_prefs(ProfWin *window, const char *const command, gchar **args);
@@ -132,7 +166,14 @@ gboolean cmd_titlebar(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_vercheck(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_who(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_win(ProfWin *window, const char *const command, gchar **args);
+
 gboolean cmd_wins(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_wins_unread(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_wins_tidy(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_wins_prune(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_wins_swap(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_wins_autotidy(ProfWin *window, const char *const command, gchar **args);
+
 gboolean cmd_xa(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_alias(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_xmlconsole(ProfWin *window, const char *const command, gchar **args);