about summary refs log tree commit diff stats
path: root/src/command
diff options
context:
space:
mode:
Diffstat (limited to 'src/command')
-rw-r--r--src/command/command.c1439
-rw-r--r--src/command/command.h4
-rw-r--r--src/command/commands.c975
-rw-r--r--src/command/commands.h7
4 files changed, 1332 insertions, 1093 deletions
diff --git a/src/command/command.c b/src/command/command.c
index 1441ef46..1871ea6c 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -1,7 +1,7 @@
 /*
  * command.c
  *
- * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com>
+ * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com>
  *
  * This file is part of Profanity.
  *
@@ -36,6 +36,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 
 #include <glib.h>
@@ -70,8 +71,6 @@
 typedef char*(*autocompleter)(char*, int*);
 
 static gboolean _cmd_execute(const char * const command, const char * const inp);
-static gboolean _cmd_execute_default(const char * inp);
-static gboolean _cmd_execute_alias(const char * const inp, gboolean *ran);
 
 static char * _cmd_complete_parameters(const char * const input);
 
@@ -101,6 +100,8 @@ static char * _role_autocomplete(const char * const input);
 static char * _resource_autocomplete(const char * const input);
 static char * _titlebar_autocomplete(const char * const input);
 static char * _inpblock_autocomplete(const char * const input);
+static char * _time_autocomplete(const char * const input);
+static char * _receipts_autocomplete(const char * const input);
 
 GHashTable *commands = NULL;
 
@@ -111,18 +112,19 @@ static struct cmd_t command_defs[] =
 {
     { "/help",
         cmd_help, parse_args, 0, 1, NULL,
-        { "/help [area|command]", "Get help on using Profanity.",
+        { "/help [area|command]", "Help on using Profanity.",
         { "/help [area|command]",
-          "-------------------------",
-          "Use with no arguments to get a help summary.",
-          "Supply an area to see help for commands related to specific features.",
-          "Supply a command (without the leading slash) to see help for that command.",
+          "--------------------",
+          "Help on using Profanity.",
+          "",
+          "area    : Summary help for commands in a certain area of functionality.",
+          "command : Full help for a specific command, for example '/help connect'.",
           "",
-          "Example : /help commands",
-          "Example : /help presence",
-          "Example : /help who",
+          "Use with no arguments to see a list of areas.",
           "",
-          "For more detailed help, see the user guide at http://www.profanity.im/userguide.html.",
+          "Example: /help commands",
+          "Example: /help presence",
+          "Example: /help who",
           NULL } } },
 
     { "/about",
@@ -135,15 +137,17 @@ static struct cmd_t command_defs[] =
 
     { "/connect",
         cmd_connect, parse_args, 0, 5, NULL,
-        { "/connect [account] [server value] [port value]", "Login to a chat service.",
+        { "/connect [account] [server value] [port value]", "Account login.",
         { "/connect [account] [server value] [port value]",
           "----------------------------------------------",
-          "Connect to an XMPP service using the specified account.",
-          "Use the server property to specify a server if required.",
-          "Change the default port (5222, or 5223 for SSL) with the port property.",
-          "An account is automatically created if one does not exist.",
-          "If no account is specified, then the default account is used."
-          "See the /account command for more details.",
+          "Login to a chat service.",
+          "",
+          "account      : The local account you wish to connect with, or a JID if connecting for the first time.",
+          "server value : Supply a server if it is different to the domain part of your JID.",
+          "port value   : The port to use if different to the default (5222, or 5223 for SSL).",
+          "",
+          "If no account is specified, the default is used if one is configured.",
+          "A local account is created with the JID as it's name if it doesn't already exist.",
           "",
           "Example: /connect",
           "Example: /connect myuser@gmail.com",
@@ -162,48 +166,57 @@ static struct cmd_t command_defs[] =
 
     { "/msg",
         cmd_msg, parse_args_with_freetext, 1, 2, NULL,
-        { "/msg contact|nick [message]", "Start chat with user.",
+        { "/msg contact|nick [message]", "Start chat with a user.",
         { "/msg contact|nick [message]",
           "---------------------------",
-          "Open a chat window for the contact and send the message if one is supplied.",
-          "When in a chat room, supply a nickname to start private chat with a room member.",
+          "Send a one to one chat message, or a private message to a chat room occupant.",
+          "",
+          "contact : The contact's JID, or nickname if one has been set in your roster.",
+          "nick    : A chat room occupant, to whom you wish to send a private message.",
+          "message : The message to send",
+          "",
+          "If the message is omitted, a new chat window will be opened without sending a message.",
           "Use quotes if the nickname includes spaces.",
           "",
-          "Example : /msg myfriend@server.com Hey, here's a message!",
-          "Example : /msg otherfriend@server.com",
-          "Example : /msg Bob Here is a private message",
-          "Example : /msg \"My Friend\" Hi, how are you?",
+          "Example: /msg myfriend@server.com Hey, here's a message!",
+          "Example: /msg otherfriend@server.com",
+          "Example: /msg Bob Here is a private message",
+          "Example: /msg \"My Friend\" Hi, how are you?",
           NULL } } },
 
     { "/roster",
         cmd_roster, parse_args_with_freetext, 0, 3, NULL,
-        { "/roster [online|show|hide|by|size|add|remove|nick|clearnick] [offline|resource] [percent] [group|presence|none] [jid] [nickname]", "Manage your roster.",
-        { "/roster [online|show|hide|by|size|add|remove|nick|clearnick] [offline|resource] [percent] [group|presence|none] [jid] [nickname]",
-          "-------------------------------------------------------------------------------------------------------------------------",
-          "View, add to, and remove from your roster.",
+        { "/roster [command] [args..]", "Manage your roster.",
+        { "/roster [command] [args..]",
+          "--------------------------",
+          "Manage your roster, and roster display settings.",
+          "",
+          "command - online|show|hide|by|size|add|remove|nick|clearnick",
+          "",
+          "online         : Show all online contacts in your roster.",
+          "show           : Show the roster panel.",
+          "show offline   : Show offline contacts in the roster panel.",
+          "show resource  : Show contact's connected resources in the roster panel.",
+          "hide           : Hide the roster panel.",
+          "hide offline   : Hide offline contacts in the roster panel.",
+          "hide resource  : Hide contact's connected resources in the roster panel.",
+          "by group       : Group contacts in the roster panel by roster group.",
+          "by presence    : Group contacts in the roster panel by presence.",
+          "by none        : No grouping in the roster panel.",
+          "size           : Percentage of the screen taken up by the roster (1-99).",
+          "add jid [nick] : Add a new item to the roster.",
+          "remove jid     : Removes an item from the roster.",
+          "nick jid nick  : Change a contacts nickname.",
+          "clearnick jid  : Removes the current nickname.",
+          "",
           "Passing no arguments lists all contacts in your roster.",
-          "online        - Show all online contacts in your roster.",
-          "show          - Show the roster panel in the console window.",
-          "hide          - Hide the roster panel.",
-          "show offline  - Show offline contacts in the roster panel.",
-          "hide offline  - Hide offline contacts in the roster panel.",
-          "show resource - Show contact's connected resources in the roster panel.",
-          "hide resource - Hide contact's connected resources in the roster panel.",
-          "by group      - Group contacts in the roster panel by roster group.",
-          "by presence   - Group contacts in the roster panel by presence.",
-          "by none       - No grouping in the roster panel.",
-          "size          - Percentage of the screen taken up by the roster (1-99).",
-          "add           - Add a new item, jid is required, nickname is optional.",
-          "remove        - Removes a contact, jid is required.",
-          "nick          - Changes a contacts nickname, both jid and nickname are required,",
-          "clearnick     - Removes the current nickname, jid is required.",
-          "",
-          "Example : /roster (show your roster)",
-          "Example : /roster add someone@contacts.org (add the contact)",
-          "Example : /roster add someone@contacts.org Buddy (add the contact with nickname 'Buddy')",
-          "Example : /roster remove someone@contacts.org (remove the contact)",
-          "Example : /roster nick myfriend@chat.org My Friend",
-          "Example : /roster clearnick kai@server.com (clears nickname)",
+          "",
+          "Example: /roster (show your roster)",
+          "Example: /roster add someone@contacts.org (add the contact)",
+          "Example: /roster add someone@contacts.org Buddy (add the contact with nickname 'Buddy')",
+          "Example: /roster remove someone@contacts.org (remove the contact)",
+          "Example: /roster nick myfriend@chat.org My Friend",
+          "Example: /roster clearnick kai@server.com (clears nickname)",
           NULL } } },
 
     { "/group",
@@ -212,31 +225,35 @@ static struct cmd_t command_defs[] =
         { "/group [show|add|remove] [group] [contact]",
           "------------------------------------------",
           "View, add to, and remove from roster groups.",
+          "",
+          "show group           : List all roster items a group.",
+          "add group contact    : Added a contact to a group.",
+          "remove group contact : Remove a contact from a group.",
+          "",
           "Passing no argument will list all roster groups.",
-          "The 'show' command takes 'group' as an argument, and lists all roster items in that group.",
-          "The 'add' command takes 'group' and 'contact' arguments, and adds the contact to the group.",
-          "The 'remove' command takes 'group' and 'contact' arguments and removes the contact from the group,",
           "",
-          "Example : /group",
-          "Example : /group show friends",
-          "Example : /group add friends newfriend@server.org",
-          "Example : /group add family Brother (using contacts nickname)",
-          "Example : /group remove colleagues boss@work.com",
+          "Example: /group",
+          "Example: /group show friends",
+          "Example: /group add friends newfriend@server.org",
+          "Example: /group add family Brother (using contacts nickname)",
+          "Example: /group remove colleagues boss@work.com",
           NULL } } },
 
     { "/info",
         cmd_info, parse_args, 0, 1, NULL,
-        { "/info [contact|nick]", "Show basic information about a contact, room, or room member.",
+        { "/info [contact|nick]", "Show information about a contact, room, or room member.",
         { "/info [contact|nick]",
           "--------------------",
-          "Show basic information about a contact, room, or room member.",
-          "If in the console, a contact must be specified.",
-          "If in a chat window the parameter is not required, the current recipient will be used.",
-          "If in a chat room, providing no arguments will display information about the room.",
-          "If in a chat room, supplying a nick will show information about the occupant.",
+          "Show information about a contact, room, or room member.",
           "",
-          "Example : /info mybuddy@chat.server.org",
-          "Example : /info kai",
+          "contact : The contact you wish to view information about.",
+          "nick    : When in a chat room, the occupant you wish to view information about.",
+          "",
+          "Passing no argument in a chat window will use the current recipient.",
+          "Passing no argument in a chat room will display information about the room.",
+          "",
+          "Example: /info mybuddy@chat.server.org",
+          "Example: /info kai",
           NULL } } },
 
     { "/caps",
@@ -244,14 +261,16 @@ static struct cmd_t command_defs[] =
         { "/caps [fulljid|nick]", "Find out a contacts client software capabilities.",
         { "/caps [fulljid|nick]",
           "--------------------",
-          "Find out a contact, or room members client software capabilities.",
-          "If in the console window or a regular chat window, a full JID is required.",
-          "If in a chat room, the nickname is required.",
-          "If in private chat, no parameter is required.",
+          "Find out a contacts, or room members client software capabilities.",
+          "",
+          "fulljid : If in the console or a chat window, the full JID for which you wish to see capabilities.",
+          "nick    : If in a chat room, nickname for which you wish to see capabilities.",
+          "",
+          "If in private chat initiated from a chat room, no parameter is required.",
           "",
-          "Example : /caps mybuddy@chat.server.org/laptop (contact's laptop resource)",
-          "Example : /caps mybuddy@chat.server.org/phone (contact's phone resource)",
-          "Example : /caps bruce (room member)",
+          "Example: /caps mybuddy@chat.server.org/laptop (contact's laptop resource)",
+          "Example: /caps mybuddy@chat.server.org/phone (contact's phone resource)",
+          "Example: /caps bruce (room member)",
           NULL } } },
 
     { "/software",
@@ -259,15 +278,17 @@ static struct cmd_t command_defs[] =
         { "/software [fulljid|nick]", "Find out software version information about a contacts resource.",
         { "/software [fulljid|nick]",
           "------------------------",
-          "Find out a contact, or room members software version information, if such requests are supported.",
-          "If in the console window or a regular chat window, a full JID is required.",
-          "If in a chat room, the nickname is required.",
-          "If in private chat, no parameter is required.",
+          "Find out a contact, or room members software version information.",
+          "",
+          "fulljid : If in the console or a chat window, the full JID for which you wish to see software information.",
+          "nick    : If in a chat room, nickname for which you wish to see software information.",
+          "",
+          "If in private chat initiated from a chat room, no parameter is required.",
           "If the contact's software does not support software version requests, nothing will be displayed.",
           "",
-          "Example : /software mybuddy@chat.server.org/laptop (contact's laptop resource)",
-          "Example : /software mybuddy@chat.server.org/phone (contact's phone resource)",
-          "Example : /software bruce (room member)",
+          "Example: /software mybuddy@chat.server.org/laptop (contact's laptop resource)",
+          "Example: /software mybuddy@chat.server.org/phone (contact's phone resource)",
+          "Example: /software bruce (room member)",
           NULL } } },
 
     { "/status",
@@ -276,39 +297,49 @@ static struct cmd_t command_defs[] =
         { "/status [contact|nick]",
           "----------------------",
           "Find out a contact, or room members presence information.",
+          "",
+          "contact : The contact who's presence you which to see.",
+          "nick    : If in a chat room, the occupant who's presence you wish to see.",
+          "",
           "If in a chat window the parameter is not required, the current recipient will be used.",
           "",
-          "Example : /status buddy@server.com",
-          "Example : /status jon",
+          "Example: /status buddy@server.com",
+          "Example: /status jon",
           NULL } } },
 
     { "/resource",
         cmd_resource, parse_args, 1, 2, &cons_resource_setting,
-        { "/resource set|off|title|message [resource]", "Set the contact's resource.",
+        { "/resource set|off|title|message [resource]", "Set the contact's resource, display settings.",
         { "/resource set|off|title|message [resource]",
           "------------------------------------------",
-          "Set the resource to use when chatting to a contact and manage resource display settings.",
-          "set resource   - Set the resource.",
-          "off            - Let the server choose which resource to route messages to.",
-          "title on|off   - Show or hide the current resource in the titlebar.",
-          "message on|off - Show or hide the resource from which a message was recieved.",
+          "Override chat session resource, and manage resource display settings.",
+          "",
+          "set resource   : Set the resource to which messages will be sent.",
+          "off            : Let the server choose which resource to route messages to.",
+          "title on|off   : Show or hide the current resource in the titlebar.",
+          "message on|off : Show or hide the resource when showing an incoming message.",
           NULL } } },
 
     { "/join",
-        cmd_join, parse_args, 1, 5, NULL,
-        { "/join room[@server] [nick value] [password value]", "Join a chat room.",
-        { "/join room[@server] [nick value] [password value]",
-          "-------------------------------------------------",
+        cmd_join, parse_args, 0, 5, NULL,
+        { "/join [room] [nick value] [password value]", "Join a chat room.",
+        { "/join [room] [nick value] [password value]",
+          "-----------------------------------------",
           "Join a chat room at the conference server.",
-          "If nick is specified you will join with this nickname.",
-          "Otherwise the account preference 'muc.nick' will be used which by default is the localpart of your JID (before the @).",
-          "If no server is supplied, the account preference 'muc.service' is used, which is 'conference.<domain-part>' by default.",
+          "",
+          "room           : Bare room JID (the chat server is determined by the 'muc.service' account property) or full room jid."
+          "nick value     : Nickname to use in the room",
+          "password value : Password if the room requires it.",
+          "",
+          "If no room is supplied, a generated name will be used with the format private-chat-[UUID].",
+          "If no nickname is specified the account preference 'muc.nick' will be used which by default is the localpart of your JID.",
           "If the room doesn't exist, and the server allows it, a new one will be created.",
           "",
-          "Example : /join jdev@conference.jabber.org",
-          "Example : /join jdev@conference.jabber.org nick mynick",
-          "Example : /join private@conference.jabber.org nick mynick password mypassword",
-          "Example : /join jdev (as user@jabber.org will join jdev@conference.jabber.org)",
+          "Example: /join",
+          "Example: /join jdev@conference.jabber.org",
+          "Example: /join jdev@conference.jabber.org nick mynick",
+          "Example: /join private@conference.jabber.org nick mynick password mypassword",
+          "Example: /join jdev (as user@jabber.org will join jdev@conference.jabber.org)",
           NULL } } },
 
     { "/leave",
@@ -324,8 +355,10 @@ static struct cmd_t command_defs[] =
         { "/invite contact [message]", "Invite contact to chat room.",
         { "/invite contact [message]",
           "-------------------------",
-          "Send a direct invite to the specified contact to the current chat room.",
-          "If a message is supplied it will be sent as the reason for the invite.",
+          "Send a direct invite to the current chat room.",
+          "",
+          "contact : The contact you wish to invite",
+          "message : An optional message to send with the invite.",
           NULL } } },
 
     { "/invites",
@@ -333,9 +366,7 @@ static struct cmd_t command_defs[] =
         { "/invites", "Show outstanding chat room invites.",
         { "/invites",
           "--------",
-          "Show all rooms that you have been invited to, and have not yet been accepted or declind.",
-          "Use \"/join <room>\" to accept a room invitation.",
-          "Use \"/decline <room>\" to decline a room invitation.",
+          "Show all rooms that you have been invited to, and not accepted or declined.",
           NULL } } },
 
     { "/decline",
@@ -343,7 +374,9 @@ static struct cmd_t command_defs[] =
         { "/decline room", "Decline a chat room invite.",
         { "/decline room",
           "-------------",
-          "Decline invitation to a chat room, the room will no longer be in the list of outstanding invites.",
+          "Decline a chat room invitation.",
+          "",
+          "room : The room for the invite you wish to decline.",
           NULL } } },
 
     { "/room",
@@ -351,9 +384,11 @@ static struct cmd_t command_defs[] =
         { "/room accept|destroy|config", "Room configuration.",
         { "/room accept|destroy|config",
           "---------------------------",
-          "accept  - Accept default room configuration.",
-          "destroy - Reject default room configuration.",
-          "config  - Edit room configuration.",
+          "Chat room configuration.",
+          "",
+          "accept  : Accept default room configuration.",
+          "destroy : Reject default room configuration.",
+          "config  : Edit room configuration.",
           NULL } } },
 
     { "/kick",
@@ -361,8 +396,10 @@ static struct cmd_t command_defs[] =
         { "/kick nick [reason]", "Kick occupants from chat rooms.",
         { "/kick nick [reason]",
           "-------------------",
-          "nick   - Nickname of the occupant to kick from the room.",
-          "reason - Optional reason for kicking the occupant.",
+          "Kick occupants from chat rooms.",
+          "",
+          "nick   : Nickname of the occupant to kick from the room.",
+          "reason : Optional reason for kicking the occupant.",
           NULL } } },
 
     { "/ban",
@@ -370,8 +407,10 @@ static struct cmd_t command_defs[] =
         { "/ban jid [reason]", "Ban users from chat rooms.",
         { "/ban jid [reason]",
           "-----------------",
-          "jid    - Bare JID of the user to ban from the room.",
-          "reason - Optional reason for banning the user.",
+          "Ban users from chat rooms.",
+          "",
+          "jid    : Bare JID of the user to ban from the room.",
+          "reason : Optional reason for banning the user.",
           NULL } } },
 
     { "/subject",
@@ -379,8 +418,10 @@ static struct cmd_t command_defs[] =
         { "/subject set|clear [subject]", "Set or clear room subject.",
         { "/subject set|clear [subject]",
           "----------------------------",
-          "set subject  - Set the room subject.",
-          "clear        - Clear the room subject.",
+          "Set or clear room subject.",
+          "",
+          "set subject  : Set the room subject.",
+          "clear        : Clear the room subject.",
           NULL } } },
 
     { "/affiliation",
@@ -388,8 +429,11 @@ static struct cmd_t command_defs[] =
         { "/affiliation set|list [affiliation] [jid] [reason]", "Manage room affiliations.",
         { "/affiliation set|list [affiliation] [jid] [reason]",
           "--------------------------------------------------",
-          "set affiliation jid [reason]- Set the affiliation of user with jid, with an optional reason.",
-          "list [affiliation]          - List all users with the specified affiliation, or all if none specified.",
+          "Manage room affiliations.",
+          "",
+          "set affiliation jid [reason]: Set the affiliation of user with jid, with an optional reason.",
+          "list [affiliation]          : List all users with the specified affiliation, or all if none specified.",
+          "",
           "The affiliation may be one of owner, admin, member, outcast or none.",
           NULL } } },
 
@@ -398,20 +442,28 @@ static struct cmd_t command_defs[] =
         { "/role set|list [role] [nick] [reason]", "Manage room roles.",
         { "/role set|list [role] [nick] [reason]",
           "-------------------------------------",
-          "set role nick [reason] - Set the role of occupant with nick, with an optional reason.",
-          "list [role]            - List all occupants with the specified role, or all if none specified.",
+          "Manage room roles.",
+          "",
+          "set role nick [reason] : Set the role of occupant with nick, with an optional reason.",
+          "list [role]            : List all occupants with the specified role, or all if none specified.",
+          "",
           "The role may be one of moderator, participant, visitor or none.",
           NULL } } },
 
     { "/occupants",
-        cmd_occupants, parse_args, 1, 2, cons_occupants_setting,
-        { "/occupants show|hide|default|size [show|hide] [percent]", "Show or hide room occupants.",
-        { "/occupants show|hide|default|size [show|hide] [percent]",
-          "-------------------------------------------------------",
-          "show    - Show the occupants panel in chat rooms.",
-          "hide    - Hide the occupants panel in chat rooms.",
-          "default - Whether occupants are shown by default in new rooms, 'show' or 'hide'",
-          "size    - Percentage of the screen taken by the occupants list in rooms (1-99).",
+        cmd_occupants, parse_args, 1, 3, cons_occupants_setting,
+        { "/occupants show|hide|default|size [jid|show|hide|percent] [jid]", "Show or hide room occupants.",
+        { "/occupants show|hide|default|size [jid|show|hide|percent] [jid]",
+          "---------------------------------------------------------------",
+          "Show or hide room occupants, and occupants panel display settings.",
+          "",
+          "show                    : Show the occupants panel in current room.",
+          "hide                    : Hide the occupants panel in current room.",
+          "show jid                : Show jid in the occupants panel in current room.",
+          "hide jid                : Hide jid in the occupants panel in current room.",
+          "default show|hide       : Whether occupants are shown by default in new rooms.",
+          "default show|hide jid   : Whether occupants jids are shown by default in new rooms.",
+          "size percent            : Percentage of the screen taken by the occupants list in rooms (1-99).",
           NULL } } },
 
     { "/form",
@@ -419,10 +471,12 @@ static struct cmd_t command_defs[] =
         { "/form show|submit|cancel|help [tag]", "Form handling.",
         { "/form show|submit|cancel|help [tag]",
           "-----------------------------------",
-          "show             - Show the current form.",
-          "submit           - Submit the current form.",
-          "cancel           - Cancel changes to the current form.",
-          "help [tag]       - Display help for form, or a specific field.",
+          "Form configuration.",
+          "",
+          "show             : Show the current form.",
+          "submit           : Submit the current form.",
+          "cancel           : Cancel changes to the current form.",
+          "help [tag]       : Display help for form, or a specific field.",
           NULL } } },
 
     { "/rooms",
@@ -431,45 +485,51 @@ static struct cmd_t command_defs[] =
         { "/rooms [conference-service]",
           "---------------------------",
           "List the chat rooms available at the specified conference service",
-          "If no argument is supplied, the account preference 'muc.service' is used, which is 'conference.<domain-part>' by default.",
           "",
-          "Example : /rooms conference.jabber.org",
-          "Example : /rooms (if logged in as me@server.org, is equivalent to /rooms conference.server.org)",
+          "conference-service : The conference service to query.",
+          "",
+          "If no argument is supplied, the account preference 'muc.service' is used, 'conference.<domain-part>' by default.",
+          "",
+          "Example: /rooms conference.jabber.org",
+          "Example: /rooms (if logged in as me@server.org, is equivalent to /rooms conference.server.org)",
           NULL } } },
 
     { "/bookmark",
         cmd_bookmark, parse_args, 0, 8, NULL,
-        { "/bookmark [list|add|update|remove|join] [room@server] [nick value] [password value] [autojoin on|off]", "Manage bookmarks.",
-        { "/bookmark [list|add|update|remove|join] [room@server] [nick value] [password value] [autojoin on|off]",
-          "---------------------------------------------------------------------------------------------------",
-          "Manage bookmarks.",
-          "list: List all bookmarks.",
-          "add: Add a bookmark for room@server with the following optional properties:",
-          "  nick: Nickname used in the chat room",
-          "  password: Password for private rooms, note this may be stored in plaintext on your server",
-          "  autojoin: Whether to join the room automatically on login \"on\" or \"off\".",
-          "update: Update any of the above properties associated with the bookmark.",
-          "remove: Remove the bookmark for room@server.",
-          "join: Join room@server using the properties associated with the bookmark.",
-          "When in a chat room, the /bookmark command with no arguments will bookmark the current room with the current settings, and set autojoin to \"on\".",
+        { "/bookmark [command] [args..]", "Manage bookmarks.",
+        { "/bookmark [command] [args..]",
+          "----------------------------",
+          "Manage bookmarks and join bookmarked rooms.",
+          "",
+          "command : list|add|update|remove|join",
+          "",
+          "list                              : List all bookmarks.",
+          "add room@server [prop value..]    : Add a bookmark for room@server with the following optional properties:",
+          "  nick value                      : Nickname used in the chat room",
+          "  password value                  : Password if required, may be stored in plaintext on your server",
+          "  autojoin on|off                 : Whether to join the room automatically on login.",
+          "update room@server [prop value..] : Update any of the above properties associated with the bookmark.",
+          "remove room@server                : Remove the bookmark for room@server.",
+          "join room@server                  : Join room using the properties associated with the bookmark.",
+          "",
+          "In a chat room, /bookmark with no arguments will bookmark the current room, setting autojoin to \"on\".",
           NULL } } },
 
     { "/disco",
         cmd_disco, parse_args, 1, 2, NULL,
-        { "/disco command entity", "Service discovery.",
-        { "/disco command entity",
+        { "/disco info|items entity", "Service discovery.",
+        { "/disco info|items entity",
           "---------------------",
           "Find out information about an entities supported services.",
-          "Command may be one of:",
-          "info: List protocols and features supported by an entity.",
-          "items: List items associated with an entity.",
           "",
-          "The entity must be a Jabber ID.",
+          "info   : List protocols and features supported by an entity.",
+          "items  : List items associated with an entity.",
+          "entity : Jabber ID.",
           "",
-          "Example : /disco info myserver.org",
-          "Example : /disco items myserver.org",
-          "Example : /disco items conference.jabber.org",
-          "Example : /disco info myfriend@server.com/laptop",
+          "Example: /disco info myserver.org",
+          "Example: /disco items myserver.org",
+          "Example: /disco items conference.jabber.org",
+          "Example: /disco info myfriend@server.com/laptop",
           NULL } } },
 
     { "/nick",
@@ -478,47 +538,52 @@ static struct cmd_t command_defs[] =
         { "/nick nickname",
           "--------------",
           "Change the name by which other members of a chat room see you.",
-          "This command is only valid when called within a chat room window.",
           "",
-          "Example : /nick kai hansen",
-          "Example : /nick bob",
+          "nickname : The new nickname.",
+          "",
+          "Example: /nick kai hansen",
+          "Example: /nick bob",
           NULL } } },
 
     { "/win",
         cmd_win, parse_args, 1, 1, NULL,
         { "/win num", "View a window.",
         { "/win num",
-          "------------------",
+          "--------",
           "Show the contents of a specific window in the main window area.",
+          "",
+          "num - Window number to display.",
           NULL } } },
 
     { "/wins",
         cmd_wins, parse_args, 0, 3, NULL,
-        { "/wins [tidy|prune|swap] [source] [target]", "List or tidy active windows.",
-        { "/wins [tidy|prune|swap] [source] [target]",
-          "-----------------------------------------",
-          "Passing no argument will list all currently active windows and information about their usage.",
-          "tidy               : Shuffle windows so there are no gaps.",
+        { "/wins [tidy|prune|swap] [source target]", "List or tidy active windows.",
+        { "/wins [tidy|prune|swap] [source target]",
+          "---------------------------------------",
+          "Show a list of windows, or tidy or swap.",
+          "",
+          "tidy               : Move windows so there are no gaps.",
           "prune              : Close all windows with no unread messages, and then tidy as above.",
           "swap source target : Swap windows, target may be an empty position.",
+          "",
+          "Passing no argument will list all currently active windows and information about their usage.",
           NULL } } },
 
     { "/sub",
         cmd_sub, parse_args, 1, 2, NULL,
-        { "/sub command [jid]", "Manage subscriptions.",
-        { "/sub command [jid]",
-          "------------------",
-          "command : One of the following,",
-          "request  : Send a subscription request to the user to be informed of their",
-          "         : presence.",
-          "allow    : Approve a contact's subscription reqeust to see your presence.",
-          "deny     : Remove subscription for a contact, or deny a request",
-          "show     : Show subscriprion status for a contact.",
-          "sent     : Show all sent subscription requests pending a response.",
-          "received : Show all received subscription requests awaiting your response.",
-          "",
-          "The optional 'jid' parameter only applys to 'request', 'allow', 'deny' and 'show'",
-          "If it is omitted the contact of the current window is used.",
+        { "/sub request|allow|deny|show|sent|received [jid]", "Manage subscriptions.",
+        { "/sub request|allow|deny|show|sent|received [jid]",
+          "------------------------------------------------",
+          "Manage subscriptions to contact presence.",
+          "",
+          "request [jid] : Send a subscription request to the user.",
+          "allow [jid]   : Approve a contact's subscription request.",
+          "deny [jid]    : Remove subscription for a contact, or deny a request",
+          "show [jid]    : Show subscription status for a contact.",
+          "sent          : Show all sent subscription requests pending a response.",
+          "received      : Show all received subscription requests awaiting your response.",
+          "",
+          "If jid is omitted, the contact of the current window is used.",
           "",
           "Example: /sub request myfriend@jabber.org",
           "Example: /sub allow myfriend@jabber.org",
@@ -531,9 +596,11 @@ static struct cmd_t command_defs[] =
         { "/tiny url", "Send url as tinyurl in current chat.",
         { "/tiny url",
           "---------",
-          "Send the url as a tiny url.",
+          "Send url as tinyurl in current chat.",
+          "",
+          "url : The url to make tiny.",
           "",
-          "Example : /tiny http://www.profanity.im",
+          "Example: /tiny http://www.profanity.im",
           NULL } } },
 
     { "/who",
@@ -541,31 +608,30 @@ static struct cmd_t command_defs[] =
         { "/who [status|role|affiliation] [group]", "Show contacts/room occupants with chosen status, role or affiliation",
         { "/who [status|role|affiliation] [group]",
           "--------------------------------------",
-          "Normal usage:",
-          "Status may be one of - online, offline, away, dnd, xa, chat, available, unavailable, or any where:",
-          "online      : Contacts that are online, chat, away, xa, dnd",
-          "available   : Contacts that are available for chat - online, chat.",
-          "unavailable : Contacts that are not available for chat - offline, away, xa, dnd.",
-          "any         : Contacts with any status (same as calling with no argument).",
+          "Show contacts/room occupants with chosen status, role or affiliation",
           "",
-          "The group argument filters the list by that group.",
-          "",
-          "In a chat room, a role or affiliation may also be supplied instead of status.",
-          "Roles: moderator, participant, visitor",
-          "Affiliations: owner, admin, member",
+          "status : online|offline|away|dnd|xa|chat|available|unavailable|any",
+          "  online      : Contacts that are online, chat, away, xa, dnd",
+          "  available   : Contacts that are available for chat - online, chat.",
+          "  unavailable : Contacts that are not available for chat - offline, away, xa, dnd.",
+          "  any         : Contacts with any status (same as calling with no argument).",
+          "role        : moderator|participant|visitor",
+          "affiliation : owner|admin|member",
+          "group       : Filter the results by the specified group.",
           NULL } } },
 
     { "/close",
         cmd_close, parse_args, 0, 1, NULL,
-        { "/close [win|read|all]", "Close windows.",
-        { "/close [win|read|all]",
+        { "/close [num|read|all]", "Close windows.",
+        { "/close [num|read|all]",
           "---------------------",
+          "Close the current window, or a number of windows.",
+          "",
+          "num  : Close the specified window.",
+          "all  : Close all windows.",
+          "read : Close all windows that have no new messages.",
+          "",
           "Passing no argument will close the current window.",
-          "2,3,4,5,6,7,8,9 or 0 : Close the specified window.",
-          "all                  : Close all currently open windows.",
-          "read                 : Close all windows that have no new messages.",
-          "The console window cannot be closed.",
-          "If in a chat room, you will leave the room.",
           NULL } } },
 
     { "/clear",
@@ -588,8 +654,8 @@ static struct cmd_t command_defs[] =
         cmd_privileges, parse_args, 1, 1, &cons_privileges_setting,
         { "/privileges on|off", "Show occupant privileges in chat rooms.",
         { "/privileges on|off",
-          "---------------------------",
-          "If enabled the room roster will be broken down my role, and role information will be showin in the room.",
+          "------------------",
+          "If enabled the room occupants panel will be grouped by role, and role information will be shown in the room.",
           NULL } } },
 
     { "/beep",
@@ -607,7 +673,7 @@ static struct cmd_t command_defs[] =
         { "/presence on|off", "Show the contacts presence in the titlebar.",
         { "/presence on|off",
           "----------------",
-          "Switch display of the contacts presence on or off.",
+          "Switch display of the contacts presence in the titlebar on or off.",
           NULL } } },
 
     { "/wrap",
@@ -615,71 +681,61 @@ static struct cmd_t command_defs[] =
         { "/wrap on|off", "Word wrapping.",
         { "/wrap on|off",
           "------------",
-          "Enable or disable word wrapping.",
+          "Enable or disable word wrapping in the main window.",
           NULL } } },
 
     { "/time",
-        cmd_time, parse_args, 1, 1, &cons_time_setting,
-        { "/time <format>", "Time display.",
-        { "/time <format>",
-          "---------------------",
-          "Configure the time format for the main window.",
+        cmd_time, parse_args, 1, 3, &cons_time_setting,
+        { "/time main|statusbar set|off [format]", "Time display.",
+        { "/time main|statusbar set|off [format]",
+          "---------------------------------",
+          "Configure time display preferences.",
+          "",
+          "main set <format>      : Change strftime format to <format> in main window.",
+          "main off               : Do not show time in main window.",
+          "statusbar set <format> : Change strftime format to <format> in statusbar.",
+          "statusbar off          : Do not show time in status bar.",
           NULL } } },
 
     { "/inpblock",
         cmd_inpblock, parse_args, 2, 2, &cons_inpblock_setting,
-        { "/inpblock timeout|dynamic [millis|on|off]", "Input blocking delay (dynamic or static).",
+        { "/inpblock timeout|dynamic [millis|on|off]", "Configure input blocking.",
         { "/inpblock timeout|dynamic [millis|on|off]",
           "-----------------------------------------",
           "How long to wait for input before checking for new messages or checking for state changes such as 'idle'.",
-          "timeout : Time to wait in milliseconds before reading input from the terminal buffer, defaults to 500.",
-          "        : Valid values are 1-1000.",
-          "dynamic : Start with a 0 timeout and increase the value dynamically up to the specified 'timeout'.",
-          "        : on|off",
-          "A higher timeout will result in less CPU usage, but a noticable delay for response to input.",
-          "A lower timeout will result in higher CPU usage, but faster response to input.",
-          "Using the dynamic setting, higher CPU usage will occur during activity, but over time the CPU usage will decrease whilst there is no activity.",
+          "",
+          "timeout millis : Time to wait (1-1000) in milliseconds before reading input from the terminal buffer, default: 1000.",
+          "dynamic on|off : Start with 0 millis and dynamically increase up to timeout when no activity, default: on.",
           NULL } } },
 
     { "/notify",
         cmd_notify, parse_args, 2, 3, &cons_notify_setting,
-        { "/notify [type value]|[type setting value]", "Control various desktop noficiations.",
+        { "/notify [type value]|[type setting value]", "Control various desktop notifications.",
         { "/notify [type value]|[type setting value]",
           "-----------------------------------------",
-          "Settings for various desktop notifications where type is one of:",
-          "message         : Notificaitons for regular messages.",
-          "                : on|off",
-          "message current : Whether messages in the current window trigger notifications.",
-          "                : on|off",
-          "message text    : Show message text in message notifications.",
-          "                : on|off",
-          "room            : Notificaitons for chat room messages.",
-          "                : on|off|mention",
-          "room current    : Whether chat room messages in the current window trigger notifications.",
-          "                : on|off",
-          "room text       : Show message test in chat room message notifications.",
-          "                : on|off",
-          "remind          : Notification reminders of unread messages.",
-          "                : where value is the reminder period in seconds,",
-          "                : use 0 to disable.",
-          "typing          : Notifications when contacts are typing.",
-          "                : on|off",
-          "typing current  : Whether typing notifications are triggerd for the current window.",
-          "                : on|off",
-          "invite          : Notifications for chat room invites.",
-          "                : on|off",
-          "sub             : Notifications for subscription requests.",
-          "                : on|off",
-          "",
-          "Example : /notify message on        (enable message notifications)",
-          "Example : /notify message text on   (show message text in notifications)",
-          "Example : /notify room mention      (enable chat room notifications only on mention)",
-          "Example : /notify room current off  (disable room message notifications when window visible)",
-          "Example : /notify room text off     (do not show message text in chat room notifications)",
-          "Example : /notify remind 10         (remind every 10 seconds)",
-          "Example : /notify remind 0          (switch off reminders)",
-          "Example : /notify typing on         (enable typing notifications)",
-          "Example : /notify invite on         (enable chat room invite notifications)",
+          "Settings for various kinds of desktop notifications.",
+          "",
+          "message on|off         : Notifications for regular messages.",
+          "message current on|off : Whether messages in the current window trigger notifications.",
+          "message text on|off    : Show message text in message notifications.",
+          "room on|off|mention    : Notifications for chat room messages.",
+          "room current on|off    : Whether chat room messages in the current window trigger notifications.",
+          "room text on|off       : Show message text in chat room message notifications.",
+          "remind seconds         : Notification reminder period for unread messages, use 0 to disable.",
+          "typing on|off          : Notifications when contacts are typing.",
+          "typing current of|off  : Whether typing notifications are triggered for the current window.",
+          "invite on|off          : Notifications for chat room invites.",
+          "sub on|off             : Notifications for subscription requests.",
+          "",
+          "Example: /notify message on (enable message notifications)",
+          "Example: /notify message text on (show message text in notifications)",
+          "Example: /notify room mention (enable chat room notifications only on mention)",
+          "Example: /notify room current off (disable room message notifications when window visible)",
+          "Example: /notify room text off (do not show message text in chat room notifications)",
+          "Example: /notify remind 10 (remind every 10 seconds)",
+          "Example: /notify remind 0 (switch off reminders)",
+          "Example: /notify typing on (enable typing notifications)",
+          "Example: /notify invite on (enable chat room invite notifications)",
           NULL } } },
 
     { "/flash",
@@ -687,8 +743,7 @@ static struct cmd_t command_defs[] =
         { "/flash on|off", "Terminal flash on new messages.",
         { "/flash on|off",
           "-------------",
-          "Make the terminal flash when incoming messages are received.",
-          "The flash will only occur if you are not in the chat window associated with the user sending the message.",
+          "Make the terminal flash when incoming messages are received in another window.",
           "If the terminal doesn't support flashing, it may attempt to beep.",
           NULL } } },
 
@@ -717,7 +772,7 @@ static struct cmd_t command_defs[] =
           "The setting can be overridden by the -a (--account) command line option.",
           "",
           "Example: /autoconnect set jc@stuntteam.org (autoconnect with the specified account).",
-          "Example: /autoconnect off                  (disable autoconnect).",
+          "Example: /autoconnect off (disable autoconnect).",
           NULL } } },
 
     { "/vercheck",
@@ -725,18 +780,18 @@ static struct cmd_t command_defs[] =
         { "/vercheck [on|off]", "Check for a new release.",
         { "/vercheck [on|off]",
           "------------------",
-          "Without a parameter will check for a new release.",
-          "Switching on or off will enable/disable a version check when Profanity starts, and each time the /about command is run.",
+          "Enable/disable a version check when Profanity starts, and each time the /about command is run.",
           NULL  } } },
 
     { "/titlebar",
         cmd_titlebar, parse_args, 2, 2, &cons_titlebar_setting,
         { "/titlebar show|goodbye on|off", "Manage the terminal window title.",
         { "/titlebar show|goodbye on|off",
-          "---------------------",
+          "-----------------------------",
           "Show or hide a title and exit message in the terminal window title.",
-          "show    - Show current logged in user, and unread messages in the title.",
-          "goodbye - Show a message in the title when exiting profanity.",
+          "",
+          "show    : Show current logged in user, and unread messages in the title.",
+          "goodbye : Show a message in the title when exiting profanity.",
           NULL  } } },
 
     { "/mouse",
@@ -744,12 +799,7 @@ static struct cmd_t command_defs[] =
         { "/mouse on|off", "Use profanity mouse handling.",
         { "/mouse on|off",
           "-------------",
-          "If set to 'on', profanity will handle mouse actions, which enables scrolling the main window with the mouse wheel.",
-          "To select text, use the shift key while selcting an area.",
-          "If set to 'off', profanity leaves mouse handling to the terminal implementation.",
-          "This feature is experimental, certain mouse click events may occasionally freeze",
-          "Profanity until a key is pressed or another mouse event is received",
-          "The default is 'off'.",
+          "This feature is experimental, default is 'off'.",
           NULL } } },
 
     { "/alias",
@@ -758,12 +808,17 @@ static struct cmd_t command_defs[] =
         { "/alias add|remove|list [name value]",
           "-----------------------------------",
           "Add, remove or show command aliases.",
-          "The alias will be available as a command, the leading '/' will be added if not supplied.",
-          "Example : /alias add friends /who online friends",
-          "Example : /alias add /q /quit",
-          "Example : /alias a /away \"I'm in a meeting.\"",
-          "Example : /alias remove q",
-          "Example : /alias list",
+          "",
+          "add name value : Add a new command alias.",
+          "remove name    : Remove a command alias.",
+          "list           : List all aliases.",
+          "",
+          "Example: /alias add friends /who online friends",
+          "Example: /alias add /q /quit",
+          "Example: /alias a /away \"I'm in a meeting.\"",
+          "Example: /alias remove q",
+          "Example: /alias list",
+          "",
           "The above aliases will be available as /friends and /a",
           NULL } } },
 
@@ -792,29 +847,30 @@ static struct cmd_t command_defs[] =
         { "/states on|off", "Send chat states during a chat session.",
         { "/states on|off",
           "--------------",
-          "Sending of chat state notifications during chat sessions.",
-          "Such as whether you have become inactive, or have closed the chat window.",
+          "Send chat state notifications during chat sessions.",
           NULL } } },
 
     { "/otr",
         cmd_otr, parse_args, 1, 3, NULL,
-        { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver|policy|secret|question|answer", "Off The Record encryption commands.",
-        { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver|policy|secret|question|answer",
-          "-------------------------------------------------------------------------------------------",
-          "gen - Generate your private key.",
-          "myfp - Show your fingerprint.",
-          "theirfp - Show contacts fingerprint.",
-          "start [contact] - Start an OTR session with the contact, or the current recipient if in a chat window and no argument supplied.",
-          "end - End the current OTR session,",
-          "trust - Indicate that you have verified the contact's fingerprint.",
-          "untrust - Indicate the the contact's fingerprint is not verified,",
-          "log - How to log OTR messages, options are 'on', 'off' and 'redact', with redaction being the default.",
-          "warn - Show when unencrypted messaging is being used in the title bar, options are 'on' and 'off' with 'on' being the default.",
-          "libver - Show which version of the libotr library is being used.",
-          "policy - manual, opportunistic or always.",
-          "secret [secret]- Verify a contacts identity using a shared secret.",
-          "question [question] [answer] - Verify a contacts identity using a question and expected anwser, if the question has spaces, surround with double quotes.",
-          "answer [answer] - Respond to a question answer verification request with your answer.",
+        { "/otr command [args..]", "Off The Record encryption commands.",
+        { "/otr command [args..]",
+          "---------------------",
+          "Off The Record encryption commands.",
+          "",
+          "gen                                : Generate your private key.",
+          "myfp                               : Show your fingerprint.",
+          "theirfp                            : Show contacts fingerprint.",
+          "start [contact]                    : Start an OTR session with contact, or current recipient if omitted.",
+          "end                                : End the current OTR session,",
+          "trust                              : Indicate that you have verified the contact's fingerprint.",
+          "untrust                            : Indicate the the contact's fingerprint is not verified,",
+          "log on|off|redact                  : OTR message logging, default: redact.",
+          "warn on|off                        : Show in the titlebar when unencrypted messaging is being used.",
+          "libver                             : Show which version of the libotr library is being used.",
+          "policy manual|opportunistic|always : Set the global OTR policy.",
+          "secret [secret]                    : Verify a contacts identity using a shared secret.",
+          "question [question] [answer]       : Verify a contacts identity using a question and expected answer.",
+          "answer [answer]                    : Respond to a question answer verification request with your answer.",
           NULL } } },
 
     { "/outtype",
@@ -822,8 +878,7 @@ static struct cmd_t command_defs[] =
         { "/outtype on|off", "Send typing notification to recipient.",
         { "/outtype on|off",
           "---------------",
-          "Send an indication that you are typing to the chat recipient.",
-          "Chat states (/states) will be enabled if this setting is set.",
+          "Send typing notifications, chat states (/states) will be enabled if this setting is set.",
           NULL } } },
 
     { "/gone",
@@ -831,8 +886,7 @@ static struct cmd_t command_defs[] =
         { "/gone minutes", "Send 'gone' state to recipient after a period.",
         { "/gone minutes",
           "-------------",
-          "Send a 'gone' state to the recipient after the specified number of minutes."
-          "This indicates to the recipient's client that you have left the conversation.",
+          "Send a 'gone' state to the recipient after the specified number of minutes.",
           "A value of 0 will disable sending this chat state.",
           "Chat states (/states) will be enabled if this setting is set.",
           NULL } } },
@@ -848,15 +902,36 @@ static struct cmd_t command_defs[] =
 
     { "/log",
         cmd_log, parse_args, 1, 2, &cons_log_setting,
-        { "/log [property] [value]", "Manage system logging settings.",
-        { "/log [property] [value]",
-          "-----------------------",
-          "where   : Show the current log file location.",
-          "Property may be one of:",
-          "rotate  : Rotate log, accepts 'on' or 'off', defaults to 'on'.",
-          "maxsize : With rotate enabled, specifies the max log size, defaults to 1048580 (1MB).",
-          "shared  : Share logs between all instances, accepts 'on' or 'off', defaults to 'on'.",
-          NULL } } },
+        { "/log where|rotate|maxsize|shared [value]", "Manage system logging settings.",
+        { "/log where|rotate|maxsize|shared [value]",
+          "----------------------------------------",
+          "Manage profanity logging settings.",
+          "",
+          "where         : Show the current log file location.",
+          "rotate on|off : Rotate log, default on.",
+          "maxsize bytes : With rotate enabled, specifies the max log size, defaults to 1048580 (1MB).",
+          "shared on|off : Share logs between all instances, default: on.",
+          NULL } } },
+
+    { "/carbons",
+      cmd_carbons, parse_args, 1, 1, &cons_carbons_setting,
+      { "/carbons on|off", "Message carbons.",
+      { "/carbons on|off",
+        "---------------",
+        "Enable or disable message carbons.",
+        "The message carbons feature ensures that both sides of all conversations are shared with all the user's clients that implement this protocol.",
+        NULL  } } },
+
+    { "/receipts",
+      cmd_receipts, parse_args, 2, 2, &cons_receipts_setting,
+      { "/receipts send|request on|off", "Message delivery receipts.",
+      { "/receipts send|request on|off",
+        "-----------------------------",
+        "Enable or disable message delivery receipts. The interface will indicate when a message has been received.",
+        "",
+        "send on|off    : Enable or disable sending of delivery receipts.",
+        "request on|off : Enable or disable sending of delivery receipt requests.",
+        NULL  } } },
 
     { "/reconnect",
         cmd_reconnect, parse_args, 1, 1, &cons_reconnect_setting,
@@ -879,26 +954,25 @@ static struct cmd_t command_defs[] =
     { "/ping",
         cmd_ping, parse_args, 0, 1, NULL,
         { "/ping [target]", "Send ping IQ request.",
-        { "/ping [rarget]",
+        { "/ping [target]",
           "--------------",
-          "Sends an IQ ping stanza to the specificed target.",
-          "If no target is supplied, your chat server will be used.",
+          "Sends an IQ ping stanza to the specified target.",
+          "If no target is supplied, your chat server will be pinged.",
           NULL } } },
 
     { "/autoaway",
         cmd_autoaway, parse_args_with_freetext, 2, 2, &cons_autoaway_setting,
-        { "/autoaway setting value", "Set auto idle/away properties.",
-        { "/autoaway setting value",
-          "-----------------------",
-          "'setting' may be one of 'mode', 'time', 'message' or 'check', with the following values:",
-          "",
-          "mode    : idle - Sends idle time, whilst your status remains online.",
-          "          away - Sends an away presence.",
-          "          off - Disabled (default).",
-          "time    : Number of minutes before the presence change is sent, the default is 15.",
-          "message : Optional message to send with the presence change.",
-          "        : off - Disable message (default).",
-          "check   : on|off, when enabled, checks for activity and sends online presence, default is 'on'.",
+        { "/autoaway mode|time|message|check value", "Set auto idle/away properties.",
+        { "/autoaway mode|time|message|check value",
+          "---------------------------------------",
+          "Manage autoway properties.",
+          "",
+          "mode idle        : Sends idle time, status remains online.",
+          "mode away        : Sends an away presence.",
+          "mode off         : Disabled (default).",
+          "time minutes     : Number of minutes before the presence change is sent, default: 15.",
+          "message text|off : Optional message to send with the presence change, default: off (disabled).",
+          "check on|off     : When enabled, checks for activity and sends online presence, default: on.",
           "",
           "Example: /autoaway mode idle",
           "Example: /autoaway time 30",
@@ -911,9 +985,11 @@ static struct cmd_t command_defs[] =
         { "/priority value", "Set priority for the current account.",
         { "/priority value",
           "---------------",
-          "Set priority for the current account, presence will be sent when calling this command.",
-          "See the /account command for more specific priority settings per presence status.",
-          "value : Number between -128 and 127. Default value is 0.",
+          "Set priority for the current account.",
+          "",
+          "value : Number between -128 and 127, default: 0.",
+          "",
+          "See the /account command for specific priority settings per presence status.",
           NULL } } },
 
     { "/account",
@@ -922,6 +998,7 @@ static struct cmd_t command_defs[] =
         { "/account [command] [account] [property] [value]",
           "-----------------------------------------------",
           "Commands for creating and managing accounts.",
+          "",
           "list                         : List all accounts.",
           "show account                 : Show information about an account.",
           "enable account               : Enable the account, it will be used for autocomplete.",
@@ -933,43 +1010,38 @@ static struct cmd_t command_defs[] =
           "set account property value   : Set 'property' of 'account' to 'value'.",
           "clear account property value : Clear 'property' of 'account'.",
           "",
-          "When connected, the /account command can be called with no arguments, to show current account settings.",
-          "",
-          "The set command may use one of the following for 'property'.",
-          "jid              : The Jabber ID of the account, the account name will be used if this property is not set.",
-          "server           : The chat server, if different to the domainpart of the JID.",
-          "port             : The port used for connecting if not the default (5222, or 5223 for SSL).",
-          "status           : The presence status to use on login, use 'last' to use whatever your last status was.",
-          "online|chat|away",
-          "|xa|dnd          : Priority for the specified presence.",
-          "resource         : The resource to be used.",
-          "password         : Password for the account, note this is currently stored in plaintext if set.",
-          "eval_password    : Shell command evaluated to retrieve password for the account.  Can be used to retrieve password from keyring.",
-          "muc              : The default MUC chat service to use.",
-          "nick             : The default nickname to use when joining chat rooms.",
-          "otr              : Override global OTR policy for this account: manual, opportunistic or always.",
-          "",
-          "The clear command works for password, port and server",
-          "",
-          "Example : /account add work",
-          "        : /account set work jid me@chatty",
-          "        : /account set work server talk.chat.com",
-          "        : /account set work port 5111",
-          "        : /account set work resource desktop",
-          "        : /account set work muc chatservice.mycompany.com",
-          "        : /account set work nick dennis",
-          "        : /account set work status dnd",
-          "        : /account set work dnd -1",
-          "        : /account set work online 10",
-          "        : /account rename work gtalk",
+          "Account properties.",
+          "",
+          "jid                     : The Jabber ID of the account, account name will be used if not set.",
+          "server                  : The chat server, if different to the domainpart of the JID.",
+          "port                    : The port used for connecting if not the default (5222, or 5223 for SSL).",
+          "status                  : The presence status to use on login, use 'last' to use your last status before logging out.",
+          "online|chat|away|xa|dnd : Priority for the specified presence.",
+          "resource                : The resource to be used.",
+          "password                : Password for the account, note this is currently stored in plaintext if set.",
+          "eval_password           : Shell command evaluated to retrieve password for the account. Can be used to retrieve password from keyring.",
+          "muc                     : The default MUC chat service to use.",
+          "nick                    : The default nickname to use when joining chat rooms.",
+          "otr                     : Override global OTR policy for this account: manual, opportunistic or always.",
+          "",
+          "Example: /account add me",
+          "Example: /account set me jid me@chatty",
+          "Example: /account set me server talk.chat.com",
+          "Example: /account set me port 5111",
+          "Example: /account set me muc chatservice.mycompany.com",
+          "Example: /account set me nick dennis",
+          "Example: /account set me status dnd",
+          "Example: /account set me dnd -1",
+          "Example: /account rename me gtalk",
           NULL  } } },
 
     { "/prefs",
         cmd_prefs, parse_args, 0, 1, NULL,
-        { "/prefs [area]", "Show configuration.",
-        { "/prefs [area]",
-          "-------------",
-          "Area is one of:",
+        { "/prefs [ui|desktop|chat|log|conn|presence]", "Show configuration.",
+        { "/prefs [ui|desktop|chat|log|conn|presence]",
+          "------------------------------------------",
+          "Show preferences for different areas of functionality.",
+          "",
           "ui       : User interface preferences.",
           "desktop  : Desktop notification preferences.",
           "chat     : Chat state preferences.",
@@ -977,22 +1049,22 @@ static struct cmd_t command_defs[] =
           "conn     : Connection handling preferences.",
           "presence : Chat presence preferences.",
           "",
-          "No argument shows all categories.",
+          "No argument shows all preferences.",
           NULL } } },
 
     { "/theme",
         cmd_theme, parse_args, 1, 2, &cons_theme_setting,
-        { "/theme list|set|colours [theme-name]", "Change colour theme.",
-        { "/theme list|set|colours [theme-name]",
-          "------------------------------------",
-          "Change the colour settings used.",
+        { "/theme list|load|colours [theme-name]", "Change colour theme.",
+        { "/theme list|load|colours [theme-name]",
+          "-------------------------------------",
+          "Load a theme, includes colours and UI options.",
           "",
-          "list           : List all available themes.",
-          "set theme-name : Load the named theme.\"default\" will reset to the default colours.",
-          "colours        : Show the colour values as rendered by the terminal.",
+          "list            : List all available themes.",
+          "load theme-name : Load the named theme. 'default' will reset to the default theme.",
+          "colours         : Show the colour values as rendered by the terminal.",
           "",
-          "Example : /theme list",
-          "Example : /theme set mycooltheme",
+          "Example: /theme list",
+          "Example: /theme load mycooltheme",
           NULL } } },
 
 
@@ -1001,12 +1073,23 @@ static struct cmd_t command_defs[] =
         { "/statuses console|chat|muc setting", "Set preferences for presence change messages.",
         { "/statuses console|chat|muc setting",
           "----------------------------------",
-          "Configure how presence changes are displayed in various windows.",
-          "Settings:",
-          "  all - Show all presence changes.",
-          "  online - Show only online/offline changes.",
-          "  none - Don't show any presence changes.",
+          "Configure which presence changes are displayed in various windows.",
+          "",
+          "console : Configure what is displayed in the console window.",
+          "chat    : Configure what is displayed in chat windows.",
+          "muc     : Configure what is displayed in chat room windows.",
+          "",
+          "Available options are:",
+          "",
+          "all    : Show all presence changes.",
+          "online : Show only online/offline changes.",
+          "none   : Don't show any presence changes.",
+          "",
           "The default is 'all' for all windows.",
+          "",
+          "Example: /statuses console none",
+          "Example: /statuses chat online",
+          "Example: /statuses muc all",
           NULL } } },
 
     { "/xmlconsole",
@@ -1019,57 +1102,52 @@ static struct cmd_t command_defs[] =
 
     { "/away",
         cmd_away, parse_args_with_freetext, 0, 1, NULL,
-        { "/away [msg]", "Set status to away.",
-        { "/away [msg]",
-          "-----------",
+        { "/away [message]", "Set status to away.",
+        { "/away [message]",
+          "---------------",
           "Set your status to 'away' with the optional message.",
-          "Your current status can be found in the top right of the screen.",
           "",
-          "Example : /away Gone for lunch",
+          "Example: /away Gone for lunch",
           NULL } } },
 
     { "/chat",
         cmd_chat, parse_args_with_freetext, 0, 1, NULL,
-        { "/chat [msg]", "Set status to chat (available for chat).",
-        { "/chat [msg]",
-          "-----------",
+        { "/chat [message]", "Set status to chat (available for chat).",
+        { "/chat [message]",
+          "---------------",
           "Set your status to 'chat', meaning 'available for chat', with the optional message.",
-          "Your current status can be found in the top right of the screen.",
           "",
-          "Example : /chat Please talk to me!",
+          "Example: /chat Please talk to me!",
           NULL } } },
 
     { "/dnd",
         cmd_dnd, parse_args_with_freetext, 0, 1, NULL,
-        { "/dnd [msg]", "Set status to dnd (do not disturb).",
-        { "/dnd [msg]",
-          "----------",
+        { "/dnd [message]", "Set status to dnd (do not disturb).",
+        { "/dnd [message]",
+          "--------------",
           "Set your status to 'dnd', meaning 'do not disturb', with the optional message.",
-          "Your current status can be found in the top right of the screen.",
           "",
-          "Example : /dnd I'm in the zone",
+          "Example: /dnd I'm in the zone",
           NULL } } },
 
     { "/online",
         cmd_online, parse_args_with_freetext, 0, 1, NULL,
-        { "/online [msg]", "Set status to online.",
-        { "/online [msg]",
-          "-------------",
+        { "/online [message]", "Set status to online.",
+        { "/online [message]",
+          "-----------------",
           "Set your status to 'online' with the optional message.",
-          "Your current status can be found in the top right of the screen.",
           "",
-          "Example : /online Up the Irons!",
+          "Example: /online Up the Irons!",
           NULL } } },
 
     { "/xa",
         cmd_xa, parse_args_with_freetext, 0, 1, NULL,
-        { "/xa [msg]", "Set status to xa (extended away).",
-        { "/xa [msg]",
-          "---------",
+        { "/xa [message]", "Set status to xa (extended away).",
+        { "/xa [message]",
+          "-------------",
           "Set your status to 'xa', meaning 'extended away', with the optional message.",
-          "Your current status can be found in the top right of the screen.",
           "",
-          "Example : /xa This meeting is going to be a long one",
+          "Example: /xa This meeting is going to be a long one",
           NULL } } },
 };
 
@@ -1121,8 +1199,12 @@ static Autocomplete form_ac;
 static Autocomplete form_field_multi_ac;
 static Autocomplete occupants_ac;
 static Autocomplete occupants_default_ac;
+static Autocomplete occupants_show_ac;
+static Autocomplete time_ac;
+static Autocomplete time_statusbar_ac;
 static Autocomplete resource_ac;
 static Autocomplete inpblock_ac;
+static Autocomplete receipts_ac;
 
 /*
  * Initialise command autocompleter and history
@@ -1140,7 +1222,7 @@ cmd_init(void)
     autocomplete_add(help_ac, "basic");
     autocomplete_add(help_ac, "chatting");
     autocomplete_add(help_ac, "groupchat");
-    autocomplete_add(help_ac, "presence");
+    autocomplete_add(help_ac, "presences");
     autocomplete_add(help_ac, "contacts");
     autocomplete_add(help_ac, "service");
     autocomplete_add(help_ac, "settings");
@@ -1163,7 +1245,7 @@ cmd_init(void)
     // load aliases
     GList *aliases = prefs_get_aliases();
     GList *curr = aliases;
-    while (curr != NULL) {
+    while (curr) {
         ProfAlias *alias = curr->data;
         GString *ac_alias = g_string_new("/");
         g_string_append(ac_alias, alias->name);
@@ -1243,8 +1325,8 @@ cmd_init(void)
     autocomplete_add(autoconnect_ac, "off");
 
     theme_ac = autocomplete_new();
+    autocomplete_add(theme_ac, "load");
     autocomplete_add(theme_ac, "list");
-    autocomplete_add(theme_ac, "set");
     autocomplete_add(theme_ac, "colours");
 
     disco_ac = autocomplete_new();
@@ -1460,6 +1542,20 @@ cmd_init(void)
     autocomplete_add(occupants_default_ac, "show");
     autocomplete_add(occupants_default_ac, "hide");
 
+    occupants_show_ac = autocomplete_new();
+    autocomplete_add(occupants_show_ac, "jid");
+
+    time_ac = autocomplete_new();
+    autocomplete_add(time_ac, "minutes");
+    autocomplete_add(time_ac, "seconds");
+    autocomplete_add(time_ac, "off");
+    autocomplete_add(time_ac, "statusbar");
+
+    time_statusbar_ac = autocomplete_new();
+    autocomplete_add(time_statusbar_ac, "minutes");
+    autocomplete_add(time_statusbar_ac, "seconds");
+    autocomplete_add(time_statusbar_ac, "off");
+
     resource_ac = autocomplete_new();
     autocomplete_add(resource_ac, "set");
     autocomplete_add(resource_ac, "off");
@@ -1469,6 +1565,10 @@ cmd_init(void)
     inpblock_ac = autocomplete_new();
     autocomplete_add(inpblock_ac, "timeout");
     autocomplete_add(inpblock_ac, "dynamic");
+
+    receipts_ac = autocomplete_new();
+    autocomplete_add(receipts_ac, "send");
+    autocomplete_add(receipts_ac, "request");
 }
 
 void
@@ -1522,8 +1622,12 @@ cmd_uninit(void)
     autocomplete_free(form_field_multi_ac);
     autocomplete_free(occupants_ac);
     autocomplete_free(occupants_default_ac);
+    autocomplete_free(occupants_show_ac);
+    autocomplete_free(time_ac);
+    autocomplete_free(time_statusbar_ac);
     autocomplete_free(resource_ac);
     autocomplete_free(inpblock_ac);
+    autocomplete_free(receipts_ac);
 }
 
 gboolean
@@ -1539,7 +1643,7 @@ cmd_exists(char *cmd)
 void
 cmd_autocomplete_add(char *value)
 {
-    if (commands_ac != NULL) {
+    if (commands_ac) {
         autocomplete_add(commands_ac, value);
     }
 }
@@ -1547,41 +1651,45 @@ cmd_autocomplete_add(char *value)
 void
 cmd_autocomplete_add_form_fields(DataForm *form)
 {
-    if (form) {
-        GSList *fields = autocomplete_create_list(form->tag_ac);
-        GSList *curr_field = fields;
-        while (curr_field) {
-            GString *field_str = g_string_new("/");
-            g_string_append(field_str, curr_field->data);
-            cmd_autocomplete_add(field_str->str);
-            g_string_free(field_str, TRUE);
-            curr_field = g_slist_next(curr_field);
-        }
-        g_slist_free_full(fields, free);
+    if (form == NULL) {
+        return;
     }
+
+    GSList *fields = autocomplete_create_list(form->tag_ac);
+    GSList *curr_field = fields;
+    while (curr_field) {
+        GString *field_str = g_string_new("/");
+        g_string_append(field_str, curr_field->data);
+        cmd_autocomplete_add(field_str->str);
+        g_string_free(field_str, TRUE);
+        curr_field = g_slist_next(curr_field);
+    }
+    g_slist_free_full(fields, free);
 }
 
 void
 cmd_autocomplete_remove_form_fields(DataForm *form)
 {
-    if (form) {
-        GSList *fields = autocomplete_create_list(form->tag_ac);
-        GSList *curr_field = fields;
-        while (curr_field) {
-            GString *field_str = g_string_new("/");
-            g_string_append(field_str, curr_field->data);
-            cmd_autocomplete_remove(field_str->str);
-            g_string_free(field_str, TRUE);
-            curr_field = g_slist_next(curr_field);
-        }
-        g_slist_free_full(fields, free);
+    if (form == NULL) {
+        return;
     }
+
+    GSList *fields = autocomplete_create_list(form->tag_ac);
+    GSList *curr_field = fields;
+    while (curr_field) {
+        GString *field_str = g_string_new("/");
+        g_string_append(field_str, curr_field->data);
+        cmd_autocomplete_remove(field_str->str);
+        g_string_free(field_str, TRUE);
+        curr_field = g_slist_next(curr_field);
+    }
+    g_slist_free_full(fields, free);
 }
 
 void
 cmd_autocomplete_remove(char *value)
 {
-    if (commands_ac != NULL) {
+    if (commands_ac) {
         autocomplete_remove(commands_ac, value);
     }
 }
@@ -1589,7 +1697,7 @@ cmd_autocomplete_remove(char *value)
 void
 cmd_alias_add(char *value)
 {
-    if (aliases_ac != NULL) {
+    if (aliases_ac) {
         autocomplete_add(aliases_ac, value);
     }
 }
@@ -1597,7 +1705,7 @@ cmd_alias_add(char *value)
 void
 cmd_alias_remove(char *value)
 {
-    if (aliases_ac != NULL) {
+    if (aliases_ac) {
         autocomplete_remove(aliases_ac, value);
     }
 }
@@ -1610,7 +1718,7 @@ cmd_autocomplete(const char * const input)
     if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, strlen(input), ' '))) {
         char *found = NULL;
         found = autocomplete_complete(commands_ac, input, TRUE);
-        if (found != NULL) {
+        if (found) {
             return found;
         }
 
@@ -1650,8 +1758,8 @@ cmd_reset_autocomplete()
     autocomplete_reset(autoaway_mode_ac);
     autocomplete_reset(autoconnect_ac);
     autocomplete_reset(theme_ac);
-    if (theme_load_ac != NULL) {
-        autocomplete_reset(theme_load_ac);
+    if (theme_load_ac) {
+        autocomplete_free(theme_load_ac);
         theme_load_ac = NULL;
     }
     autocomplete_reset(account_ac);
@@ -1686,8 +1794,12 @@ cmd_reset_autocomplete()
     autocomplete_reset(form_field_multi_ac);
     autocomplete_reset(occupants_ac);
     autocomplete_reset(occupants_default_ac);
+    autocomplete_reset(occupants_show_ac);
+    autocomplete_reset(time_ac);
+    autocomplete_reset(time_statusbar_ac);
     autocomplete_reset(resource_ac);
     autocomplete_reset(inpblock_ac);
+    autocomplete_reset(receipts_ac);
 
     if (ui_current_win_type() == WIN_CHAT) {
         ProfChatWin *chatwin = wins_get_current_chat();
@@ -1724,11 +1836,6 @@ cmd_process_input(char *inp)
     gboolean result = FALSE;
     g_strstrip(inp);
 
-    // add line to history if something typed
-    if (strlen(inp) > 0) {
-        ui_inp_history_append(inp);
-    }
-
     // just carry on if no input
     if (strlen(inp) == 0) {
         result = TRUE;
@@ -1742,7 +1849,7 @@ cmd_process_input(char *inp)
 
     // call a default handler if input didn't start with '/'
     } else {
-        result = _cmd_execute_default(inp);
+        result = cmd_execute_default(inp);
     }
 
     return result;
@@ -1782,7 +1889,7 @@ _cmd_execute(const char * const command, const char * const inp)
     Command *cmd = g_hash_table_lookup(commands, command);
     gboolean result = FALSE;
 
-    if (cmd != NULL) {
+    if (cmd) {
         gchar **args = cmd->parser(inp, cmd->min_args, cmd->max_args, &result);
         if (result == FALSE) {
             ui_invalid_command_usage(cmd->help.usage, cmd->setting_func);
@@ -1794,145 +1901,15 @@ _cmd_execute(const char * const command, const char * const inp)
         }
     } else {
         gboolean ran_alias = FALSE;
-        gboolean alias_result = _cmd_execute_alias(inp, &ran_alias);
+        gboolean alias_result = cmd_execute_alias(inp, &ran_alias);
         if (!ran_alias) {
-            return _cmd_execute_default(inp);
+            return cmd_execute_default(inp);
         } else {
             return alias_result;
         }
     }
 }
 
-static gboolean
-_cmd_execute_alias(const char * const inp, gboolean *ran)
-{
-    if (inp[0] != '/') {
-        ran = FALSE;
-        return TRUE;
-    } else {
-        char *alias = strdup(inp+1);
-        char *value = prefs_get_alias(alias);
-        free(alias);
-        if (value != NULL) {
-            *ran = TRUE;
-            return cmd_process_input(value);
-        } else {
-            *ran = FALSE;
-            return TRUE;
-        }
-    }
-}
-
-static gboolean
-_cmd_execute_default(const char * inp)
-{
-    jabber_conn_status_t status = jabber_get_connection_status();
-
-    // handle escaped commands - treat as normal message
-    if (g_str_has_prefix(inp, "//")) {
-        inp++;
-
-    // handle unknown commands
-    } else if ((inp[0] == '/') && (!g_str_has_prefix(inp, "/me "))) {
-        cons_show("Unknown command: %s", inp);
-        cons_alert();
-        return TRUE;
-    }
-
-    win_type_t win_type = ui_current_win_type();
-    switch (win_type)
-    {
-        case WIN_MUC:
-            if (status != JABBER_CONNECTED) {
-                ui_current_print_line("You are not currently connected.");
-            } else {
-                ProfMucWin *mucwin = wins_get_current_muc();
-                message_send_groupchat(mucwin->roomjid, inp);
-            }
-            break;
-
-        case WIN_CHAT:
-            if (status != JABBER_CONNECTED) {
-                ui_current_print_line("You are not currently connected.");
-            } else {
-                ProfWin *current = wins_get_current();
-                ProfChatWin *chatwin = (ProfChatWin*)current;
-                assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-#ifdef HAVE_LIBOTR
-                prof_otrpolicy_t policy = otr_get_policy(chatwin->barejid);
-                if (policy == PROF_OTRPOLICY_ALWAYS && !otr_is_secure(chatwin->barejid)) {
-                    cons_show_error("Failed to send message. Please check OTR policy");
-                    return TRUE;
-                }
-                if (otr_is_secure(chatwin->barejid)) {
-                    char *encrypted = otr_encrypt_message(chatwin->barejid, inp);
-                    if (encrypted != NULL) {
-                        message_send_chat(chatwin->barejid, encrypted);
-                        otr_free_message(encrypted);
-                        if (prefs_get_boolean(PREF_CHLOG)) {
-                            const char *jid = jabber_get_fulljid();
-                            Jid *jidp = jid_create(jid);
-                            char *pref_otr_log = prefs_get_string(PREF_OTR_LOG);
-                            if (strcmp(pref_otr_log, "on") == 0) {
-                                chat_log_chat(jidp->barejid, chatwin->barejid, inp, PROF_OUT_LOG, NULL);
-                            } else if (strcmp(pref_otr_log, "redact") == 0) {
-                                chat_log_chat(jidp->barejid, chatwin->barejid, "[redacted]", PROF_OUT_LOG, NULL);
-                            }
-                            prefs_free_string(pref_otr_log);
-                            jid_destroy(jidp);
-                        }
-
-                        ui_outgoing_chat_msg("me", chatwin->barejid, inp);
-                    } else {
-                        cons_show_error("Failed to send message.");
-                    }
-                } else {
-                    message_send_chat(chatwin->barejid, inp);
-                    if (prefs_get_boolean(PREF_CHLOG)) {
-                        const char *jid = jabber_get_fulljid();
-                        Jid *jidp = jid_create(jid);
-                        chat_log_chat(jidp->barejid, chatwin->barejid, inp, PROF_OUT_LOG, NULL);
-                        jid_destroy(jidp);
-                    }
-
-                    ui_outgoing_chat_msg("me", chatwin->barejid, inp);
-                }
-#else
-                message_send_chat(chatwin->barejid, inp);
-                if (prefs_get_boolean(PREF_CHLOG)) {
-                    const char *jid = jabber_get_fulljid();
-                    Jid *jidp = jid_create(jid);
-                    chat_log_chat(jidp->barejid, chatwin->barejid, inp, PROF_OUT_LOG, NULL);
-                    jid_destroy(jidp);
-                }
-
-                ui_outgoing_chat_msg("me", chatwin->barejid, inp);
-#endif
-            }
-            break;
-
-        case WIN_PRIVATE:
-            if (status != JABBER_CONNECTED) {
-                ui_current_print_line("You are not currently connected.");
-            } else {
-                ProfPrivateWin *privatewin = wins_get_current_private();
-                message_send_private(privatewin->fulljid, inp);
-                ui_outgoing_private_msg("me", privatewin->fulljid, inp);
-            }
-            break;
-
-        case WIN_CONSOLE:
-        case WIN_XML:
-            cons_show("Unknown command: %s", inp);
-            break;
-
-        default:
-            break;
-    }
-
-    return TRUE;
-}
-
 static char *
 _cmd_complete_parameters(const char * const input)
 {
@@ -1942,7 +1919,7 @@ _cmd_complete_parameters(const char * const input)
     // autocomplete boolean settings
     gchar *boolean_choices[] = { "/beep", "/intype", "/states", "/outtype",
         "/flash", "/splash", "/chlog", "/grlog", "/mouse", "/history",
-        "/vercheck", "/privileges", "/presence", "/wrap" };
+        "/vercheck", "/privileges", "/presence", "/wrap", "/carbons" };
 
     for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
         result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice);
@@ -1958,23 +1935,31 @@ _cmd_complete_parameters(const char * const input)
         if (nick_ac) {
             gchar *nick_choices[] = { "/msg", "/info", "/caps", "/status", "/software" } ;
 
+            // Remove quote character before and after names when doing autocomplete
+            char *unquoted = strip_arg_quotes(input);
             for (i = 0; i < ARRAY_SIZE(nick_choices); i++) {
-                result = autocomplete_param_with_ac(input, nick_choices[i], nick_ac, TRUE);
+                result = autocomplete_param_with_ac(unquoted, nick_choices[i], nick_ac, TRUE);
                 if (result) {
+                    free(unquoted);
                     return result;
                 }
             }
+            free(unquoted);
         }
 
     // otherwise autocomplete using roster
     } else {
         gchar *contact_choices[] = { "/msg", "/info", "/status" };
+        // Remove quote character before and after names when doing autocomplete
+        char *unquoted = strip_arg_quotes(input);
         for (i = 0; i < ARRAY_SIZE(contact_choices); i++) {
-            result = autocomplete_param_with_func(input, contact_choices[i], roster_contact_autocomplete);
+            result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete);
             if (result) {
+                free(unquoted);
                 return result;
             }
         }
+        free(unquoted);
 
         gchar *resource_choices[] = { "/caps", "/software", "/ping" };
         for (i = 0; i < ARRAY_SIZE(resource_choices); i++) {
@@ -1998,8 +1983,8 @@ _cmd_complete_parameters(const char * const input)
         }
     }
 
-    gchar *cmds[] = { "/help", "/prefs", "/disco", "/close", "/wins", "/subject", "/room", };
-    Autocomplete completers[] = { help_ac, prefs_ac, disco_ac, close_ac, wins_ac, subject_ac, room_ac, };
+    gchar *cmds[] = { "/help", "/prefs", "/disco", "/close", "/wins", "/subject", "/room" };
+    Autocomplete completers[] = { help_ac, prefs_ac, disco_ac, close_ac, wins_ac, subject_ac, room_ac };
 
     for (i = 0; i < ARRAY_SIZE(cmds); i++) {
         result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE);
@@ -2034,6 +2019,8 @@ _cmd_complete_parameters(const char * const input)
     g_hash_table_insert(ac_funcs, "/resource",      _resource_autocomplete);
     g_hash_table_insert(ac_funcs, "/titlebar",      _titlebar_autocomplete);
     g_hash_table_insert(ac_funcs, "/inpblock",      _inpblock_autocomplete);
+    g_hash_table_insert(ac_funcs, "/time",          _time_autocomplete);
+    g_hash_table_insert(ac_funcs, "/receipts",      _receipts_autocomplete);
 
     int len = strlen(input);
     char parsed[len+1];
@@ -2049,7 +2036,7 @@ _cmd_complete_parameters(const char * const input)
     parsed[i] = '\0';
 
     char * (*ac_func)(const char * const) = g_hash_table_lookup(ac_funcs, parsed);
-    if (ac_func != NULL) {
+    if (ac_func) {
         result = ac_func(input);
         if (result) {
             g_hash_table_destroy(ac_funcs);
@@ -2073,15 +2060,15 @@ _sub_autocomplete(const char * const input)
 {
     char *result = NULL;
     result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_ac(input, "/sub", sub_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2096,7 +2083,7 @@ _who_autocomplete(const char * const input)
 
     if (win_type == WIN_MUC) {
         result = autocomplete_param_with_ac(input, "/who", who_room_ac, TRUE);
-        if (result != NULL) {
+        if (result) {
             return result;
         }
     } else {
@@ -2107,13 +2094,13 @@ _who_autocomplete(const char * const input)
 
         for (i = 0; i < ARRAY_SIZE(group_commands); i++) {
             result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete);
-            if (result != NULL) {
+            if (result) {
                 return result;
             }
         }
 
         result = autocomplete_param_with_ac(input, "/who", who_roster_ac, TRUE);
-        if (result != NULL) {
+        if (result) {
             return result;
         }
     }
@@ -2126,31 +2113,31 @@ _roster_autocomplete(const char * const input)
 {
     char *result = NULL;
     result = autocomplete_param_with_func(input, "/roster nick", roster_barejid_autocomplete);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_ac(input, "/roster show", roster_option_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_ac(input, "/roster hide", roster_option_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_ac(input, "/roster by", roster_by_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_ac(input, "/roster", roster_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2162,28 +2149,28 @@ _group_autocomplete(const char * const input)
 {
     char *result = NULL;
     result = autocomplete_param_with_func(input, "/group show", roster_group_autocomplete);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_no_with_func(input, "/group add", 4, roster_contact_autocomplete);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_no_with_func(input, "/group remove", 4, roster_contact_autocomplete);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_func(input, "/group add", roster_group_autocomplete);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_func(input, "/group remove", roster_group_autocomplete);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_ac(input, "/group", group_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2244,7 +2231,7 @@ _bookmark_autocomplete(const char * const input)
             found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE);
         }
         g_string_free(beginning, TRUE);
-        if (found != NULL) {
+        if (found) {
             g_strfreev(args);
             return found;
         }
@@ -2253,15 +2240,15 @@ _bookmark_autocomplete(const char * const input)
     g_strfreev(args);
 
     found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
     found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
     found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2276,42 +2263,42 @@ _notify_autocomplete(const char * const input)
     char *result = NULL;
 
     result = autocomplete_param_with_func(input, "/notify room current", prefs_autocomplete_boolean_choice);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_func(input, "/notify message current", prefs_autocomplete_boolean_choice);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_func(input, "/notify typing current", prefs_autocomplete_boolean_choice);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_func(input, "/notify room text", prefs_autocomplete_boolean_choice);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_func(input, "/notify message text", prefs_autocomplete_boolean_choice);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/notify room", notify_room_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/notify message", notify_message_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/notify typing", notify_typing_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2319,13 +2306,13 @@ _notify_autocomplete(const char * const input)
     for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
         result = autocomplete_param_with_func(input, boolean_choices[i],
             prefs_autocomplete_boolean_choice);
-        if (result != NULL) {
+        if (result) {
             return result;
         }
     }
 
     result = autocomplete_param_with_ac(input, "/notify", notify_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2338,16 +2325,16 @@ _autoaway_autocomplete(const char * const input)
     char *result = NULL;
 
     result = autocomplete_param_with_ac(input, "/autoaway mode", autoaway_mode_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_func(input, "/autoaway check",
         prefs_autocomplete_boolean_choice);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_ac(input, "/autoaway", autoaway_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2361,16 +2348,16 @@ _log_autocomplete(const char * const input)
 
     result = autocomplete_param_with_func(input, "/log rotate",
         prefs_autocomplete_boolean_choice);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_func(input, "/log shared",
         prefs_autocomplete_boolean_choice);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
     result = autocomplete_param_with_ac(input, "/log", log_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2383,12 +2370,12 @@ _autoconnect_autocomplete(const char * const input)
     char *result = NULL;
 
     result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/autoconnect", autoconnect_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2401,12 +2388,12 @@ _otr_autocomplete(const char * const input)
     char *found = NULL;
 
     found = autocomplete_param_with_func(input, "/otr start", roster_contact_autocomplete);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_ac(input, "/otr log", otr_log_ac, TRUE);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2421,7 +2408,7 @@ _otr_autocomplete(const char * const input)
 
         found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete);
         g_string_free(beginning, TRUE);
-        if (found != NULL) {
+        if (found) {
             g_strfreev(args);
             return found;
         }
@@ -2430,18 +2417,18 @@ _otr_autocomplete(const char * const input)
     g_strfreev(args);
 
     found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_func(input, "/otr warn",
         prefs_autocomplete_boolean_choice);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2452,24 +2439,25 @@ static char *
 _theme_autocomplete(const char * const input)
 {
     char *result = NULL;
-    if ((strncmp(input, "/theme set ", 11) == 0) && (strlen(input) > 11)) {
+    if ((strncmp(input, "/theme load ", 12) == 0) && (strlen(input) > 12)) {
         if (theme_load_ac == NULL) {
             theme_load_ac = autocomplete_new();
             GSList *themes = theme_list();
-            while (themes != NULL) {
-                autocomplete_add(theme_load_ac, themes->data);
-                themes = g_slist_next(themes);
+            GSList *curr = themes;
+            while (curr) {
+                autocomplete_add(theme_load_ac, curr->data);
+                curr = g_slist_next(curr);
             }
-            g_slist_free(themes);
+            g_slist_free_full(themes, g_free);
             autocomplete_add(theme_load_ac, "default");
         }
-        result = autocomplete_param_with_ac(input, "/theme set", theme_load_ac, TRUE);
-        if (result != NULL) {
+        result = autocomplete_param_with_ac(input, "/theme load", theme_load_ac, TRUE);
+        if (result) {
             return result;
         }
     }
     result = autocomplete_param_with_ac(input, "/theme", theme_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2488,24 +2476,24 @@ _resource_autocomplete(const char * const input)
         if (contact) {
             Autocomplete ac = p_contact_resource_ac(contact);
             found = autocomplete_param_with_ac(input, "/resource set", ac, FALSE);
-            if (found != NULL) {
+            if (found) {
                 return found;
             }
         }
     }
 
     found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_ac(input, "/resource", resource_ac, FALSE);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2518,17 +2506,17 @@ _titlebar_autocomplete(const char * const input)
     char *found = NULL;
 
     found = autocomplete_param_with_func(input, "/titlebar show", prefs_autocomplete_boolean_choice);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_func(input, "/titlebar goodbye", prefs_autocomplete_boolean_choice);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_ac(input, "/titlebar", titlebar_ac, FALSE);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2541,12 +2529,12 @@ _inpblock_autocomplete(const char * const input)
     char *found = NULL;
 
     found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_ac(input, "/inpblock", inpblock_ac, FALSE);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2567,13 +2555,13 @@ _form_autocomplete(const char * const input)
     DataForm *form = confwin->form;
     if (form) {
         found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE);
-        if (found != NULL) {
+        if (found) {
             return found;
         }
     }
 
     found = autocomplete_param_with_ac(input, "/form", form_ac, TRUE);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2656,13 +2644,51 @@ _occupants_autocomplete(const char * const input)
 {
     char *found = NULL;
 
+    found = autocomplete_param_with_ac(input, "/occupants default show", occupants_show_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/occupants default hide", occupants_show_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
     found = autocomplete_param_with_ac(input, "/occupants default", occupants_default_ac, TRUE);
-    if (found != NULL) {
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/occupants show", occupants_show_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/occupants hide", occupants_show_ac, TRUE);
+    if (found) {
         return found;
     }
 
     found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE);
-    if (found != NULL) {
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
+
+static char *
+_time_autocomplete(const char * const input)
+{
+    char *found = NULL;
+
+    found = autocomplete_param_with_ac(input, "/time statusbar", time_statusbar_ac, TRUE);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/time", time_ac, TRUE);
+    if (found) {
         return found;
     }
 
@@ -2678,9 +2704,9 @@ _kick_autocomplete(const char * const input)
         ProfMucWin *mucwin = wins_get_current_muc();
         Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
 
-        if (nick_ac != NULL) {
+        if (nick_ac) {
             result = autocomplete_param_with_ac(input, "/kick", nick_ac, TRUE);
-            if (result != NULL) {
+            if (result) {
                 return result;
             }
         }
@@ -2698,9 +2724,9 @@ _ban_autocomplete(const char * const input)
         ProfMucWin *mucwin = wins_get_current_muc();
         Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid);
 
-        if (jid_ac != NULL) {
+        if (jid_ac) {
             result = autocomplete_param_with_ac(input, "/ban", jid_ac, TRUE);
-            if (result != NULL) {
+            if (result) {
                 return result;
             }
         }
@@ -2729,7 +2755,7 @@ _affiliation_autocomplete(const char * const input)
 
             result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE);
             g_string_free(beginning, TRUE);
-            if (result != NULL) {
+            if (result) {
                 g_strfreev(args);
                 return result;
             }
@@ -2739,17 +2765,17 @@ _affiliation_autocomplete(const char * const input)
     }
 
     result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/affiliation list", affiliation_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/affiliation", privilege_cmd_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2776,7 +2802,7 @@ _role_autocomplete(const char * const input)
 
             result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE);
             g_string_free(beginning, TRUE);
-            if (result != NULL) {
+            if (result) {
                 g_strfreev(args);
                 return result;
             }
@@ -2786,17 +2812,17 @@ _role_autocomplete(const char * const input)
     }
 
     result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/role list", role_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/role", privilege_cmd_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2809,22 +2835,45 @@ _statuses_autocomplete(const char * const input)
     char *result = NULL;
 
     result = autocomplete_param_with_ac(input, "/statuses console", statuses_setting_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/statuses chat", statuses_setting_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/statuses muc", statuses_setting_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/statuses", statuses_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
+        return result;
+    }
+
+    return NULL;
+}
+
+static char *
+_receipts_autocomplete(const char * const input)
+{
+    char *result = NULL;
+
+    result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice);
+    if (result) {
+        return result;
+    }
+
+    result = autocomplete_param_with_ac(input, "/receipts", receipts_ac, TRUE);
+    if (result) {
         return result;
     }
 
@@ -2837,12 +2886,12 @@ _alias_autocomplete(const char * const input)
     char *result = NULL;
 
     result = autocomplete_param_with_ac(input, "/alias remove", aliases_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
     result = autocomplete_param_with_ac(input, "/alias", alias_ac, TRUE);
-    if (result != NULL) {
+    if (result) {
         return result;
     }
 
@@ -2860,7 +2909,7 @@ _connect_autocomplete(const char * const input)
     if ((strncmp(input, "/connect", 8) == 0) && (result == TRUE)) {
         GString *beginning = g_string_new("/connect ");
         g_string_append(beginning, args[0]);
-        if (args[1] != NULL && args[2] != NULL) {
+        if (args[1] && args[2]) {
             g_string_append(beginning, " ");
             g_string_append(beginning, args[1]);
             g_string_append(beginning, " ");
@@ -2868,7 +2917,7 @@ _connect_autocomplete(const char * const input)
         }
         found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE);
         g_string_free(beginning, TRUE);
-        if (found != NULL) {
+        if (found) {
             g_strfreev(args);
             return found;
         }
@@ -2877,7 +2926,7 @@ _connect_autocomplete(const char * const input)
     g_strfreev(args);
 
     found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2891,7 +2940,7 @@ _join_autocomplete(const char * const input)
     gboolean result = FALSE;
 
     found = autocomplete_param_with_func(input, "/join", bookmark_find);
-    if (found != NULL) {
+    if (found) {
         return found;
     }
 
@@ -2900,7 +2949,7 @@ _join_autocomplete(const char * const input)
     if ((strncmp(input, "/join", 5) == 0) && (result == TRUE)) {
         GString *beginning = g_string_new("/join ");
         g_string_append(beginning, args[0]);
-        if (args[1] != NULL && args[2] != NULL) {
+        if (args[1] && args[2]) {
             g_string_append(beginning, " ");
             g_string_append(beginning, args[1]);
             g_string_append(beginning, " ");
@@ -2908,7 +2957,7 @@ _join_autocomplete(const char * const input)
         }
         found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE);
         g_string_free(beginning, TRUE);
-        if (found != NULL) {
+        if (found) {
             g_strfreev(args);
             return found;
         }
@@ -2935,14 +2984,14 @@ _account_autocomplete(const char * const input)
             g_string_append(beginning, args[2]);
             found = autocomplete_param_with_ac(input, beginning->str, otr_policy_ac, TRUE);
             g_string_free(beginning, TRUE);
-            if (found != NULL) {
+            if (found) {
                 g_strfreev(args);
                 return found;
             }
         } else {
             found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE);
             g_string_free(beginning, TRUE);
-            if (found != NULL) {
+            if (found) {
                 g_strfreev(args);
                 return found;
             }
@@ -2954,7 +3003,7 @@ _account_autocomplete(const char * const input)
         g_string_append(beginning, args[1]);
         found = autocomplete_param_with_ac(input, beginning->str, account_clear_ac, TRUE);
         g_string_free(beginning, TRUE);
-        if (found != NULL) {
+        if (found) {
             g_strfreev(args);
             return found;
         }
@@ -2974,7 +3023,7 @@ _account_autocomplete(const char * const input)
 
     for (i = 0; i < ARRAY_SIZE(account_choice); i++) {
         found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all);
-        if (found != NULL) {
+        if (found) {
             return found;
         }
     }
@@ -2982,3 +3031,55 @@ _account_autocomplete(const char * const input)
     found = autocomplete_param_with_ac(input, "/account", account_ac, TRUE);
     return found;
 }
+
+static int
+_cmp_command(Command *cmd1, Command *cmd2)
+{
+    return g_strcmp0(cmd1->cmd, cmd2->cmd);
+}
+
+void
+command_docgen(void)
+{
+    GList *cmds = NULL;
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(command_defs); i++) {
+        Command *pcmd = command_defs+i;
+        cmds = g_list_insert_sorted(cmds, pcmd, (GCompareFunc)_cmp_command);
+    }
+
+    FILE *toc_fragment = fopen("toc_fragment.html", "w");
+    FILE *main_fragment = fopen("main_fragment.html", "w");
+
+    fputs("<ul><li><ul><li>\n", toc_fragment);
+    fputs("<hr>\n", main_fragment);
+
+    GList *curr = cmds;
+    while (curr) {
+        Command *pcmd = curr->data;
+
+        fprintf(toc_fragment, "<a href=\"#%s\">%s</a>,\n", &pcmd->cmd[1], pcmd->cmd);
+
+        fprintf(main_fragment, "<a name=\"%s\"></a>\n", &pcmd->cmd[1]);
+        fprintf(main_fragment, "<h4>%s</h4>\n", pcmd->cmd);
+        fputs("<p>Usage:</p>\n", main_fragment);
+        fprintf(main_fragment, "<p><pre><code>%s</code></pre></p>\n", pcmd->help.usage);
+
+        fputs("<p>Details:</p>\n", main_fragment);
+        fputs("<p><pre><code>", main_fragment);
+        int i = 2;
+        while (pcmd->help.long_help[i]) {
+            fprintf(main_fragment, "%s\n", pcmd->help.long_help[i++]);
+        }
+        fputs("</code></pre></p>\n<a href=\"#top\"><h5>back to top</h5></a><br><hr>\n", main_fragment);
+        fputs("\n", main_fragment);
+
+        curr = g_list_next(curr);
+    }
+
+    fputs("</ul></ul>\n", toc_fragment);
+
+    fclose(toc_fragment);
+    fclose(main_fragment);
+    g_list_free(cmds);
+}
diff --git a/src/command/command.h b/src/command/command.h
index ffbccfa4..b500404b 100644
--- a/src/command/command.h
+++ b/src/command/command.h
@@ -1,7 +1,7 @@
 /*
  * command.h
  *
- * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com>
+ * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com>
  *
  * This file is part of Profanity.
  *
@@ -66,4 +66,6 @@ void cmd_history_append(char *inp);
 char *cmd_history_previous(char *inp);
 char *cmd_history_next(char *inp);
 
+void command_docgen(void);
+
 #endif
diff --git a/src/command/commands.c b/src/command/commands.c
index 02910f99..c5350519 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -1,7 +1,7 @@
 /*
  * commands.c
  *
- * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com>
+ * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com>
  *
  * This file is part of Profanity.
  *
@@ -38,10 +38,8 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <assert.h>
+#include <uuid/uuid.h>
 #include <glib.h>
-#ifdef HAVE_LIBOTR
-#include <libotr/proto.h>
-#endif
 
 #include "chat_session.h"
 #include "command/commands.h"
@@ -67,12 +65,13 @@
 #include "xmpp/bookmark.h"
 #include "ui/ui.h"
 #include "ui/windows.h"
+#include "event/client_events.h"
+#include "event/ui_events.h"
 
 static void _update_presence(const resource_presence_t presence,
     const char * const show, gchar **args);
 static gboolean _cmd_set_boolean_preference(gchar *arg, struct cmd_help_t help,
     const char * const display, preference_t pref);
-static int _strtoi(char *str, int *saveptr, int min, int max);
 static void _cmd_show_filtered_help(char *heading, gchar *cmd_filter[], int filter_size);
 static gint _compare_commands(Command *a, Command *b);
 static void _who_room(gchar **args, struct cmd_help_t help);
@@ -81,115 +80,178 @@ static void _who_roster(gchar **args, struct cmd_help_t help);
 extern GHashTable *commands;
 
 gboolean
-cmd_connect(gchar **args, struct cmd_help_t help)
+cmd_execute_default(const char * inp)
 {
-    gboolean result = FALSE;
+    // handle escaped commands - treat as normal message
+    if (g_str_has_prefix(inp, "//")) {
+        inp++;
 
-    jabber_conn_status_t conn_status = jabber_get_connection_status();
+    // handle unknown commands
+    } else if ((inp[0] == '/') && (!g_str_has_prefix(inp, "/me "))) {
+        cons_show("Unknown command: %s", inp);
+        cons_alert();
+        return TRUE;
+    }
+
+    // handle non commands in non chat windows
+    ProfWin *current = wins_get_current();
+    if (current->type != WIN_CHAT && current->type != WIN_MUC && current->type != WIN_PRIVATE) {
+        cons_show("Unknown command: %s", inp);
+        return TRUE;
+    }
+
+    jabber_conn_status_t status = jabber_get_connection_status();
+    if (status != JABBER_CONNECTED) {
+        ui_current_print_line("You are not currently connected.");
+        return TRUE;
+    }
+
+    switch (current->type) {
+    case WIN_CHAT:
+    {
+        ProfChatWin *chatwin = wins_get_current_chat();
+        cl_ev_send_msg(chatwin, inp);
+        break;
+    }
+    case WIN_PRIVATE:
+    {
+        ProfPrivateWin *privatewin = wins_get_current_private();
+        cl_ev_send_priv_msg(privatewin, inp);
+        break;
+    }
+    case WIN_MUC:
+    {
+        ProfMucWin *mucwin = wins_get_current_muc();
+        cl_ev_send_muc_msg(mucwin, inp);
+        break;
+    }
+    default:
+        break;
+    }
+
+    return TRUE;
+}
+
+gboolean
+cmd_execute_alias(const char * const inp, gboolean *ran)
+{
+    if (inp[0] != '/') {
+        ran = FALSE;
+        return TRUE;
+    }
+
+    char *alias = strdup(inp+1);
+    char *value = prefs_get_alias(alias);
+    free(alias);
+    if (value) {
+        *ran = TRUE;
+        return cmd_process_input(value);
+    }
 
+    *ran = FALSE;
+    return TRUE;
+}
+
+gboolean
+cmd_connect(gchar **args, struct cmd_help_t help)
+{
+    jabber_conn_status_t conn_status = jabber_get_connection_status();
     if ((conn_status != JABBER_DISCONNECTED) && (conn_status != JABBER_STARTED)) {
         cons_show("You are either connected already, or a login is in process.");
-        result = TRUE;
-    } else {
-        gchar *opt_keys[] = { "server", "port", NULL };
-        gboolean parsed;
+        return TRUE;
+    }
 
-        GHashTable *options = parse_options(&args[args[0] ? 1 : 0], opt_keys, &parsed);
-        if (!parsed) {
-            cons_show("Usage: %s", help.usage);
+    gchar *opt_keys[] = { "server", "port", NULL };
+    gboolean parsed;
+
+    GHashTable *options = parse_options(&args[args[0] ? 1 : 0], opt_keys, &parsed);
+    if (!parsed) {
+        cons_show("Usage: %s", help.usage);
+        cons_show("");
+        return TRUE;
+    }
+
+    char *altdomain = g_hash_table_lookup(options, "server");
+
+    int port = 0;
+    if (g_hash_table_contains(options, "port")) {
+        char *port_str = g_hash_table_lookup(options, "port");
+        char *err_msg = NULL;
+        gboolean res = strtoi_range(port_str, &port, 1, 65535, &err_msg);
+        if (!res) {
+            cons_show(err_msg);
             cons_show("");
+            free(err_msg);
+            port = 0;
             return TRUE;
         }
+    }
 
-        char *altdomain = g_hash_table_lookup(options, "server");
-
-        int port = 0;
-        if (g_hash_table_contains(options, "port")) {
-            char *port_str = g_hash_table_lookup(options, "port");
-            if (_strtoi(port_str, &port, 1, 65535) != 0) {
-                port = 0;
-                cons_show("");
-                return TRUE;
-            }
+    char *user = args[0];
+    char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
+    if (!user) {
+        if (def) {
+            user = def;
+            cons_show("Using default account %s.", user);
+        } else {
+            cons_show("No default account.");
+            g_free(def);
+            return TRUE;
         }
+    }
 
-        char *user = args[0];
-        char *def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
-        if(!user){
-            if(def){
-                user = def;
-                cons_show("Using default account %s.", user);
+    char *lower = g_utf8_strdown(user, -1);
+    char *jid;
+    g_free(def);
+
+    // connect with account
+    ProfAccount *account = accounts_get_account(lower);
+    if (account) {
+        // use password if set
+        if (account->password) {
+            conn_status = cl_ev_connect_account(account);
+
+        // use eval_password if set
+        } else if (account->eval_password) {
+            gboolean res = account_eval_password(account);
+            if (res) {
+                conn_status = cl_ev_connect_account(account);
+                free(account->password);
+                account->password = NULL;
             } else {
-                cons_show("No default account.");
-                g_free(def);
+                cons_show("Error evaluating password, see logs for details.");
+                g_free(lower);
                 return TRUE;
             }
-        }
 
-        char *lower = g_utf8_strdown(user, -1);
-        char *jid;
-        g_free(def);
-        def = NULL;
-
-        ProfAccount *account = accounts_get_account(lower);
-        if (account != NULL) {
-            jid = account_create_full_jid(account);
-            if(account->eval_password){
-                // Evaluate as shell command to retrieve password
-                GString *cmd = g_string_append(g_string_new(account->eval_password), " 2>/dev/null");
-                FILE *stream = popen(cmd->str, "r");
-                g_string_free(cmd, TRUE);
-                if(stream){
-                    // Limit to READ_BUF_SIZE bytes to prevent overflows in the case of a poorly chosen command
-                    account->password = g_malloc(READ_BUF_SIZE);
-                    if(!account->password){
-                        log_error("Failed to allocate enough memory to read eval_password output");
-                        cons_show("Error evaluating password, see logs for details.");
-                        return TRUE;
-                    }
-                    account->password = fgets(account->password, READ_BUF_SIZE, stream);
-                    pclose(stream);
-                    if(!account->password){
-                        log_error("No result from eval_password.");
-                        cons_show("Error evaluating password, see logs for details.");
-                        return TRUE;
-                    }
-                    g_strstrip(account->password);
-                } else {
-                    log_error("popen failed when running eval_password.");
-                    cons_show("Error evaluating password, see logs for details.");
-                    return TRUE;
-                }
-            } else if (!account->password) {
-                account->password = ui_ask_password();
-            }
-            cons_show("Connecting with account %s as %s", account->name, jid);
-            if(g_hash_table_contains(options, "port") || g_hash_table_contains(options, "server"))
-                cons_show("Ignoring extra connect options. Please set them with /account set");
-            conn_status = jabber_connect_with_account(account);
-            account_free(account);
+        // no account password setting, prompt
         } else {
-            char *passwd = ui_ask_password();
-            jid = strdup(lower);
-            cons_show("Connecting as %s", jid);
-            conn_status = jabber_connect_with_details(jid, passwd, altdomain, port);
-            free(passwd);
-        }
-        g_free(lower);
-
-        if (conn_status == JABBER_DISCONNECTED) {
-            cons_show_error("Connection attempt for %s failed.", jid);
-            log_info("Connection attempt for %s failed", jid);
+            account->password = ui_ask_password();
+            conn_status = cl_ev_connect_account(account);
+            free(account->password);
+            account->password = NULL;
         }
 
-        options_destroy(options);
+        jid = account_create_full_jid(account);
 
-        free(jid);
+    // connect with JID
+    } else {
+        jid = strdup(lower);
+        char *passwd = ui_ask_password();
+        conn_status = cl_ev_connect_jid(jid, passwd, altdomain, port);
+        free(passwd);
+    }
 
-        result = TRUE;
+    if (conn_status == JABBER_DISCONNECTED) {
+        cons_show_error("Connection attempt for %s failed.", jid);
+        log_info("Connection attempt for %s failed", jid);
     }
 
-    return result;
+    options_destroy(options);
+    g_free(lower);
+    free(jid);
+
+    return TRUE;
 }
 
 gboolean
@@ -342,7 +404,7 @@ cmd_account(gchar **args, struct cmd_help_t help)
                     } else {
                         accounts_set_jid(account_name, jid->barejid);
                         cons_show("Updated jid for account %s: %s", account_name, jid->barejid);
-                        if (jid->resourcepart != NULL) {
+                        if (jid->resourcepart) {
                             accounts_set_resource(account_name, jid->resourcepart);
                             cons_show("Updated resource for account %s: %s", account_name, jid->resourcepart);
                         }
@@ -355,8 +417,12 @@ cmd_account(gchar **args, struct cmd_help_t help)
                     cons_show("");
                 } else if (strcmp(property, "port") == 0) {
                     int port;
-                    if (_strtoi(value, &port, 1, 65535) != 0) {
+                    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);
@@ -368,7 +434,7 @@ cmd_account(gchar **args, struct cmd_help_t help)
                     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 != NULL) {
+                    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);
@@ -376,7 +442,7 @@ cmd_account(gchar **args, struct cmd_help_t help)
                         cons_show("");
                     }
                 } else if (strcmp(property, "eval_password") == 0) {
-                    if(accounts_get_account(account_name)->password != NULL) {
+                    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);
@@ -410,42 +476,46 @@ cmd_account(gchar **args, struct cmd_help_t help)
                     }
                     cons_show("");
                 } else if (valid_resource_presence_string(property)) {
-                        int intval;
-
-                        if (_strtoi(value, &intval, -128, 127) == 0) {
-                            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;
-                            }
+                    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;
+                        }
 
-                            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);
+                        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();
-                                    presence_update(last_presence, message, 0);
-                                }
+                            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("");
                         }
+                        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("");
@@ -652,10 +722,14 @@ gboolean
 cmd_win(gchar **args, struct cmd_help_t help)
 {
     int num = atoi(args[0]);
-    gboolean switched = ui_switch_win(num);
-    if (switched == FALSE) {
+
+    ProfWin *window = wins_get_by_num(num);
+    if (!window) {
         cons_show("Window %d does not exist.", num);
+    } else {
+        ui_ev_focus_win(window);
     }
+
     return TRUE;
 }
 
@@ -681,7 +755,7 @@ cmd_help(gchar **args, struct cmd_help_t help)
         }
 
         GList *curr = ordered_commands;
-        while (curr != NULL) {
+        while (curr) {
             Command *cmd = curr->data;
             cons_show("%-12s: %s", cmd->cmd, cmd->help.short_help);
             curr = g_list_next(curr);
@@ -711,7 +785,7 @@ cmd_help(gchar **args, struct cmd_help_t help)
             "/rooms", "/tiny", "/who", "/nick", "/privileges", "/info", "/occupants" };
         _cmd_show_filtered_help("Groupchat commands", filter, ARRAY_SIZE(filter));
 
-    } else if (strcmp(args[0], "presence") == 0) {
+    } else if (strcmp(args[0], "presences") == 0) {
         gchar *filter[] = { "/autoaway", "/away", "/chat", "/dnd",
             "/online", "/priority", "/account", "/status", "/statuses", "/who",
             "/xa" };
@@ -727,7 +801,7 @@ cmd_help(gchar **args, struct cmd_help_t help)
 
     } else if (strcmp(args[0], "settings") == 0) {
         gchar *filter[] = { "/account", "/autoaway", "/autoping", "/autoconnect", "/beep",
-            "/chlog", "/flash", "/gone", "/grlog", "/history", "/intype",
+            "/carbons", "/chlog", "/flash", "/gone", "/grlog", "/history", "/intype",
             "/log", "/mouse", "/notify", "/outtype", "/prefs", "/priority",
             "/reconnect", "/roster", "/splash", "/states", "/statuses", "/theme",
             "/titlebar", "/vercheck", "/privileges", "/occupants", "/presence", "/wrap" };
@@ -743,12 +817,12 @@ cmd_help(gchar **args, struct cmd_help_t help)
         const gchar **help_text = NULL;
         Command *command = g_hash_table_lookup(commands, cmd_with_slash);
 
-        if (command != NULL) {
+        if (command) {
             help_text = command->help.long_help;
         }
 
         cons_show("");
-        if (help_text != NULL) {
+        if (help_text) {
             ProfWin *console = wins_get_console();
             ui_show_lines(console, help_text);
         } else {
@@ -819,7 +893,7 @@ cmd_theme(gchar **args, struct cmd_help_t help)
         g_slist_free_full(themes, g_free);
 
     // load a theme
-    } else if (g_strcmp0(args[0], "set") == 0) {
+    } else if (g_strcmp0(args[0], "load") == 0) {
         if (args[1] == NULL) {
             cons_show("Usage: %s", help.usage);
         } else if (theme_load(args[1])) {
@@ -854,13 +928,13 @@ cmd_theme(gchar **args, struct cmd_help_t help)
 static void
 _who_room(gchar **args, struct cmd_help_t help)
 {
-    if ((g_strv_length(args) == 2) && (args[1] != NULL)) {
+    if ((g_strv_length(args) == 2) && args[1]) {
         cons_show("Argument group is not applicable to chat rooms.");
         return;
     }
 
     // bad arg
-    if (args[0] != NULL &&
+    if (args[0] &&
             (g_strcmp0(args[0], "online") != 0) &&
             (g_strcmp0(args[0], "available") != 0) &&
             (g_strcmp0(args[0], "unavailable") != 0) &&
@@ -904,7 +978,7 @@ _who_room(gchar **args, struct cmd_help_t help)
         } else if (strcmp("available", presence) == 0) {
             GList *filtered = NULL;
 
-            while (occupants != NULL) {
+            while (occupants) {
                 Occupant *occupant = occupants->data;
                 if (muc_occupant_available(occupant)) {
                     filtered = g_list_append(filtered, occupant);
@@ -918,7 +992,7 @@ _who_room(gchar **args, struct cmd_help_t help)
         } else if (strcmp("unavailable", presence) == 0) {
             GList *filtered = NULL;
 
-            while (occupants != NULL) {
+            while (occupants) {
                 Occupant *occupant = occupants->data;
                 if (!muc_occupant_available(occupant)) {
                     filtered = g_list_append(filtered, occupant);
@@ -932,7 +1006,7 @@ _who_room(gchar **args, struct cmd_help_t help)
         } else {
             GList *filtered = NULL;
 
-            while (occupants != NULL) {
+            while (occupants) {
                 Occupant *occupant = occupants->data;
                 const char *presence_str = string_from_resource_presence(occupant->presence);
                 if (strcmp(presence_str, presence) == 0) {
@@ -986,7 +1060,7 @@ _who_roster(gchar **args, struct cmd_help_t help)
     char *presence = args[0];
 
     // bad arg
-    if ((presence != NULL)
+    if (presence
             && (strcmp(presence, "online") != 0)
             && (strcmp(presence, "available") != 0)
             && (strcmp(presence, "unavailable") != 0)
@@ -1001,13 +1075,13 @@ _who_roster(gchar **args, struct cmd_help_t help)
     }
 
     char *group = NULL;
-    if ((g_strv_length(args) == 2) && (args[1] != NULL)) {
+    if ((g_strv_length(args) == 2) && args[1]) {
         group = args[1];
     }
 
     cons_show("");
     GSList *list = NULL;
-    if (group != NULL) {
+    if (group) {
         list = roster_get_group(group);
         if (list == NULL) {
             cons_show("No such group: %s.", group);
@@ -1023,7 +1097,7 @@ _who_roster(gchar **args, struct cmd_help_t help)
 
     // no arg, show all contacts
     if ((presence == NULL) || (g_strcmp0(presence, "any") == 0)) {
-        if (group != NULL) {
+        if (group) {
             if (list == NULL) {
                 cons_show("No contacts in group %s.", group);
             } else {
@@ -1043,15 +1117,16 @@ _who_roster(gchar **args, struct cmd_help_t help)
     } else if (strcmp("available", presence) == 0) {
         GSList *filtered = NULL;
 
-        while (list != NULL) {
-            PContact contact = list->data;
+        GSList *curr = list;
+        while (curr) {
+            PContact contact = curr->data;
             if (p_contact_is_available(contact)) {
                 filtered = g_slist_append(filtered, contact);
             }
-            list = g_slist_next(list);
+            curr = g_slist_next(curr);
         }
 
-        if (group != NULL) {
+        if (group) {
             if (filtered == NULL) {
                 cons_show("No contacts in group %s are %s.", group, presence);
             } else {
@@ -1066,20 +1141,22 @@ _who_roster(gchar **args, struct cmd_help_t help)
                 cons_show_contacts(filtered);
             }
         }
+        g_slist_free(filtered);
 
     // unavailable
     } else if (strcmp("unavailable", presence) == 0) {
         GSList *filtered = NULL;
 
-        while (list != NULL) {
-            PContact contact = list->data;
+        GSList *curr = list;
+        while (curr) {
+            PContact contact = curr->data;
             if (!p_contact_is_available(contact)) {
                 filtered = g_slist_append(filtered, contact);
             }
-            list = g_slist_next(list);
+            curr = g_slist_next(curr);
         }
 
-        if (group != NULL) {
+        if (group) {
             if (filtered == NULL) {
                 cons_show("No contacts in group %s are %s.", group, presence);
             } else {
@@ -1094,20 +1171,22 @@ _who_roster(gchar **args, struct cmd_help_t help)
                 cons_show_contacts(filtered);
             }
         }
+        g_slist_free(filtered);
 
     // online, available resources
     } else if (strcmp("online", presence) == 0) {
         GSList *filtered = NULL;
 
-        while (list != NULL) {
-            PContact contact = list->data;
+        GSList *curr = list;
+        while (curr) {
+            PContact contact = curr->data;
             if (p_contact_has_available_resource(contact)) {
                 filtered = g_slist_append(filtered, contact);
             }
-            list = g_slist_next(list);
+            curr = g_slist_next(curr);
         }
 
-        if (group != NULL) {
+        if (group) {
             if (filtered == NULL) {
                 cons_show("No contacts in group %s are %s.", group, presence);
             } else {
@@ -1122,20 +1201,22 @@ _who_roster(gchar **args, struct cmd_help_t help)
                 cons_show_contacts(filtered);
             }
         }
+        g_slist_free(filtered);
 
     // offline, no available resources
     } else if (strcmp("offline", presence) == 0) {
         GSList *filtered = NULL;
 
-        while (list != NULL) {
-            PContact contact = list->data;
+        GSList *curr = list;
+        while (curr) {
+            PContact contact = curr->data;
             if (!p_contact_has_available_resource(contact)) {
                 filtered = g_slist_append(filtered, contact);
             }
-            list = g_slist_next(list);
+            curr = g_slist_next(curr);
         }
 
-        if (group != NULL) {
+        if (group) {
             if (filtered == NULL) {
                 cons_show("No contacts in group %s are %s.", group, presence);
             } else {
@@ -1150,20 +1231,22 @@ _who_roster(gchar **args, struct cmd_help_t help)
                 cons_show_contacts(filtered);
             }
         }
+        g_slist_free(filtered);
 
     // show specific status
     } else {
         GSList *filtered = NULL;
 
-        while (list != NULL) {
-            PContact contact = list->data;
+        GSList *curr = list;
+        while (curr) {
+            PContact contact = curr->data;
             if (strcmp(p_contact_presence(contact), presence) == 0) {
                 filtered = g_slist_append(filtered, contact);
             }
-            list = g_slist_next(list);
+            curr = g_slist_next(curr);
         }
 
-        if (group != NULL) {
+        if (group) {
             if (filtered == NULL) {
                 cons_show("No contacts in group %s are %s.", group, presence);
             } else {
@@ -1178,6 +1261,7 @@ _who_roster(gchar **args, struct cmd_help_t help)
                 cons_show_contacts(filtered);
             }
         }
+        g_slist_free(filtered);
     }
 
     g_slist_free(list);
@@ -1218,6 +1302,7 @@ cmd_msg(gchar **args, struct cmd_help_t help)
         return TRUE;
     }
 
+    // send private message when in MUC room
     if (win_type == WIN_MUC) {
         ProfMucWin *mucwin = wins_get_current_muc();
         if (muc_roster_contains_nick(mucwin->roomjid, usr)) {
@@ -1225,11 +1310,14 @@ cmd_msg(gchar **args, struct cmd_help_t help)
             g_string_append(full_jid, "/");
             g_string_append(full_jid, usr);
 
-            if (msg != NULL) {
-                message_send_private(full_jid->str, msg);
-                ui_outgoing_private_msg("me", full_jid->str, msg);
-            } else {
-                ui_new_private_win(full_jid->str);
+            ProfPrivateWin *privwin = wins_get_private(full_jid->str);
+            if (!privwin) {
+                privwin = ui_ev_new_private_win(full_jid->str);
+            }
+            ui_ev_focus_win((ProfWin*)privwin);
+
+            if (msg) {
+                cl_ev_send_priv_msg(privwin, msg);
             }
 
             g_string_free(full_jid, TRUE);
@@ -1240,85 +1328,30 @@ cmd_msg(gchar **args, struct cmd_help_t help)
 
         return TRUE;
 
+    // send chat message
     } else {
-        // get barejid
         char *barejid = roster_barejid_from_name(usr);
         if (barejid == NULL) {
             barejid = usr;
         }
 
-        if (msg != NULL) {
-#ifdef HAVE_LIBOTR
-            if (otr_is_secure(barejid)) {
-                char *encrypted = otr_encrypt_message(barejid, msg);
-                if (encrypted != NULL) {
-                    message_send_chat(barejid, encrypted);
-                    otr_free_message(encrypted);
-                    ui_outgoing_chat_msg("me", barejid, msg);
-
-                    if (((win_type == WIN_CHAT) || (win_type == WIN_CONSOLE)) && prefs_get_boolean(PREF_CHLOG)) {
-                        const char *jid = jabber_get_fulljid();
-                        Jid *jidp = jid_create(jid);
-                        char *pref_otr_log = prefs_get_string(PREF_OTR_LOG);
-                        if (strcmp(pref_otr_log, "on") == 0) {
-                            chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL);
-                        } else if (strcmp(pref_otr_log, "redact") == 0) {
-                            chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_OUT_LOG, NULL);
-                        }
-                        prefs_free_string(pref_otr_log);
-                        jid_destroy(jidp);
-                    }
-                } else {
-                    cons_show_error("Failed to encrypt and send message,");
-                }
-            } else {
-                prof_otrpolicy_t policy = otr_get_policy(barejid);
-
-                if (policy == PROF_OTRPOLICY_ALWAYS) {
-                    cons_show_error("Failed to send message. Please check OTR policy");
-                    return TRUE;
-                } else if (policy == PROF_OTRPOLICY_OPPORTUNISTIC) {
-                    GString *otr_message = g_string_new(msg);
-                    g_string_append(otr_message, OTRL_MESSAGE_TAG_BASE);
-                    g_string_append(otr_message, OTRL_MESSAGE_TAG_V2);
-                    message_send_chat(barejid, otr_message->str);
-
-                    g_string_free(otr_message, TRUE);
-                } else {
-                    message_send_chat(barejid, msg);
-                }
-                ui_outgoing_chat_msg("me", barejid, msg);
-
-                if (((win_type == WIN_CHAT) || (win_type == WIN_CONSOLE)) && prefs_get_boolean(PREF_CHLOG)) {
-                    const char *jid = jabber_get_fulljid();
-                    Jid *jidp = jid_create(jid);
-                    chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL);
-                    jid_destroy(jidp);
-                }
-            }
-            return TRUE;
-#else
-            message_send_chat(barejid, msg);
-            ui_outgoing_chat_msg("me", barejid, msg);
-
-            if (((win_type == WIN_CHAT) || (win_type == WIN_CONSOLE)) && prefs_get_boolean(PREF_CHLOG)) {
-                const char *jid = jabber_get_fulljid();
-                Jid *jidp = jid_create(jid);
-                chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL);
-                jid_destroy(jidp);
-            }
-            return TRUE;
-#endif
+        ProfChatWin *chatwin = wins_get_chat(barejid);
+        if (!chatwin) {
+            chatwin = ui_ev_new_chat_win(barejid);
+        }
+        ui_ev_focus_win((ProfWin*)chatwin);
 
-        } else { // msg == NULL
-            ui_new_chat_win(barejid);
+        if (msg) {
+            cl_ev_send_msg(chatwin, msg);
+        } else {
 #ifdef HAVE_LIBOTR
             if (otr_is_secure(barejid)) {
                 ui_gone_secure(barejid, otr_is_trusted(barejid));
             }
 #endif
-            return TRUE;
         }
+
+        return TRUE;
     }
 }
 
@@ -1336,9 +1369,9 @@ cmd_group(gchar **args, struct cmd_help_t help)
     if (args[0] == NULL) {
         GSList *groups = roster_get_groups();
         GSList *curr = groups;
-        if (curr != NULL) {
+        if (curr) {
             cons_show("Groups:");
-            while (curr != NULL) {
+            while (curr) {
                 cons_show("  %s", curr->data);
                 curr = g_slist_next(curr);
             }
@@ -1455,11 +1488,14 @@ cmd_roster(gchar **args, struct cmd_help_t help)
 
     // set roster size
     } else if (g_strcmp0(args[0], "size") == 0) {
-        int intval = 0;
         if (!args[1]) {
             cons_show("Usage: %s", help.usage);
             return TRUE;
-        } else if (_strtoi(args[1], &intval, 1, 99) == 0) {
+        }
+        int intval = 0;
+        char *err_msg = NULL;
+        gboolean res = strtoi_range(args[1], &intval, 1, 99, &err_msg);
+        if (res) {
             prefs_set_roster_size(intval);
             cons_show("Roster screen size set to: %d%%", intval);
             if (prefs_get_boolean(PREF_ROSTER)) {
@@ -1467,6 +1503,8 @@ cmd_roster(gchar **args, struct cmd_help_t help)
             }
             return TRUE;
         } else {
+            cons_show(err_msg);
+            free(err_msg);
             return TRUE;
         }
 
@@ -1701,35 +1739,35 @@ cmd_status(gchar **args, struct cmd_help_t help)
     switch (win_type)
     {
         case WIN_MUC:
-            if (usr != NULL) {
+            if (usr) {
                 ProfMucWin *mucwin = wins_get_current_muc();
                 ProfWin *window = (ProfWin*) mucwin;
                 Occupant *occupant = muc_roster_item(mucwin->roomjid, usr);
                 if (occupant) {
                     win_show_occupant(window, occupant);
                 } else {
-                    win_save_vprint(window, '-', NULL, 0, 0, "", "No such participant \"%s\" in room.", usr);
+                    win_vprint(window, '-', NULL, 0, 0, "", "No such participant \"%s\" in room.", usr);
                 }
             } else {
                 ui_current_print_line("You must specify a nickname.");
             }
             break;
         case WIN_CHAT:
-            if (usr != NULL) {
+            if (usr) {
                 ui_current_print_line("No parameter required when in chat.");
             } else {
                 ProfChatWin *chatwin = wins_get_current_chat();
                 ProfWin *window = (ProfWin*) chatwin;
                 PContact pcontact = roster_get_contact(chatwin->barejid);
-                if (pcontact != NULL) {
+                if (pcontact) {
                     win_show_contact(window, pcontact);
                 } else {
-                    win_save_println(window, "Error getting contact info.");
+                    win_println(window, "Error getting contact info.");
                 }
             }
             break;
         case WIN_PRIVATE:
-            if (usr != NULL) {
+            if (usr) {
                 ui_current_print_line("No parameter required when in chat.");
             } else {
                 ProfPrivateWin *privatewin = wins_get_current_private();
@@ -1739,13 +1777,13 @@ cmd_status(gchar **args, struct cmd_help_t help)
                 if (occupant) {
                     win_show_occupant(window, occupant);
                 } else {
-                    win_save_println(window, "Error getting contact info.");
+                    win_println(window, "Error getting contact info.");
                 }
                 jid_destroy(jid);
             }
             break;
         case WIN_CONSOLE:
-            if (usr != NULL) {
+            if (usr) {
                 char *usr_jid = roster_barejid_from_name(usr);
                 if (usr_jid == NULL) {
                     usr_jid = usr;
@@ -1790,7 +1828,7 @@ cmd_info(gchar **args, struct cmd_help_t help)
                 }
             } else {
                 ProfMucWin *mucwin = wins_get_current_muc();
-                iq_room_info_request(mucwin->roomjid);
+                iq_room_info_request(mucwin->roomjid, TRUE);
                 ui_show_room_info(mucwin);
                 return TRUE;
             }
@@ -1802,10 +1840,10 @@ cmd_info(gchar **args, struct cmd_help_t help)
                 ProfChatWin *chatwin = wins_get_current_chat();
                 ProfWin *window = (ProfWin*) chatwin;
                 PContact pcontact = roster_get_contact(chatwin->barejid);
-                if (pcontact != NULL) {
+                if (pcontact) {
                     win_show_info(window, pcontact);
                 } else {
-                    win_save_println(window, "Error getting contact info.");
+                    win_println(window, "Error getting contact info.");
                 }
             }
             break;
@@ -1820,7 +1858,7 @@ cmd_info(gchar **args, struct cmd_help_t help)
                 if (occupant) {
                     win_show_occupant_info(window, jid->barejid, occupant);
                 } else {
-                    win_save_println(window, "Error getting contact info.");
+                    win_println(window, "Error getting contact info.");
                 }
                 jid_destroy(jid);
             }
@@ -1832,7 +1870,7 @@ cmd_info(gchar **args, struct cmd_help_t help)
                     usr_jid = usr;
                 }
                 pcontact = roster_get_contact(usr_jid);
-                if (pcontact != NULL) {
+                if (pcontact) {
                     cons_show_info(pcontact);
                 } else {
                     cons_show("No such contact \"%s\" in roster.", usr);
@@ -1864,7 +1902,7 @@ cmd_caps(gchar **args, struct cmd_help_t help)
     switch (win_type)
     {
         case WIN_MUC:
-            if (args[0] != NULL) {
+            if (args[0]) {
                 ProfMucWin *mucwin = wins_get_current_muc();
                 occupant = muc_roster_item(mucwin->roomjid, args[0]);
                 if (occupant) {
@@ -1880,7 +1918,7 @@ cmd_caps(gchar **args, struct cmd_help_t help)
             break;
         case WIN_CHAT:
         case WIN_CONSOLE:
-            if (args[0] != NULL) {
+            if (args[0]) {
                 Jid *jid = jid_create(args[0]);
 
                 if (jid->fulljid == NULL) {
@@ -1904,7 +1942,7 @@ cmd_caps(gchar **args, struct cmd_help_t help)
             }
             break;
         case WIN_PRIVATE:
-            if (args[0] != NULL) {
+            if (args[0]) {
                 cons_show("No parameter needed to /caps when in private chat.");
             } else {
                 ProfPrivateWin *privatewin = wins_get_current_private();
@@ -1939,7 +1977,7 @@ cmd_software(gchar **args, struct cmd_help_t help)
     switch (win_type)
     {
         case WIN_MUC:
-            if (args[0] != NULL) {
+            if (args[0]) {
                 ProfMucWin *mucwin = wins_get_current_muc();
                 occupant = muc_roster_item(mucwin->roomjid, args[0]);
                 if (occupant) {
@@ -1955,7 +1993,7 @@ cmd_software(gchar **args, struct cmd_help_t help)
             break;
         case WIN_CHAT:
         case WIN_CONSOLE:
-            if (args[0] != NULL) {
+            if (args[0]) {
                 Jid *jid = jid_create(args[0]);
 
                 if (jid == NULL || jid->fulljid == NULL) {
@@ -1969,7 +2007,7 @@ cmd_software(gchar **args, struct cmd_help_t help)
             }
             break;
         case WIN_PRIVATE:
-            if (args[0] != NULL) {
+            if (args[0]) {
                 cons_show("No parameter needed to /software when in private chat.");
             } else {
                 ProfPrivateWin *privatewin = wins_get_current_private();
@@ -1993,8 +2031,24 @@ cmd_join(gchar **args, struct cmd_help_t help)
     }
 
     if (args[0] == NULL) {
-        cons_show("Usage: %s", help.usage);
-        cons_show("");
+        uuid_t uuid;
+        uuid_generate(uuid);
+        char *uuid_str = malloc(sizeof(char) * 37);
+        uuid_unparse_lower(uuid, uuid_str);
+
+        char *account_name = jabber_get_account_name();
+        ProfAccount *account = accounts_get_account(account_name);
+
+        GString *room_str = g_string_new("");
+        g_string_append_printf(room_str, "private-chat-%s@%s", uuid_str, account->muc_service);
+
+        presence_join_room(room_str->str, account->muc_nick, NULL);
+        muc_join(room_str->str, account->muc_nick, NULL, FALSE);
+
+        g_string_free(room_str, TRUE);
+        free(uuid_str);
+        account_free(account);
+
         return TRUE;
     }
 
@@ -2013,7 +2067,7 @@ cmd_join(gchar **args, struct cmd_help_t help)
     ProfAccount *account = accounts_get_account(account_name);
 
     // full room jid supplied (room@server)
-    if (room_arg->localpart != NULL) {
+    if (room_arg->localpart) {
         room = args[0];
 
     // server not supplied (room), use account preference
@@ -2041,10 +2095,15 @@ cmd_join(gchar **args, struct cmd_help_t help)
     options_destroy(options);
 
     // In the case that a nick wasn't provided by the optional args...
-    if (nick == NULL) {
+    if (!nick) {
         nick = account->muc_nick;
     }
 
+    // When no password, check for invite with password
+    if (!passwd) {
+        passwd = muc_invite_password(room);
+    }
+
     if (!muc_active(room)) {
         presence_join_room(room, nick, passwd);
         muc_join(room, nick, passwd, FALSE);
@@ -2083,7 +2142,7 @@ cmd_invite(gchar **args, struct cmd_help_t help)
 
     ProfMucWin *mucwin = wins_get_current_muc();
     message_send_invite(mucwin->roomjid, usr_jid, reason);
-    if (reason != NULL) {
+    if (reason) {
         cons_show("Room invite sent, contact: %s, room: %s, reason: \"%s\".",
             contact, mucwin->roomjid, reason);
     } else {
@@ -2368,7 +2427,7 @@ cmd_form(gchar **args, struct cmd_help_t help)
 
     if (g_strcmp0(args[0], "help") == 0) {
         char *tag = args[1];
-        if (tag != NULL) {
+        if (tag) {
             ui_show_form_field_help(confwin, tag);
         } else {
             ui_show_form_help(confwin);
@@ -2376,7 +2435,7 @@ cmd_form(gchar **args, struct cmd_help_t help)
             const gchar **help_text = NULL;
             Command *command = g_hash_table_lookup(commands, "/form");
 
-            if (command != NULL) {
+            if (command) {
                 help_text = command->help.long_help;
             }
 
@@ -2400,12 +2459,11 @@ cmd_form(gchar **args, struct cmd_help_t help)
             cmd_autocomplete_remove_form_fields(confwin->form);
         }
         wins_close_current();
-        ProfWin *current = (ProfWin*)wins_get_muc(confwin->roomjid);
-        if (current == NULL) {
-            current = wins_get_console();
+        ProfWin *new_current = (ProfWin*)wins_get_muc(confwin->roomjid);
+        if (!new_current) {
+            new_current = wins_get_console();
         }
-        int num = wins_get_num(current);
-        ui_switch_win(num);
+        ui_ev_focus_win(new_current);
     }
 
     return TRUE;
@@ -2435,7 +2493,7 @@ cmd_kick(gchar **args, struct cmd_help_t help)
             char *reason = args[1];
             iq_room_kick_occupant(mucwin->roomjid, nick, reason);
         } else {
-            win_save_vprint((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Occupant does not exist: %s", nick);
+            win_vprint((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Occupant does not exist: %s", nick);
         }
     } else {
         cons_show("Usage: %s", help.usage);
@@ -2494,10 +2552,10 @@ cmd_subject(gchar **args, struct cmd_help_t help)
     if (args[0] == NULL) {
         char *subject = muc_subject(mucwin->roomjid);
         if (subject) {
-            win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Room subject: ");
-            win_save_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", subject);
+            win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Room subject: ");
+            win_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", subject);
         } else {
-            win_save_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room has no subject");
+            win_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room has no subject");
         }
         return TRUE;
     }
@@ -2543,7 +2601,7 @@ cmd_affiliation(gchar **args, struct cmd_help_t help)
     }
 
     char *affiliation = args[1];
-    if ((affiliation != NULL) &&
+    if (affiliation &&
             (g_strcmp0(affiliation, "owner") != 0) &&
             (g_strcmp0(affiliation, "admin") != 0) &&
             (g_strcmp0(affiliation, "member") != 0) &&
@@ -2562,7 +2620,7 @@ cmd_affiliation(gchar **args, struct cmd_help_t help)
             iq_room_affiliation_list(mucwin->roomjid, "member");
             iq_room_affiliation_list(mucwin->roomjid, "outcast");
         } else if (g_strcmp0(affiliation, "none") == 0) {
-            win_save_print((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Cannot list users with no affiliation.");
+            win_print((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Cannot list users with no affiliation.");
         } else {
             iq_room_affiliation_list(mucwin->roomjid, affiliation);
         }
@@ -2613,7 +2671,7 @@ cmd_role(gchar **args, struct cmd_help_t help)
     }
 
     char *role = args[1];
-    if ((role != NULL ) &&
+    if (role &&
             (g_strcmp0(role, "visitor") != 0) &&
             (g_strcmp0(role, "participant") != 0) &&
             (g_strcmp0(role, "moderator") != 0) &&
@@ -2630,7 +2688,7 @@ cmd_role(gchar **args, struct cmd_help_t help)
             iq_room_role_list(mucwin->roomjid, "participant");
             iq_room_role_list(mucwin->roomjid, "visitor");
         } else if (g_strcmp0(role, "none") == 0) {
-            win_save_print((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Cannot list users with no role.");
+            win_print((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Cannot list users with no role.");
         } else {
             iq_room_role_list(mucwin->roomjid, role);
         }
@@ -2693,12 +2751,12 @@ cmd_room(gchar **args, struct cmd_help_t help)
     if (g_strcmp0(args[0], "accept") == 0) {
         gboolean requires_config = muc_requires_config(mucwin->roomjid);
         if (!requires_config) {
-            win_save_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Current room does not require configuration.");
+            win_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Current room does not require configuration.");
             return TRUE;
         } else {
             iq_confirm_instant_room(mucwin->roomjid);
             muc_set_requires_config(mucwin->roomjid, FALSE);
-            win_save_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room unlocked.");
+            win_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room unlocked.");
             return TRUE;
         }
     }
@@ -2711,9 +2769,8 @@ cmd_room(gchar **args, struct cmd_help_t help)
     if (g_strcmp0(args[0], "config") == 0) {
         ProfMucConfWin *confwin = wins_get_muc_conf(mucwin->roomjid);
 
-        if (confwin != NULL) {
-            num = wins_get_num(window);
-            ui_switch_win(num);
+        if (confwin) {
+            ui_ev_focus_win((ProfWin*)confwin);
         } else {
             iq_request_room_config_form(mucwin->roomjid);
         }
@@ -2734,26 +2791,44 @@ cmd_occupants(gchar **args, struct cmd_help_t help)
     }
 
     if (g_strcmp0(args[0], "size") == 0) {
-        int intval = 0;
         if (!args[1]) {
             cons_show("Usage: %s", help.usage);
             return TRUE;
-        } else if (_strtoi(args[1], &intval, 1, 99) == 0) {
-            prefs_set_occupants_size(intval);
-            cons_show("Occupants screen size set to: %d%%", intval);
-            wins_resize_all();
-            return TRUE;
+        } else {
+            int intval = 0;
+            char *err_msg = NULL;
+            gboolean res = strtoi_range(args[1], &intval, 1, 99, &err_msg);
+            if (res) {
+                prefs_set_occupants_size(intval);
+                cons_show("Occupants screen size set to: %d%%", intval);
+                wins_resize_all();
+                return TRUE;
+            } else {
+                cons_show(err_msg);
+                free(err_msg);
+                return TRUE;
+            }
         }
     }
 
     if (g_strcmp0(args[0], "default") == 0) {
         if (g_strcmp0(args[1], "show") == 0) {
-            cons_show("Occupant list enabled.");
-            prefs_set_boolean(PREF_OCCUPANTS, TRUE);
+            if (g_strcmp0(args[2], "jid") == 0) {
+                cons_show("Occupant jids enabled.");
+                prefs_set_boolean(PREF_OCCUPANTS_JID, TRUE);
+            } else {
+                cons_show("Occupant list enabled.");
+                prefs_set_boolean(PREF_OCCUPANTS, TRUE);
+            }
             return TRUE;
         } else if (g_strcmp0(args[1], "hide") == 0) {
-            cons_show("Occupant list disabled.");
-            prefs_set_boolean(PREF_OCCUPANTS, FALSE);
+            if (g_strcmp0(args[2], "jid") == 0) {
+                cons_show("Occupant jids disabled.");
+                prefs_set_boolean(PREF_OCCUPANTS_JID, FALSE);
+            } else {
+                cons_show("Occupant list disabled.");
+                prefs_set_boolean(PREF_OCCUPANTS, FALSE);
+            }
             return TRUE;
         } else {
             cons_show("Usage: %s", help.usage);
@@ -2763,16 +2838,26 @@ cmd_occupants(gchar **args, struct cmd_help_t help)
 
     win_type_t win_type = ui_current_win_type();
     if (win_type != WIN_MUC) {
-        cons_show("Cannot show/hide occupant list when not in chat room.");
+        cons_show("Cannot apply setting when not in chat room.");
         return TRUE;
     }
 
     ProfMucWin *mucwin = wins_get_current_muc();
 
     if (g_strcmp0(args[0], "show") == 0) {
-        ui_room_show_occupants(mucwin->roomjid);
+        if (g_strcmp0(args[1], "jid") == 0) {
+            mucwin->showjid = TRUE;
+            ui_room_update_occupants(mucwin->roomjid);
+        } else {
+            ui_room_show_occupants(mucwin->roomjid);
+        }
     } else if (g_strcmp0(args[0], "hide") == 0) {
-        ui_room_hide_occupants(mucwin->roomjid);
+        if (g_strcmp0(args[1], "jid") == 0) {
+            mucwin->showjid = FALSE;
+            ui_room_update_occupants(mucwin->roomjid);
+        } else {
+            ui_room_hide_occupants(mucwin->roomjid);
+        }
     } else {
         cons_show("Usage: %s", help.usage);
     }
@@ -2876,7 +2961,7 @@ cmd_bookmark(gchar **args, struct cmd_help_t help)
             char *password = g_hash_table_lookup(options, "password");
             char *autojoin = g_hash_table_lookup(options, "autojoin");
 
-            if (autojoin != NULL) {
+            if (autojoin) {
                 if ((strcmp(autojoin, "on") != 0) && (strcmp(autojoin, "off") != 0)) {
                     cons_show("Usage: %s", help.usage);
                     cons_show("");
@@ -2924,7 +3009,7 @@ cmd_disco(gchar **args, struct cmd_help_t help)
     }
 
     GString *jid = g_string_new("");
-    if (args[1] != NULL) {
+    if (args[1]) {
         jid = g_string_append(jid, args[1]);
     } else {
         Jid *jidp = jid_create(jabber_get_fulljid());
@@ -3040,82 +3125,48 @@ gboolean
 cmd_tiny(gchar **args, struct cmd_help_t help)
 {
     char *url = args[0];
-    win_type_t win_type = ui_current_win_type();
-
-    if (!tinyurl_valid(url)) {
-        GString *error = g_string_new("/tiny, badly formed URL: ");
-        g_string_append(error, url);
-        cons_show_error(error->str);
-        if (win_type != WIN_CONSOLE) {
-            ui_current_error_line(error->str);
-        }
-        g_string_free(error, TRUE);
-    } else if (win_type != WIN_CONSOLE) {
-        char *tiny = tinyurl_get(url);
+    ProfWin *current = wins_get_current();
 
-        if (tiny != NULL) {
-            if (win_type == WIN_CHAT) {
-                ProfChatWin *chatwin = wins_get_current_chat();
-#ifdef HAVE_LIBOTR
-                if (otr_is_secure(chatwin->barejid)) {
-                    char *encrypted = otr_encrypt_message(chatwin->barejid, tiny);
-                    if (encrypted != NULL) {
-                        message_send_chat(chatwin->barejid, encrypted);
-                        otr_free_message(encrypted);
-                        if (prefs_get_boolean(PREF_CHLOG)) {
-                            const char *jid = jabber_get_fulljid();
-                            Jid *jidp = jid_create(jid);
-                            char *pref_otr_log = prefs_get_string(PREF_OTR_LOG);
-                            if (strcmp(pref_otr_log, "on") == 0) {
-                                chat_log_chat(jidp->barejid, chatwin->barejid, tiny, PROF_OUT_LOG, NULL);
-                            } else if (strcmp(pref_otr_log, "redact") == 0) {
-                                chat_log_chat(jidp->barejid, chatwin->barejid, "[redacted]", PROF_OUT_LOG, NULL);
-                            }
-                            prefs_free_string(pref_otr_log);
-                            jid_destroy(jidp);
-                        }
+    if (current->type != WIN_CHAT && current->type != WIN_MUC && current->type != WIN_PRIVATE) {
+        cons_show("/tiny can only be used in chat windows");
+        return TRUE;
+    }
 
-                        ui_outgoing_chat_msg("me", chatwin->barejid, tiny);
-                    } else {
-                        cons_show_error("Failed to send message.");
-                    }
-                } else {
-                    message_send_chat(chatwin->barejid, tiny);
-                    if (prefs_get_boolean(PREF_CHLOG)) {
-                        const char *jid = jabber_get_fulljid();
-                        Jid *jidp = jid_create(jid);
-                        chat_log_chat(jidp->barejid, chatwin->barejid, tiny, PROF_OUT_LOG, NULL);
-                        jid_destroy(jidp);
-                    }
+    if (!tinyurl_valid(url)) {
+        win_vprint(current, '-', NULL, 0, THEME_ERROR, "", "/tiny, badly formed URL: %s", url);
+        return TRUE;
+    }
 
-                    ui_outgoing_chat_msg("me", chatwin->barejid, tiny);
-                }
-#else
-                message_send_chat(chatwin->barejid, tiny);
-                if (prefs_get_boolean(PREF_CHLOG)) {
-                    const char *jid = jabber_get_fulljid();
-                    Jid *jidp = jid_create(jid);
-                    chat_log_chat(jidp->barejid, chatwin->barejid, tiny, PROF_OUT_LOG, NULL);
-                    jid_destroy(jidp);
-                }
+    char *tiny = tinyurl_get(url);
+    if (!tiny) {
+        win_print(current, '-', NULL, 0, THEME_ERROR, "", "Couldn't create tinyurl.");
+        return TRUE;
+    }
 
-                ui_outgoing_chat_msg("me", chatwin->barejid, tiny);
-#endif
-            } else if (win_type == WIN_PRIVATE) {
-                ProfPrivateWin *privatewin = wins_get_current_private();
-                message_send_private(tiny, privatewin->fulljid);
-                ui_outgoing_private_msg("me", privatewin->fulljid, tiny);
-            } else if (win_type == WIN_MUC) {
-                ProfMucWin *mucwin = wins_get_current_muc();
-                message_send_groupchat(tiny, mucwin->roomjid);
-            }
-            free(tiny);
-        } else {
-            cons_show_error("Couldn't get tinyurl.");
-        }
-    } else {
-        cons_show("/tiny can only be used in chat windows");
+    switch (current->type){
+    case WIN_CHAT:
+    {
+        ProfChatWin *chatwin = wins_get_current_chat();
+        cl_ev_send_msg(chatwin, tiny);
+        break;
+    }
+    case WIN_PRIVATE:
+    {
+        ProfPrivateWin *privatewin = wins_get_current_private();
+        cl_ev_send_priv_msg(privatewin, tiny);
+        break;
+    }
+    case WIN_MUC:
+    {
+        ProfMucWin *mucwin = wins_get_current_muc();
+        cl_ev_send_muc_msg(mucwin, tiny);
+        break;
     }
+    default:
+        break;
+    }
+
+    free(tiny);
 
     return TRUE;
 }
@@ -3135,7 +3186,7 @@ cmd_close(gchar **args, struct cmd_help_t help)
     int count = 0;
 
     if (args[0] == NULL) {
-        index = ui_current_win_index();
+        index = wins_get_current_num();
     } else if (strcmp(args[0], "all") == 0) {
         count = ui_close_all_wins();
         if (count == 0) {
@@ -3170,19 +3221,15 @@ cmd_close(gchar **args, struct cmd_help_t help)
         return TRUE;
     }
 
-    if (!ui_win_exists(index)) {
+    ProfWin *window = wins_get_by_num(index);
+    if (!window) {
         cons_show("Window is not open.");
         return TRUE;
     }
 
     // check for unsaved form
     if (ui_win_has_unsaved_form(index)) {
-        ProfWin *window = wins_get_current();
-        if (wins_is_current(window)) {
-            ui_current_print_line("You have unsaved changes, use /form submit or /form cancel");
-        } else {
-            cons_show("Cannot close form window with unsaved changes, use /form submit or /form cancel");
-        }
+        ui_current_print_line("You have unsaved changes, use /form submit or /form cancel");
         return TRUE;
     }
 
@@ -3203,7 +3250,7 @@ cmd_leave(gchar **args, struct cmd_help_t help)
 {
     jabber_conn_status_t conn_status = jabber_get_connection_status();
     win_type_t win_type = ui_current_win_type();
-    int index = ui_current_win_index();
+    int index = wins_get_current_num();
 
     if (win_type != WIN_MUC) {
         cons_show("You can only use the /leave command in a chat room.");
@@ -3257,10 +3304,46 @@ cmd_wrap(gchar **args, struct cmd_help_t help)
 gboolean
 cmd_time(gchar **args, struct cmd_help_t help)
 {
-    prefs_set_string(PREF_TIME, args[0]);
-    cons_show("Time format set to '%s'", args[0]);
-    wins_resize_all();
-    return TRUE;
+    if (g_strcmp0(args[0], "statusbar") == 0) {
+        if (args[1] == NULL) {
+            cons_show("Current status bar time format is '%s'.", prefs_get_string(PREF_TIME_STATUSBAR));
+            return TRUE;
+        } else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
+            prefs_set_string(PREF_TIME_STATUSBAR, args[2]);
+            cons_show("Status bar time format set to '%s'.", args[2]);
+            ui_redraw();
+            return TRUE;
+        } else if (g_strcmp0(args[1], "off") == 0) {
+            prefs_set_string(PREF_TIME_STATUSBAR, "");
+            cons_show("Status bar time display disabled.");
+            ui_redraw();
+            return TRUE;
+        } else {
+            cons_show("Usage: %s", help.usage);
+            return TRUE;
+        }
+    } else if (g_strcmp0(args[0], "main") == 0) {
+        if (args[1] == NULL) {
+            cons_show("Current time format is '%s'.", prefs_get_string(PREF_TIME));
+            return TRUE;
+        } else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
+            prefs_set_string(PREF_TIME, args[2]);
+            cons_show("Time format set to '%s'.", args[2]);
+            wins_resize_all();
+            return TRUE;
+        } else if (g_strcmp0(args[1], "off") == 0) {
+            prefs_set_string(PREF_TIME, "");
+            cons_show("Time display disabled.");
+            wins_resize_all();
+            return TRUE;
+        } else {
+            cons_show("Usage: %s", help.usage);
+            return TRUE;
+        }
+    } else {
+        cons_show("Usage: %s", help.usage);
+        return TRUE;
+    }
 }
 
 gboolean
@@ -3481,7 +3564,6 @@ cmd_inpblock(gchar **args, struct cmd_help_t help)
 {
     char *subcmd = args[0];
     char *value = args[1];
-    int intval;
 
     if (g_strcmp0(subcmd, "timeout") == 0) {
         if (value == NULL) {
@@ -3489,10 +3571,16 @@ cmd_inpblock(gchar **args, struct cmd_help_t help)
             return TRUE;
         }
 
-        if (_strtoi(value, &intval, 1, 1000) == 0) {
+        int intval = 0;
+        char *err_msg = NULL;
+        gboolean res = strtoi_range(value, &intval, 1, 1000, &err_msg);
+        if (res) {
             cons_show("Input blocking set to %d milliseconds.", intval);
             prefs_set_inpblock(intval);
             ui_input_nonblocking(FALSE);
+        } else {
+            cons_show(err_msg);
+            free(err_msg);
         }
 
         return TRUE;
@@ -3522,16 +3610,22 @@ cmd_log(gchar **args, struct cmd_help_t help)
 {
     char *subcmd = args[0];
     char *value = args[1];
-    int intval;
 
     if (strcmp(subcmd, "maxsize") == 0) {
         if (value == NULL) {
             cons_show("Usage: %s", help.usage);
             return TRUE;
         }
-        if (_strtoi(value, &intval, PREFS_MIN_LOG_SIZE, INT_MAX) == 0) {
+
+        int intval = 0;
+        char *err_msg = NULL;
+        gboolean res = strtoi_range(value, &intval, PREFS_MIN_LOG_SIZE, INT_MAX, &err_msg);
+        if (res) {
             prefs_set_max_log_size(intval);
             cons_show("Log maxinum size set to %d bytes", intval);
+        } else {
+            cons_show(err_msg);
+            free(err_msg);
         }
         return TRUE;
     }
@@ -3571,9 +3665,11 @@ gboolean
 cmd_reconnect(gchar **args, struct cmd_help_t help)
 {
     char *value = args[0];
-    int intval;
 
-    if (_strtoi(value, &intval, 0, INT_MAX) == 0) {
+    int intval = 0;
+    char *err_msg = NULL;
+    gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
+    if (res) {
         prefs_set_reconnect(intval);
         if (intval == 0) {
             cons_show("Reconnect disabled.", intval);
@@ -3581,7 +3677,9 @@ cmd_reconnect(gchar **args, struct cmd_help_t help)
             cons_show("Reconnect interval set to %d seconds.", intval);
         }
     } else {
+        cons_show(err_msg);
         cons_show("Usage: %s", help.usage);
+        free(err_msg);
     }
 
     return TRUE;
@@ -3591,9 +3689,11 @@ gboolean
 cmd_autoping(gchar **args, struct cmd_help_t help)
 {
     char *value = args[0];
-    int intval;
 
-    if (_strtoi(value, &intval, 0, INT_MAX) == 0) {
+    int intval = 0;
+    char *err_msg = NULL;
+    gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
+    if (res) {
         prefs_set_autoping(intval);
         iq_set_autoping(intval);
         if (intval == 0) {
@@ -3602,7 +3702,9 @@ cmd_autoping(gchar **args, struct cmd_help_t help)
             cons_show("Autoping interval set to %d seconds.", intval);
         }
     } else {
+        cons_show(err_msg);
         cons_show("Usage: %s", help.usage);
+        free(err_msg);
     }
 
     return TRUE;
@@ -3633,7 +3735,6 @@ cmd_autoaway(gchar **args, struct cmd_help_t help)
 {
     char *setting = args[0];
     char *value = args[1];
-    int minutesval;
 
     if ((strcmp(setting, "mode") != 0) && (strcmp(setting, "time") != 0) &&
             (strcmp(setting, "message") != 0) && (strcmp(setting, "check") != 0)) {
@@ -3654,9 +3755,15 @@ cmd_autoaway(gchar **args, struct cmd_help_t help)
     }
 
     if (strcmp(setting, "time") == 0) {
-        if (_strtoi(value, &minutesval, 1, INT_MAX) == 0) {
+        int minutesval = 0;
+        char *err_msg = NULL;
+        gboolean res = strtoi_range(value, &minutesval, 1, INT_MAX, &err_msg);
+        if (res) {
             prefs_set_autoaway_time(minutesval);
             cons_show("Auto away time set to: %d minutes.", minutesval);
+        } else {
+            cons_show(err_msg);
+            free(err_msg);
         }
 
         return TRUE;
@@ -3693,13 +3800,18 @@ cmd_priority(gchar **args, struct cmd_help_t help)
     }
 
     char *value = args[0];
-    int intval;
 
-    if (_strtoi(value, &intval, -128, 127) == 0) {
+    int intval = 0;
+    char *err_msg = NULL;
+    gboolean res = strtoi_range(value, &intval, -128, 127, &err_msg);
+    if (res) {
         accounts_set_priority_all(jabber_get_account_name(), intval);
         resource_presence_t last_presence = accounts_get_last_presence(jabber_get_account_name());
-        presence_update(last_presence, jabber_get_presence_message(), 0);
+        cl_ev_presence_send(last_presence, jabber_get_presence_message(), 0);
         cons_show("Priority set to %d.", intval);
+    } else {
+        cons_show(err_msg);
+        free(err_msg);
     }
 
     return TRUE;
@@ -3865,6 +3977,42 @@ cmd_history(gchar **args, struct cmd_help_t help)
 }
 
 gboolean
+cmd_carbons(gchar **args, struct cmd_help_t help)
+{
+    gboolean result = _cmd_set_boolean_preference(args[0], help,
+        "Message carbons preference", PREF_CARBONS);
+
+    jabber_conn_status_t conn_status = jabber_get_connection_status();
+
+    if (conn_status == JABBER_CONNECTED) {
+        // enable carbons
+        if (strcmp(args[0], "on") == 0) {
+            iq_enable_carbons();
+        }
+        else if (strcmp(args[0], "off") == 0){
+            iq_disable_carbons();
+        }
+    }
+
+    return result;
+}
+
+gboolean
+cmd_receipts(gchar **args, struct cmd_help_t help)
+{
+    if (g_strcmp0(args[0], "send") == 0) {
+        return _cmd_set_boolean_preference(args[1], help,
+            "Send delivery receipts", PREF_RECEIPTS_SEND);
+    } else if (g_strcmp0(args[0], "request") == 0) {
+        return _cmd_set_boolean_preference(args[1], help,
+            "Request delivery receipets", PREF_RECEIPTS_REQUEST);
+    } else {
+        cons_show("Usage: %s", help.usage);
+        return TRUE;
+    }
+}
+
+gboolean
 cmd_away(gchar **args, struct cmd_help_t help)
 {
     _update_presence(RESOURCE_AWAY, "away", args);
@@ -4013,14 +4161,18 @@ cmd_otr(gchar **args, struct cmd_help_t help)
         return TRUE;
 
     } else if (strcmp(args[0], "start") == 0) {
-        if (args[1] != NULL) {
+        if (args[1]) {
             char *contact = args[1];
             char *barejid = roster_barejid_from_name(contact);
             if (barejid == NULL) {
                 barejid = contact;
             }
 
-            ui_new_chat_win(barejid);
+            ProfChatWin *chatwin = wins_get_chat(barejid);
+            if (!chatwin) {
+                chatwin = ui_ev_new_chat_win(barejid);
+            }
+            ui_ev_focus_win((ProfWin*)chatwin);
 
             if (ui_current_win_is_otr()) {
                 ui_current_print_formatted_line('!', 0, "You are already in an OTR session.");
@@ -4029,7 +4181,7 @@ cmd_otr(gchar **args, struct cmd_help_t help)
                     ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'");
                 } else if (!otr_is_secure(barejid)) {
                     char *otr_query_message = otr_start_query();
-                    message_send_chat(barejid, otr_query_message);
+                    message_send_chat_encrypted(barejid, otr_query_message);
                 } else {
                     ui_gone_secure(barejid, otr_is_trusted(barejid));
                 }
@@ -4047,7 +4199,7 @@ cmd_otr(gchar **args, struct cmd_help_t help)
                 } else {
                     ProfChatWin *chatwin = ui_get_current_chat();
                     char *otr_query_message = otr_start_query();
-                    message_send_chat(chatwin->barejid, otr_query_message);
+                    message_send_chat_encrypted(chatwin->barejid, otr_query_message);
                 }
             }
         }
@@ -4175,7 +4327,7 @@ _update_presence(const resource_presence_t resource_presence,
     if (conn_status != JABBER_CONNECTED) {
         cons_show("You are not currently connected.");
     } else {
-        presence_update(resource_presence, msg, 0);
+        cl_ev_presence_send(resource_presence, msg, 0);
         ui_update_presence(resource_presence, msg, show);
     }
 }
@@ -4213,27 +4365,6 @@ _cmd_set_boolean_preference(gchar *arg, struct cmd_help_t help,
     return TRUE;
 }
 
-static int
-_strtoi(char *str, int *saveptr, int min, int max)
-{
-    char *ptr;
-    int val;
-
-    errno = 0;
-    val = (int)strtol(str, &ptr, 0);
-    if (errno != 0 || *str == '\0' || *ptr != '\0') {
-        cons_show("Could not convert \"%s\" to a number.", str);
-        return -1;
-    } else if (val < min || val > max) {
-        cons_show("Value %s out of range. Must be in %d..%d.", str, min, max);
-        return -1;
-    }
-
-    *saveptr = val;
-
-    return 0;
-}
-
 static void
 _cmd_show_filtered_help(char *heading, gchar *cmd_filter[], int filter_size)
 {
@@ -4249,7 +4380,7 @@ _cmd_show_filtered_help(char *heading, gchar *cmd_filter[], int filter_size)
     }
 
     GList *curr = ordered_commands;
-    while (curr != NULL) {
+    while (curr) {
         Command *cmd = curr->data;
         cons_show("%-12s: %s", cmd->cmd, cmd->help.short_help);
         curr = g_list_next(curr);
diff --git a/src/command/commands.h b/src/command/commands.h
index f4e040a9..7b7e7c93 100644
--- a/src/command/commands.h
+++ b/src/command/commands.h
@@ -1,7 +1,7 @@
 /*
  * commands.h
  *
- * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com>
+ * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com>
  *
  * This file is part of Profanity.
  *
@@ -62,6 +62,9 @@ typedef struct cmd_t {
     CommandHelp help;
 } Command;
 
+gboolean cmd_execute_alias(const char * const inp, gboolean *ran);
+gboolean cmd_execute_default(const char * inp);
+
 gboolean cmd_about(gchar **args, struct cmd_help_t help);
 gboolean cmd_account(gchar **args, struct cmd_help_t help);
 gboolean cmd_autoaway(gchar **args, struct cmd_help_t help);
@@ -85,6 +88,8 @@ gboolean cmd_grlog(gchar **args, struct cmd_help_t help);
 gboolean cmd_group(gchar **args, struct cmd_help_t help);
 gboolean cmd_help(gchar **args, struct cmd_help_t help);
 gboolean cmd_history(gchar **args, struct cmd_help_t help);
+gboolean cmd_carbons(gchar **args, struct cmd_help_t help);
+gboolean cmd_receipts(gchar **args, struct cmd_help_t help);
 gboolean cmd_info(gchar **args, struct cmd_help_t help);
 gboolean cmd_intype(gchar **args, struct cmd_help_t help);
 gboolean cmd_invite(gchar **args, struct cmd_help_t help);