memory leaks: Memory leak cleanup patch by Corey Farrell (second set)
[asterisk/asterisk.git] / main / asterisk.c
index 73d390f..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"
@@ -240,10 +241,13 @@ int daemon(int, int);  /* defined in libresolv of all places */
 #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"
 
@@ -297,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" \
@@ -317,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 */
@@ -347,6 +351,7 @@ struct console {
 
 struct ast_atexit {
        void (*func)(void);
+       int is_cleanup;
        AST_LIST_ENTRY(ast_atexit) list;
 };
 
@@ -361,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 *);
@@ -372,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];
@@ -396,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;
@@ -445,12 +452,6 @@ static struct {
         unsigned int need_quit_handler:1;
 } sig_flags;
 
-/*! \brief The \ref stasis topic for system level changes */
-static struct stasis_topic *system_topic;
-
-/*!\ brief The \ref stasis_message_type for network changes */
-STASIS_MESSAGE_TYPE_DEFN(ast_network_change_type);
-
 #if !defined(LOW_MEMORY)
 struct file_version {
        AST_RWLIST_ENTRY(file_version) list;
@@ -458,9 +459,6 @@ struct file_version {
        char *version;
 };
 
-/*! \brief The \ref stasis topic for system level changes */
-static struct stasis_topic *system_topic;
-
 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
 
 void ast_register_file_version(const char *file, const char *version)
@@ -603,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
@@ -628,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");
@@ -642,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  */
@@ -1095,87 +1093,22 @@ static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct
 
 #endif /* ! LOW_MEMORY */
 
-struct stasis_topic *ast_system_topic(void)
-{
-       return system_topic;
-}
-
-/*! \brief Cleanup the \ref stasis system level items */
-static void stasis_system_topic_cleanup(void)
-{
-       ao2_cleanup(system_topic);
-       system_topic = NULL;
-       STASIS_MESSAGE_TYPE_CLEANUP(ast_network_change_type);
-}
-
-/*! \brief Initialize the system level items for \ref stasis */
-static int stasis_system_topic_init(void)
-{
-       ast_register_atexit(stasis_system_topic_cleanup);
-
-       system_topic = stasis_topic_create("ast_system");
-       if (!system_topic) {
-               return 1;
-       }
-
-       if (STASIS_MESSAGE_TYPE_INIT(ast_network_change_type) != 0) {
-               return -1;
-       }
-
-       return 0;
-}
-
-/*!
- * \brief Publish a \ref system_status_type message over \ref stasis
- *
- * \param payload The JSON payload to send with the message
- */
-static void publish_system_message(const char *message_type, struct ast_json *obj)
-{
-       RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-       RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
-       RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref);
-
-       if (!obj) {
-               return;
-       }
-
-       event_info = ast_json_pack("{s: s, s: i, s: o}",
-                       "type", message_type,
-                       "class_type", EVENT_FLAG_SYSTEM,
-                       "event", obj);
-       if (!event_info) {
-               return;
-       }
-
-       payload = ast_json_payload_create(event_info);
-       if (!payload) {
-               return;
-       }
-
-       message = stasis_message_create(ast_manager_get_generic_type(), payload);
-       if (!message) {
-               return;
-       }
-       stasis_publish(ast_manager_get_topic(), message);
-}
-
 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");
-       publish_system_message("FullyBooted", json_object);
+       ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
 }
 
-static void ast_run_atexits(void)
+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);
@@ -1197,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;
 
@@ -1206,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);
@@ -1215,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);
@@ -1929,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 (;;) {
@@ -1946,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 (;;) {
@@ -1962,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);
@@ -1978,9 +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;
-       RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
+       struct ast_json *json_object = NULL;
+       int run_cleanups = niceness >= SHUTDOWN_NICE;
 
-       if (niceness >= SHUTDOWN_NICE) {
+       if (run_cleanups) {
                ast_module_shutdown();
        }
 
@@ -2007,15 +1952,22 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
                }
        }
        active_channels = ast_active_channels();
-       json_object = ast_json_pack("{s: s, s: s}",
-                       "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
-                       "Restart", restart ? "True" : "False");
-       publish_system_message("Shutdown", json_object);
+       /* Don't publish messages if we're a remote console - we won't have all of the Stasis
+        * topics or message types
+        */
+       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) {
@@ -2023,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;
@@ -2079,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) {
@@ -2164,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])
@@ -2524,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;
@@ -2550,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;
@@ -2580,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) {
@@ -2621,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;
@@ -2789,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;
 }
@@ -2928,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;
@@ -2942,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);
@@ -3068,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)
@@ -3256,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");
@@ -3323,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));
@@ -3358,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)
@@ -3452,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));
@@ -3490,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);
@@ -3658,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;
@@ -3775,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':
@@ -4152,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();
@@ -4194,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());
@@ -4219,11 +4244,24 @@ int main(int argc, char *argv[])
                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 (stasis_system_topic_init()) {
+
+       if (ast_stasis_system_init()) {
                printf("Stasis system-level information initialization failed.\n%s", term_quit());
                exit(1);
        }
@@ -4264,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();
 
@@ -4278,13 +4319,6 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
-#ifdef AST_XML_DOCS
-       /* Load XML documentation. */
-       ast_xmldoc_load_documentation();
-#endif
-
-       aco_init();
-
        if (app_init()) {
                printf("App core initialization failed.\n%s", term_quit());
                exit(1);
@@ -4313,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);
@@ -4324,7 +4363,6 @@ int main(int argc, char *argv[])
        }
 
        if (ast_security_stasis_init()) {               /* Initialize Security Stasis Topic and Events */
-               ast_security_stasis_cleanup();
                printf("%s", term_quit());
                exit(1);
        }
@@ -4336,55 +4374,60 @@ int main(int argc, char *argv[])
 
        ast_http_init();                /* Start the HTTP server, if needed */
 
-       if (ast_cdr_engine_init()) {
+       if (ast_indications_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_cel_engine_init()) {
+       if (ast_features_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_device_state_engine_init()) {
+       if (ast_pickup_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_presence_state_engine_init()) {
+       if (ast_bridging_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       ast_dsp_init();
-       ast_udptl_init();
+       if (ast_parking_stasis_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
 
-       if (ast_image_init()) {
+       if (ast_cdr_engine_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_file_init()) {
+       if (ast_device_state_engine_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (load_pbx()) {
+       if (ast_presence_state_engine_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_indications_init()) {
+       ast_dsp_init();
+       ast_udptl_init();
+
+       if (ast_image_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_features_init()) {
+       if (ast_file_init()) {
                printf("%s", term_quit());
                exit(1);
        }
 
-       if (ast_bridging_init()) {
+       if (load_pbx()) {
                printf("%s", term_quit());
                exit(1);
        }
@@ -4394,6 +4437,11 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       if (ast_cel_engine_init()) {
+               printf("%s", term_quit());
+               exit(1);
+       }
+
        if (init_manager()) {
                printf("%s", term_quit());
                exit(1);
@@ -4409,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);