memory leaks: Memory leak cleanup patch by Corey Farrell (second set)
[asterisk/asterisk.git] / main / asterisk.c
index 67d09ff..2e5ffa7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2012, Digium, Inc.
+ * Copyright (C) 1999 - 2013, Digium, Inc.
  *
  * Mark Spencer <markster@digium.com>
  *
@@ -27,7 +27,7 @@
  * internals of the Asterisk software. This documentation contains basic
  * examples, developer documentation, support information, and information
  * for upgrading.
- * 
+ *
  * \section community Community
  * Asterisk is a big project and has a busy community. Look at the
  * resources for questions and stick around to help answer questions.
@@ -53,7 +53,7 @@
  *
  * \section copyright Copyright and Author
  *
- * Copyright (C) 1999 - 2012, Digium, Inc.
+ * Copyright (C) 1999 - 2013, Digium, Inc.
  * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
  * of <a href="http://www.digium.com">Digium, Inc</a>.
  *
  * \par
  * Use http://www.freenode.net IRC server to connect with Asterisk
  * developers and users in realtime.
- * 
+ *
  * \li \verbatim #asterisk \endverbatim Asterisk Users Room
  * \li \verbatim #asterisk-dev \endverbatim Asterisk Developers Room
  *
@@ -202,6 +202,7 @@ int daemon(int, int);  /* defined in libresolv of all places */
 #include "asterisk/cli.h"
 #include "asterisk/channel.h"
 #include "asterisk/translate.h"
+#include "asterisk/pickup.h"
 #include "asterisk/features.h"
 #include "asterisk/acl.h"
 #include "asterisk/ulaw.h"
@@ -239,10 +240,51 @@ int daemon(int, int);  /* defined in libresolv of all places */
 #include "asterisk/format.h"
 #include "asterisk/aoc.h"
 #include "asterisk/uuid.h"
+#include "asterisk/sorcery.h"
+#include "asterisk/bucket.h"
+#include "asterisk/stasis.h"
+#include "asterisk/json.h"
+#include "asterisk/stasis_endpoints.h"
+#include "asterisk/stasis_system.h"
+#include "asterisk/security_events.h"
+#include "asterisk/endpoints.h"
 
 #include "../defaults.h"
 
 /*** DOCUMENTATION
+       <managerEvent language="en_US" name="FullyBooted">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
+                       <syntax>
+                               <parameter name="Status">
+                                       <para>Informational message</para>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
+       <managerEvent language="en_US" name="Shutdown">
+               <managerEventInstance class="EVENT_FLAG_SYSTEM">
+                       <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
+                       <syntax>
+                               <parameter name="Shutdown">
+                                       <para>Whether the shutdown is proceeding cleanly (all channels
+                                       were hungup successfully) or uncleanly (channels will be
+                                       terminated)</para>
+                                       <enumlist>
+                                               <enum name="Uncleanly"/>
+                                               <enum name="Cleanly"/>
+                                       </enumlist>
+                               </parameter>
+                               <parameter name="Restart">
+                                       <para>Whether or not a restart will occur.</para>
+                                       <enumlist>
+                                               <enum name="True"/>
+                                               <enum name="False"/>
+                                       </enumlist>
+                               </parameter>
+                       </syntax>
+               </managerEventInstance>
+       </managerEvent>
  ***/
 
 #ifndef AF_LOCAL
@@ -259,7 +301,7 @@ int daemon(int, int);  /* defined in libresolv of all places */
 
 /*! \brief Welcome message when starting a CLI interface */
 #define WELCOME_MESSAGE \
-    ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
+    ast_verbose("Asterisk %s, Copyright (C) 1999 - 2013 Digium, Inc. and others.\n" \
                 "Created by Mark Spencer <markster@digium.com>\n" \
                 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
                 "This is free software, with components licensed under the GNU General Public\n" \
@@ -279,9 +321,9 @@ struct ast_flags ast_compat = { 0 };
 
 int option_verbose;                            /*!< Verbosity level */
 int option_debug;                              /*!< Debug level */
-double option_maxload;                         /*!< Max load avg on system */
-int option_maxcalls;                           /*!< Max number of active calls */
-int option_maxfiles;                           /*!< Max number of open file handles (files, sockets) */
+double ast_option_maxload;                     /*!< Max load avg on system */
+int ast_option_maxcalls;                       /*!< Max number of active calls */
+int ast_option_maxfiles;                       /*!< Max number of open file handles (files, sockets) */
 unsigned int option_dtmfminduration;           /*!< Minimum duration of DTMF. */
 #if defined(HAVE_SYSINFO)
 long option_minmemfree;                                /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
@@ -309,6 +351,7 @@ struct console {
 
 struct ast_atexit {
        void (*func)(void);
+       int is_cleanup;
        AST_LIST_ENTRY(ast_atexit) list;
 };
 
@@ -323,7 +366,7 @@ static char *remotehostname;
 
 struct console consoles[AST_MAX_CONNECTS];
 
-char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
+char ast_defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
 
 static int ast_el_add_history(char *);
 static int ast_el_read_history(char *);
@@ -334,6 +377,7 @@ struct _cfg_paths {
        char module_dir[PATH_MAX];
        char spool_dir[PATH_MAX];
        char monitor_dir[PATH_MAX];
+       char recording_dir[PATH_MAX];
        char var_dir[PATH_MAX];
        char data_dir[PATH_MAX];
        char log_dir[PATH_MAX];
@@ -358,6 +402,7 @@ const char *ast_config_AST_CONFIG_FILE      = cfg_paths.config_file;
 const char *ast_config_AST_MODULE_DIR  = cfg_paths.module_dir;
 const char *ast_config_AST_SPOOL_DIR   = cfg_paths.spool_dir;
 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
+const char *ast_config_AST_RECORDING_DIR       = cfg_paths.recording_dir;
 const char *ast_config_AST_VAR_DIR     = cfg_paths.var_dir;
 const char *ast_config_AST_DATA_DIR    = cfg_paths.data_dir;
 const char *ast_config_AST_LOG_DIR     = cfg_paths.log_dir;
@@ -556,17 +601,17 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
        ast_cli(a->fd, "-----------------\n");
        ast_cli(a->fd, "  Version:                     %s\n", ast_get_version());
        ast_cli(a->fd, "  Build Options:               %s\n", S_OR(AST_BUILDOPTS, "(none)"));
-       if (option_maxcalls)
-               ast_cli(a->fd, "  Maximum calls:               %d (Current %d)\n", option_maxcalls, ast_active_channels());
+       if (ast_option_maxcalls)
+               ast_cli(a->fd, "  Maximum calls:               %d (Current %d)\n", ast_option_maxcalls, ast_active_channels());
        else
                ast_cli(a->fd, "  Maximum calls:               Not set\n");
-       if (option_maxfiles)
-               ast_cli(a->fd, "  Maximum open file handles:   %d\n", option_maxfiles);
+       if (ast_option_maxfiles)
+               ast_cli(a->fd, "  Maximum open file handles:   %d\n", ast_option_maxfiles);
        else
                ast_cli(a->fd, "  Maximum open file handles:   Not set\n");
        ast_cli(a->fd, "  Verbosity:                   %d\n", option_verbose);
        ast_cli(a->fd, "  Debug level:                 %d\n", option_debug);
-       ast_cli(a->fd, "  Maximum load average:        %lf\n", option_maxload);
+       ast_cli(a->fd, "  Maximum load average:        %lf\n", ast_option_maxload);
 #if defined(HAVE_SYSINFO)
        ast_cli(a->fd, "  Minimum free memory:         %ld MB\n", option_minmemfree);
 #endif
@@ -581,7 +626,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
        ast_cli(a->fd, "  System:                      %s/%s built by %s on %s %s\n", ast_build_os, ast_build_kernel, ast_build_user, ast_build_machine, ast_build_date);
        ast_cli(a->fd, "  System name:                 %s\n", ast_config_AST_SYSTEM_NAME);
        ast_cli(a->fd, "  Entity ID:                   %s\n", eid_str);
-       ast_cli(a->fd, "  Default language:            %s\n", defaultlanguage);
+       ast_cli(a->fd, "  Default language:            %s\n", ast_defaultlanguage);
        ast_cli(a->fd, "  Language prefix:             %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
        ast_cli(a->fd, "  User name and group:         %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
        ast_cli(a->fd, "  Executable includes:         %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
@@ -595,7 +640,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
        ast_cli(a->fd, "  -------------\n");
        ast_cli(a->fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
        ast_cli(a->fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
-       ast_cli(a->fd, "  Call data records:           %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
+       ast_cli(a->fd, "  Call data records:           %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
        ast_cli(a->fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
 
        /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */
@@ -1048,13 +1093,22 @@ static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct
 
 #endif /* ! LOW_MEMORY */
 
-static void ast_run_atexits(void)
+static void publish_fully_booted(void)
+{
+       RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+
+       json_object = ast_json_pack("{s: s}",
+                       "Status", "Fully Booted");
+       ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
+}
+
+static void ast_run_atexits(int run_cleanups)
 {
        struct ast_atexit *ae;
 
        AST_LIST_LOCK(&atexits);
        while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
-               if (ae->func) {
+               if (ae->func && (!ae->is_cleanup || run_cleanups)) {
                        ae->func();
                }
                ast_free(ae);
@@ -1076,7 +1130,7 @@ static void __ast_unregister_atexit(void (*func)(void))
        AST_LIST_TRAVERSE_SAFE_END;
 }
 
-int ast_register_atexit(void (*func)(void))
+static int register_atexit(void (*func)(void), int is_cleanup)
 {
        struct ast_atexit *ae;
 
@@ -1085,6 +1139,7 @@ int ast_register_atexit(void (*func)(void))
                return -1;
        }
        ae->func = func;
+       ae->is_cleanup = is_cleanup;
 
        AST_LIST_LOCK(&atexits);
        __ast_unregister_atexit(func);
@@ -1094,6 +1149,16 @@ int ast_register_atexit(void (*func)(void))
        return 0;
 }
 
+int ast_register_atexit(void (*func)(void))
+{
+       return register_atexit(func, 0);
+}
+
+int ast_register_cleanup(void (*func)(void))
+{
+       return register_atexit(func, 1);
+}
+
 void ast_unregister_atexit(void (*func)(void))
 {
        AST_LIST_LOCK(&atexits);
@@ -1808,8 +1873,8 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
                time_t s, e;
                /* Begin shutdown routine, hanging up active channels */
                ast_begin_shutdown(1);
-               if (option_verbose && ast_opt_console) {
-                       ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
+               if (ast_opt_console) {
+                       ast_verb(0, "Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
                }
                time(&s);
                for (;;) {
@@ -1825,7 +1890,7 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
                if (niceness != SHUTDOWN_REALLY_NICE) {
                        ast_begin_shutdown(0);
                }
-               if (option_verbose && ast_opt_console) {
+               if (ast_opt_console) {
                        ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
                }
                for (;;) {
@@ -1841,7 +1906,7 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
         */
        ast_mutex_lock(&safe_system_lock);
        if (shuttingdown != niceness) {
-               if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
+               if (shuttingdown == NOT_SHUTTING_DOWN && ast_opt_console) {
                        ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
                }
                ast_mutex_unlock(&safe_system_lock);
@@ -1857,8 +1922,10 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
 static void really_quit(int num, shutdown_nice_t niceness, int restart)
 {
        int active_channels;
+       struct ast_json *json_object = NULL;
+       int run_cleanups = niceness >= SHUTDOWN_NICE;
 
-       if (niceness >= SHUTDOWN_NICE) {
+       if (run_cleanups) {
                ast_module_shutdown();
        }
 
@@ -1885,38 +1952,22 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
                }
        }
        active_channels = ast_active_channels();
-       /* The manager event for shutdown must happen prior to ast_run_atexits, as
-        * the manager interface will dispose of its sessions as part of its
-        * shutdown.
+       /* Don't publish messages if we're a remote console - we won't have all of the Stasis
+        * topics or message types
         */
-       /*** DOCUMENTATION
-               <managerEventInstance>
-                       <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
-                       <syntax>
-                               <parameter name="Shutdown">
-                                       <enumlist>
-                                               <enum name="Uncleanly"/>
-                                               <enum name="Cleanly"/>
-                                       </enumlist>
-                               </parameter>
-                               <parameter name="Restart">
-                                       <enumlist>
-                                               <enum name="True"/>
-                                               <enum name="False"/>
-                                       </enumlist>
-                               </parameter>
-                       </syntax>
-               </managerEventInstance>
-       ***/
-       manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\n"
-               "Restart: %s\r\n",
-               active_channels ? "Uncleanly" : "Cleanly",
-               restart ? "True" : "False");
+       if (!ast_opt_remote) {
+               json_object = ast_json_pack("{s: s, s: s}",
+                               "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
+                               "Restart", restart ? "True" : "False");
+               ast_manager_publish_event("Shutdown", EVENT_FLAG_SYSTEM, json_object);
+               ast_json_unref(json_object);
+               json_object = NULL;
+       }
        ast_verb(0, "Asterisk %s ending (%d).\n",
                active_channels ? "uncleanly" : "cleanly", num);
 
        ast_verb(0, "Executing last minute cleanups\n");
-       ast_run_atexits();
+       ast_run_atexits(run_cleanups);
 
        ast_debug(1, "Asterisk ending (%d).\n", num);
        if (ast_socket > -1) {
@@ -1924,11 +1975,17 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
                close(ast_socket);
                ast_socket = -1;
                unlink(ast_config_AST_SOCKET);
+               pthread_kill(lthread, SIGURG);
+               pthread_join(lthread, NULL);
        }
        if (ast_consock > -1)
                close(ast_consock);
        if (!ast_opt_remote)
                unlink(ast_config_AST_PID);
+       if (sig_alert_pipe[0])
+               close(sig_alert_pipe[0]);
+       if (sig_alert_pipe[1])
+               close(sig_alert_pipe[1]);
        printf("%s", term_quit());
        if (restart) {
                int i;
@@ -1980,49 +2037,127 @@ static void __remote_quit_handler(int num)
        sig_flags.need_quit = 1;
 }
 
-static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
+static const char *fix_header(char *outbuf, int maxout, const char *s, char level)
 {
-       const char *c;
+       const char *cmp;
+
+       switch (level) {
+       case 0: *outbuf = '\0';
+               return s;
+       case 1: cmp = VERBOSE_PREFIX_1;
+               break;
+       case 2: cmp = VERBOSE_PREFIX_2;
+               break;
+       case 3: cmp = VERBOSE_PREFIX_3;
+               break;
+       default: cmp = VERBOSE_PREFIX_4;
+               break;
+       }
 
        if (!strncmp(s, cmp, strlen(cmp))) {
-               c = s + strlen(cmp);
-               term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
-               return c;
+               s += strlen(cmp);
        }
-       return NULL;
+       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
+
+       return s;
 }
 
+struct console_state_data {
+       char verbose_line_level;
+};
+
+static int console_state_init(void *ptr)
+{
+       struct console_state_data *state = ptr;
+       state->verbose_line_level = 0;
+       return 0;
+}
+
+AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr);
+
 /* These gymnastics are due to platforms which designate char as unsigned by
  * default. Level is the negative character -- offset by 1, because \0 is the
  * EOS delimiter. */
 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
 #define VERBOSE_HASMAGIC(x)    (*(signed char *) (x) < 0)
 
-static void console_verboser(const char *s)
+static int console_print(const char *s, int local)
 {
-       char tmp[80];
-       const char *c = NULL;
-       char level = 0;
+       struct console_state_data *state =
+               ast_threadstorage_get(&console_state, sizeof(*state));
 
-       if (VERBOSE_HASMAGIC(s)) {
-               level = VERBOSE_MAGIC2LEVEL(s);
-               s++;
-               if (level > option_verbose) {
-                       return;
+       char prefix[80];
+       const char *c;
+       int num, res = 0;
+       unsigned int newline;
+
+       do {
+               if (VERBOSE_HASMAGIC(s)) {
+                       /* always use the given line's level, otherwise
+                          we'll use the last line's level */
+                       state->verbose_line_level = VERBOSE_MAGIC2LEVEL(s);
+                       /* move past magic */
+                       s++;
+
+                       if (local) {
+                               s = fix_header(prefix, sizeof(prefix), s,
+                                              state->verbose_line_level);
+                       }
+               } else {
+                       *prefix = '\0';
+               }
+               c = s;
+
+               /* for a given line separate on verbose magic, newline, and eol */
+               if ((s = strchr(c, '\n'))) {
+                       ++s;
+                       newline = 1;
+               } else {
+                       s = strchr(c, '\0');
+                       newline = 0;
+               }
+
+               /* check if we should write this line after calculating begin/end
+                  so we process the case of a higher level line embedded within
+                  two lower level lines */
+               if (state->verbose_line_level > option_verbose) {
+                       continue;
+               }
+
+               if (local && !ast_strlen_zero(prefix)) {
+                       fputs(prefix, stdout);
+               }
+
+               num = s - c;
+               if (fwrite(c, sizeof(char), num, stdout) < num) {
+                       break;
                }
+
+               if (!res) {
+                       /* if at least some info has been written
+                          we'll want to return true */
+                       res = 1;
+               }
+       } while (*s);
+
+       if (newline) {
+               /* if ending on a newline then reset last level to zero
+                   since what follows may be not be logging output */
+               state->verbose_line_level = 0;
        }
 
-       if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
-           (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
-           (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
-           (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
-               fputs(tmp, stdout);
-               fputs(c, stdout);
-       } else {
-               fputs(s, stdout);
+       if (res) {
+               fflush(stdout);
        }
 
-       fflush(stdout);
+       return res;
+}
+
+static void console_verboser(const char *s)
+{
+       if (!console_print(s, 1)) {
+               return;
+       }
 
        /* Wake up a poll()ing console */
        if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
@@ -2065,6 +2200,11 @@ static int remoteconsolehandler(char *s)
        /* Called when readline data is available */
        if (!ast_all_zeros(s))
                ast_el_add_history(s);
+
+       while (isspace(*s)) {
+               s++;
+       }
+
        /* The real handler for bang */
        if (s[0] == '!') {
                if (s[1])
@@ -2425,23 +2565,6 @@ static struct ast_cli_entry cli_asterisk[] = {
 #endif /* ! LOW_MEMORY */
 };
 
-struct el_read_char_state_struct {
-       unsigned int line_full:1;
-       unsigned int prev_line_full:1;
-       char prev_line_verbosity;
-};
-
-static int el_read_char_state_init(void *ptr)
-{
-       struct el_read_char_state_struct *state = ptr;
-       state->line_full = 1;
-       state->prev_line_full = 1;
-       state->prev_line_verbosity = 0;
-       return 0;
-}
-
-AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
-
 static int ast_el_read_char(EditLine *editline, char *cp)
 {
        int num_read = 0;
@@ -2451,7 +2574,6 @@ static int ast_el_read_char(EditLine *editline, char *cp)
        int max;
 #define EL_BUF_SIZE 512
        char buf[EL_BUF_SIZE];
-       struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
 
        for (;;) {
                max = 1;
@@ -2481,8 +2603,6 @@ static int ast_el_read_char(EditLine *editline, char *cp)
                        }
                }
                if (fds[0].revents) {
-                       char level = 0;
-                       char *curline = buf, *nextline;
                        res = read(ast_consock, buf, sizeof(buf) - 1);
                        /* if the remote side disappears exit */
                        if (res < 1) {
@@ -2522,33 +2642,7 @@ static int ast_el_read_char(EditLine *editline, char *cp)
                                }
                        }
 
-                       do {
-                               state->prev_line_full = state->line_full;
-                               if ((nextline = strchr(curline, '\n'))) {
-                                       state->line_full = 1;
-                                       nextline++;
-                               } else {
-                                       state->line_full = 0;
-                                       nextline = strchr(curline, '\0');
-                               }
-
-                               if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
-                                       level = VERBOSE_MAGIC2LEVEL(curline);
-                                       curline++;
-                               } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
-                                       /* Non-verbose output */
-                                       level = 0;
-                               } else {
-                                       level = state->prev_line_verbosity;
-                               }
-                               if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
-                                       if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
-                                       }
-                               }
-
-                               state->prev_line_verbosity = level;
-                               curline = nextline;
-                       } while (!ast_strlen_zero(curline));
+                       console_print(buf, 0);
 
                        if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
                                *cp = CC_REFRESH;
@@ -2570,7 +2664,6 @@ static char *cli_prompt(EditLine *editline)
        char *pfmt;
        int color_used = 0;
        static int cli_prompt_changes = 0;
-       char term_code[20];
        struct passwd *pw;
        struct group *gr;
 
@@ -2597,10 +2690,10 @@ static char *cli_prompt(EditLine *editline)
                                case 'C': /* color */
                                        t++;
                                        if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
-                                               ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
+                                               ast_term_color_code(&prompt, fgcolor, bgcolor);
                                                t += i - 1;
                                        } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
-                                               ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
+                                               ast_term_color_code(&prompt, fgcolor, 0);
                                                t += i - 1;
                                        }
 
@@ -2680,7 +2773,7 @@ static char *cli_prompt(EditLine *editline)
                }
                if (color_used) {
                        /* Force colors back to normal at end */
-                       ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
+                       ast_term_color_code(&prompt, 0, 0);
                }
        } else if (remotehostname) {
                ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
@@ -2691,45 +2784,62 @@ static char *cli_prompt(EditLine *editline)
        return ast_str_buffer(prompt);
 }
 
+static void destroy_match_list(char **match_list, int matches)
+{
+       if (match_list) {
+               int idx;
+
+               for (idx = 0; idx < matches; ++idx) {
+                       ast_free(match_list[idx]);
+               }
+               ast_free(match_list);
+       }
+}
+
 static char **ast_el_strtoarr(char *buf)
 {
-       char **match_list = NULL, **match_list_tmp, *retstr;
-       size_t match_list_len;
+       char *retstr;
+       char **match_list = NULL;
+       char **new_list;
+       size_t match_list_len = 1;
        int matches = 0;
 
-       match_list_len = 1;
-       while ( (retstr = strsep(&buf, " ")) != NULL) {
-
-               if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
+       while ((retstr = strsep(&buf, " "))) {
+               if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) {
                        break;
+               }
                if (matches + 1 >= match_list_len) {
                        match_list_len <<= 1;
-                       if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
-                               match_list = match_list_tmp;
-                       } else {
-                               if (match_list)
-                                       ast_free(match_list);
-                               return (char **) NULL;
+                       new_list = ast_realloc(match_list, match_list_len * sizeof(char *));
+                       if (!new_list) {
+                               destroy_match_list(match_list, matches);
+                               return NULL;
                        }
+                       match_list = new_list;
                }
 
-               match_list[matches++] = ast_strdup(retstr);
+               retstr = ast_strdup(retstr);
+               if (!retstr) {
+                       destroy_match_list(match_list, matches);
+                       return NULL;
+               }
+               match_list[matches++] = retstr;
        }
 
-       if (!match_list)
-               return (char **) NULL;
+       if (!match_list) {
+               return NULL;
+       }
 
        if (matches >= match_list_len) {
-               if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
-                       match_list = match_list_tmp;
-               } else {
-                       if (match_list)
-                               ast_free(match_list);
-                       return (char **) NULL;
+               new_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *));
+               if (!new_list) {
+                       destroy_match_list(match_list, matches);
+                       return NULL;
                }
+               match_list = new_list;
        }
 
-       match_list[matches] = (char *) NULL;
+       match_list[matches] = NULL;
 
        return match_list;
 }
@@ -2830,7 +2940,9 @@ static char *cli_complete(EditLine *editline, int ch)
 
                if (nummatches > 0) {
                        char *mbuf;
+                       char *new_mbuf;
                        int mlen = 0, maxmbuf = 2048;
+
                        /* Start with a 2048 byte buffer */
                        if (!(mbuf = ast_malloc(maxmbuf))) {
                                *((char *) lf->cursor) = savechr;
@@ -2844,10 +2956,13 @@ static char *cli_complete(EditLine *editline, int ch)
                                if (mlen + 1024 > maxmbuf) {
                                        /* Every step increment buffer 1024 bytes */
                                        maxmbuf += 1024;
-                                       if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
+                                       new_mbuf = ast_realloc(mbuf, maxmbuf);
+                                       if (!new_mbuf) {
+                                               ast_free(mbuf);
                                                *((char *) lf->cursor) = savechr;
                                                return (char *)(CC_ERROR);
                                        }
+                                       mbuf = new_mbuf;
                                }
                                /* Only read 1024 bytes at a time */
                                res = read(ast_consock, mbuf + mlen, 1024);
@@ -2970,12 +3085,23 @@ static int ast_el_initialize(void)
 static int ast_el_add_history(char *buf)
 {
        HistEvent ev;
+       char *stripped_buf;
 
-       if (el_hist == NULL || el == NULL)
+       if (el_hist == NULL || el == NULL) {
                ast_el_initialize();
-       if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
+       }
+       if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1)) {
                return 0;
-       return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
+       }
+
+       stripped_buf = ast_strip(ast_strdupa(buf));
+
+       /* HISTCONTROL=ignoredups */
+       if (!history(el_hist, &ev, H_FIRST) && strcmp(ev.str, stripped_buf) == 0) {
+               return 0;
+       }
+
+       return history(el_hist, &ev, H_ENTER, stripped_buf);
 }
 
 static int ast_el_write_history(char *filename)
@@ -3158,7 +3284,7 @@ static int show_version(void)
 
 static int show_cli_help(void)
 {
-       printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
+       printf("Asterisk %s, Copyright (C) 1999 - 2013, Digium, Inc. and others.\n", ast_get_version());
        printf("Usage: asterisk [OPTIONS]\n");
        printf("Valid Options:\n");
        printf("   -V              Display version number and exit\n");
@@ -3225,6 +3351,7 @@ static void ast_readconfig(void)
        ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
        ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
        snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
+       snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", cfg_paths.spool_dir);
        ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
        ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
        ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
@@ -3260,6 +3387,7 @@ static void ast_readconfig(void)
                } else if (!strcasecmp(v->name, "astspooldir")) {
                        ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
                        snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
+                       snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", v->value);
                } else if (!strcasecmp(v->name, "astvarlibdir")) {
                        ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
                        if (!found.dbdir)
@@ -3354,22 +3482,22 @@ static void ast_readconfig(void)
                                option_dtmfminduration = AST_MIN_DTMF_DURATION;
                        }
                } else if (!strcasecmp(v->name, "maxcalls")) {
-                       if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
-                               option_maxcalls = 0;
+                       if ((sscanf(v->value, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) {
+                               ast_option_maxcalls = 0;
                        }
                } else if (!strcasecmp(v->name, "maxload")) {
                        double test[1];
 
                        if (getloadavg(test, 1) == -1) {
                                ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
-                               option_maxload = 0.0;
-                       } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
-                               option_maxload = 0.0;
+                               ast_option_maxload = 0.0;
+                       } else if ((sscanf(v->value, "%30lf", &ast_option_maxload) != 1) || (ast_option_maxload < 0.0)) {
+                               ast_option_maxload = 0.0;
                        }
                /* Set the maximum amount of open files */
                } else if (!strcasecmp(v->name, "maxfiles")) {
-                       option_maxfiles = atoi(v->value);
-                       set_ulimit(option_maxfiles);
+                       ast_option_maxfiles = atoi(v->value);
+                       set_ulimit(ast_option_maxfiles);
                /* What user to run as */
                } else if (!strcasecmp(v->name, "runuser")) {
                        ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
@@ -3392,7 +3520,7 @@ static void ast_readconfig(void)
                } else if (!strcasecmp(v->name, "languageprefix")) {
                        ast_language_is_prefix = ast_true(v->value);
                } else if (!strcasecmp(v->name, "defaultlanguage")) {
-                       ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
+                       ast_copy_string(ast_defaultlanguage, v->value, MAX_LANGUAGE);
                } else if (!strcasecmp(v->name, "lockmode")) {
                        if (!strcasecmp(v->value, "lockfile")) {
                                ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
@@ -3560,7 +3688,7 @@ static void env_init(void)
 
 static void print_intro_message(const char *runuser, const char *rungroup)
 {
-       if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
+       if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
                if (ast_register_verbose(console_verboser)) {
                        fprintf(stderr, "Unable to register console verboser?\n");
                        return;
@@ -3585,7 +3713,6 @@ int main(int argc, char *argv[])
        int c;
        char filename[80] = "";
        char hostname[MAXHOSTNAMELEN] = "";
-       char tmp[80];
        char * xarg = NULL;
        int x;
        FILE *f;
@@ -3678,13 +3805,13 @@ int main(int argc, char *argv[])
                        ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
                        break;
                case 'L':
-                       if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
-                               option_maxload = 0.0;
+                       if ((sscanf(optarg, "%30lf", &ast_option_maxload) != 1) || (ast_option_maxload < 0.0)) {
+                               ast_option_maxload = 0.0;
                        }
                        break;
                case 'M':
-                       if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
-                               option_maxcalls = 0;
+                       if ((sscanf(optarg, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) {
+                               ast_option_maxcalls = 0;
                        }
                        break;
                case 'm':
@@ -4055,8 +4182,8 @@ int main(int argc, char *argv[])
 
        print_intro_message(runuser, rungroup);
 
-       if (ast_opt_console && !option_verbose) {
-               ast_verbose("[ Initializing Custom Configuration Options ]\n");
+       if (ast_opt_console) {
+               ast_verb(0, "[ Initializing Custom Configuration Options ]\n");
        }
        /* custom config setup */
        register_config_cli();
@@ -4070,6 +4197,7 @@ int main(int argc, char *argv[])
                        ast_el_read_history(filename);
        }
 
+       ast_json_init();
        ast_ulaw_init();
        ast_alaw_init();
        tdd_init();
@@ -4096,11 +4224,6 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
-       if (ast_event_init()) {
-               printf("%s", term_quit());
-               exit(1);
-       }
-
 #ifdef TEST_FRAMEWORK
        if (ast_test_init()) {
                printf("%s", term_quit());
@@ -4116,6 +4239,38 @@ int main(int argc, char *argv[])
        ast_aoc_cli_init();
        ast_uuid_init();
 
+       if (ast_sorcery_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
+#ifdef AST_XML_DOCS
+       /* Load XML documentation. */
+       ast_xmldoc_load_documentation();
+#endif
+
+       aco_init();
+
+       if (ast_bucket_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
+       if (stasis_init()) {
+               printf("Stasis initialization failed.\n%s", term_quit());
+               exit(1);
+       }
+
+       if (ast_stasis_system_init()) {
+               printf("Stasis system-level information initialization failed.\n%s", term_quit());
+               exit(1);
+       }
+
+       if (ast_endpoint_stasis_init()) {
+               printf("Endpoint initialization failed.\n%s", term_quit());
+               exit(1);
+       }
+
        ast_makesocket();
        sigemptyset(&sigs);
        sigaddset(&sigs, SIGHUP);
@@ -4147,7 +4302,10 @@ int main(int argc, char *argv[])
 
        ast_format_attr_init();
        ast_format_list_init();
-       ast_rtp_engine_init();
+       if (ast_rtp_engine_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
 
        ast_autoservice_init();
 
@@ -4161,10 +4319,15 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
-#ifdef AST_XML_DOCS
-       /* Load XML documentation. */
-       ast_xmldoc_load_documentation();
-#endif
+       if (app_init()) {
+               printf("App core initialization failed.\n%s", term_quit());
+               exit(1);
+       }
+
+       if (devstate_init()) {
+               printf("Device state core initialization failed.\n%s", term_quit());
+               exit(1);
+       }
 
        if (astdb_init()) {
                printf("%s", term_quit());
@@ -4184,6 +4347,11 @@ int main(int argc, char *argv[])
 
        ast_channels_init();
 
+       if (ast_endpoint_init()) {
+               printf ("%s", term_quit());
+               exit(1);
+       }
+
        if ((moduleresult = load_modules(1))) {         /* Load modules, pre-load only */
                printf("%s", term_quit());
                exit(moduleresult == -2 ? 2 : 1);
@@ -4194,6 +4362,11 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       if (ast_security_stasis_init()) {               /* Initialize Security Stasis Topic and Events */
+               printf("%s", term_quit());
+               exit(1);
+       }
+
        if (ast_named_acl_init()) { /* Initialize the Named ACL system */
                printf("%s", term_quit());
                exit(1);
@@ -4201,17 +4374,32 @@ int main(int argc, char *argv[])
 
        ast_http_init();                /* Start the HTTP server, if needed */
 
-       if (init_manager()) {
+       if (ast_indications_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_cdr_engine_init()) {
+       if (ast_features_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_cel_engine_init()) {
+       if (ast_pickup_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
+       if (ast_bridging_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
+       if (ast_parking_stasis_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
+       if (ast_cdr_engine_init()) {
                printf("%s", term_quit());
                exit(1);
        }
@@ -4244,12 +4432,17 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
-       if (ast_indications_init()) {
+       if (ast_local_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_features_init()) {
+       if (ast_cel_engine_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
+       if (init_manager()) {
                printf("%s", term_quit());
                exit(1);
        }
@@ -4264,6 +4457,11 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       if (ast_sounds_index_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
        if ((moduleresult = load_modules(0))) {         /* Load modules */
                printf("%s", term_quit());
                exit(moduleresult == -2 ? 2 : 1);
@@ -4278,7 +4476,7 @@ int main(int argc, char *argv[])
 
        /* We might have the option of showing a console, but for now just
           do nothing... */
-       ast_verb(0, "%s\n", term_color(tmp, "Asterisk Ready.", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
+       ast_verb(0, COLORIZE_FMT "\n", COLORIZE(COLOR_BRWHITE, COLOR_BLACK, "Asterisk Ready."));
        if (ast_opt_no_fork) {
                consolethread = pthread_self();
        }
@@ -4288,12 +4486,7 @@ int main(int argc, char *argv[])
        }
 
        ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
-       /*** DOCUMENTATION
-               <managerEventInstance>
-                       <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
-               </managerEventInstance>
-       ***/
-       manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
+       publish_fully_booted();
 
        ast_process_pending_reloads();