Fix potential segfault, add support for MacOS X locks
[asterisk/asterisk.git] / manager.c
index 0305c9f..c77fec1 100755 (executable)
--- a/manager.c
+++ b/manager.c
 #include <pthread.h>
 #include <string.h>
 #include <sys/time.h>
 #include <pthread.h>
 #include <string.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <netdb.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <signal.h>
 #include <errno.h>
 #include <unistd.h>
 #include <arpa/inet.h>
 #include <signal.h>
 #include <errno.h>
 #include <unistd.h>
+#include <sys/poll.h>
 #include <asterisk/channel.h>
 #include <asterisk/file.h>
 #include <asterisk/manager.h>
 #include <asterisk/channel.h>
 #include <asterisk/file.h>
 #include <asterisk/manager.h>
 #include <asterisk/app.h>
 #include <asterisk/pbx.h>
 #include <asterisk/md5.h>
 #include <asterisk/app.h>
 #include <asterisk/pbx.h>
 #include <asterisk/md5.h>
+#include <asterisk/acl.h>
+
+struct fast_originate_helper
+{
+       char tech[256];
+       char data[256];
+       int timeout;
+       char app[256];
+       char appdata[256];
+       char callerid[256];
+       char variable[256];
+       char account[256];
+       char context[256];
+       char exten[256];
+       int priority;
+};
 
 static int enabled = 0;
 static int portno = DEFAULT_MANAGER_PORT;
 static int asock = -1;
 static pthread_t t;
 
 static int enabled = 0;
 static int portno = DEFAULT_MANAGER_PORT;
 static int asock = -1;
 static pthread_t t;
-static pthread_mutex_t sessionlock = AST_MUTEX_INITIALIZER;
+static ast_mutex_t sessionlock = AST_MUTEX_INITIALIZER;
+static int block_sockets = 0;
 
 static struct permalias {
        int num;
 
 static struct permalias {
        int num;
@@ -50,40 +71,67 @@ static struct permalias {
        { EVENT_FLAG_VERBOSE, "verbose" },
        { EVENT_FLAG_COMMAND, "command" },
        { EVENT_FLAG_AGENT, "agent" },
        { EVENT_FLAG_VERBOSE, "verbose" },
        { EVENT_FLAG_COMMAND, "command" },
        { EVENT_FLAG_AGENT, "agent" },
+       { EVENT_FLAG_USER, "user" },
        { -1, "all" },
 };
 
 static struct mansession *sessions = NULL;
 static struct manager_action *first_action = NULL;
        { -1, "all" },
 };
 
 static struct mansession *sessions = NULL;
 static struct manager_action *first_action = NULL;
-static pthread_mutex_t actionlock = AST_MUTEX_INITIALIZER;
+static ast_mutex_t actionlock = AST_MUTEX_INITIALIZER;
+
+int ast_carefulwrite(int fd, char *s, int len, int timeoutms) 
+{
+       /* Try to write string, but wait no more than ms milliseconds
+          before timing out */
+       int res=0;
+       struct pollfd fds[1];
+       while(len) {
+               res = write(fd, s, len);
+               if ((res < 0) && (errno != EAGAIN)) {
+                       return -1;
+               }
+               if (res < 0) res = 0;
+               len -= res;
+               s += res;
+               fds[0].fd = fd;
+               fds[0].events = POLLOUT;
+               /* Wait until writable again */
+               res = poll(fds, 1, timeoutms);
+               if (res < 1)
+                       return -1;
+       }
+       return res;
+}
 
 static int handle_showmancmds(int fd, int argc, char *argv[])
 {
        struct manager_action *cur = first_action;
 
 static int handle_showmancmds(int fd, int argc, char *argv[])
 {
        struct manager_action *cur = first_action;
+       char *format = "  %-15.15s  %-45.45s\n";
 
 
-       ast_pthread_mutex_lock(&actionlock);
+       ast_mutex_lock(&actionlock);
+       ast_cli(fd, format, "Action", "Synopsis");
        while(cur) { /* Walk the list of actions */
        while(cur) { /* Walk the list of actions */
-               ast_cli(fd, "\t%s  %s\r\n",cur->action, cur->synopsis);
+               ast_cli(fd, format, cur->action, cur->synopsis);
                cur = cur->next;
        }
 
                cur = cur->next;
        }
 
-       ast_pthread_mutex_unlock(&actionlock);
+       ast_mutex_unlock(&actionlock);
        return RESULT_SUCCESS;
 }
 
 static int handle_showmanconn(int fd, int argc, char *argv[])
 {
        struct mansession *s;
        return RESULT_SUCCESS;
 }
 
 static int handle_showmanconn(int fd, int argc, char *argv[])
 {
        struct mansession *s;
-
-       ast_pthread_mutex_lock(&sessionlock);
+       char *format = "  %-15.15s  %-15.15s\n";
+       ast_mutex_lock(&sessionlock);
        s = sessions;
        s = sessions;
-       ast_cli(fd, "  Username\tIP Address\n");
+       ast_cli(fd, format, "Username", "IP Address");
        while(s) {
        while(s) {
-               ast_cli(fd, "  %s\t\t%s\r\n",s->username, inet_ntoa(s->sin.sin_addr));
+               ast_cli(fd, format,s->username, inet_ntoa(s->sin.sin_addr));
                s = s->next;
        }
 
                s = s->next;
        }
 
-       ast_pthread_mutex_unlock(&sessionlock);
+       ast_mutex_unlock(&sessionlock);
        return RESULT_SUCCESS;
 }
 
        return RESULT_SUCCESS;
 }
 
@@ -107,7 +155,7 @@ static struct ast_cli_entry show_manconn_cli =
 static void destroy_session(struct mansession *s)
 {
        struct mansession *cur, *prev = NULL;
 static void destroy_session(struct mansession *s)
 {
        struct mansession *cur, *prev = NULL;
-       ast_pthread_mutex_lock(&sessionlock);
+       ast_mutex_lock(&sessionlock);
        cur = sessions;
        while(cur) {
                if (cur == s)
        cur = sessions;
        while(cur) {
                if (cur == s)
@@ -125,11 +173,11 @@ static void destroy_session(struct mansession *s)
                free(s);
        } else
                ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
                free(s);
        } else
                ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
-       ast_pthread_mutex_unlock(&sessionlock);
+       ast_mutex_unlock(&sessionlock);
        
 }
 
        
 }
 
-static char *get_header(struct message *m, char *var)
+char *astman_get_header(struct message *m, char *var)
 {
        char cmp[80];
        int x;
 {
        char cmp[80];
        int x;
@@ -140,28 +188,34 @@ static char *get_header(struct message *m, char *var)
        return "";
 }
 
        return "";
 }
 
-static void send_error(struct mansession *s, char *error)
+void astman_send_error(struct mansession *s, struct message *m, char *error)
 {
 {
-       ast_pthread_mutex_lock(&s->lock);
+       char *id = astman_get_header(m,"ActionID");
+       ast_mutex_lock(&s->lock);
        ast_cli(s->fd, "Response: Error\r\n");
        ast_cli(s->fd, "Response: Error\r\n");
+       if (id && strlen(id))
+               ast_cli(s->fd, "ActionID: %s\r\n",id);
        ast_cli(s->fd, "Message: %s\r\n\r\n", error);
        ast_cli(s->fd, "Message: %s\r\n\r\n", error);
-       ast_pthread_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->lock);
 }
 
 }
 
-static void send_response(struct mansession *s, char *resp, char *msg)
+void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
 {
 {
-       ast_pthread_mutex_lock(&s->lock);
+       char *id = astman_get_header(m,"ActionID");
+       ast_mutex_lock(&s->lock);
        ast_cli(s->fd, "Response: %s\r\n", resp);
        ast_cli(s->fd, "Response: %s\r\n", resp);
+       if (id && strlen(id))
+               ast_cli(s->fd, "ActionID: %s\r\n",id);
        if (msg)
                ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
        else
                ast_cli(s->fd, "\r\n");
        if (msg)
                ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
        else
                ast_cli(s->fd, "\r\n");
-       ast_pthread_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->lock);
 }
 
 }
 
-static void send_ack(struct mansession *s, char *msg)
+void astman_send_ack(struct mansession *s, struct message *m, char *msg)
 {
 {
-       send_response(s, "Success", msg);
+       astman_send_response(s, m, "Success", msg);
 }
 
 static int get_perm(char *instr)
 }
 
 static int get_perm(char *instr)
@@ -186,15 +240,34 @@ static int get_perm(char *instr)
        return ret;
 }
 
        return ret;
 }
 
+static int set_eventmask(struct mansession *s, char *eventmask)
+{
+       if (!eventmask)
+               return -1;
+       if (!strcasecmp(eventmask, "on") || ast_true(eventmask)) {
+               ast_mutex_lock(&s->lock);
+               s->send_events = 1;
+               ast_mutex_unlock(&s->lock);
+               return 1;
+       } else if (!strcasecmp(eventmask, "off") || ast_false(eventmask)) {
+               ast_mutex_lock(&s->lock);
+               s->send_events = 0;
+               ast_mutex_unlock(&s->lock);
+               return 0;
+       }
+       return -1;
+}
+
 static int authenticate(struct mansession *s, struct message *m)
 {
        struct ast_config *cfg;
        char *cat;
 static int authenticate(struct mansession *s, struct message *m)
 {
        struct ast_config *cfg;
        char *cat;
-       char *user = get_header(m, "Username");
-       char *pass = get_header(m, "Secret");
-       char *authtype = get_header(m, "AuthType");
-       char *key = get_header(m, "Key");
-
+       char *user = astman_get_header(m, "Username");
+       char *pass = astman_get_header(m, "Secret");
+       char *authtype = astman_get_header(m, "AuthType");
+       char *key = astman_get_header(m, "Key");
+       char *events = astman_get_header(m, "Events");
+       
        cfg = ast_load("manager.conf");
        if (!cfg)
                return -1;
        cfg = ast_load("manager.conf");
        if (!cfg)
                return -1;
@@ -203,7 +276,26 @@ static int authenticate(struct mansession *s, struct message *m)
                if (strcasecmp(cat, "general")) {
                        /* This is a user */
                        if (!strcasecmp(cat, user)) {
                if (strcasecmp(cat, "general")) {
                        /* This is a user */
                        if (!strcasecmp(cat, user)) {
-                               char *password = ast_variable_retrieve(cfg, cat, "secret");
+                               struct ast_variable *v;
+                               struct ast_ha *ha = NULL;
+                               char *password = NULL;
+                               v = ast_variable_browse(cfg, cat);
+                               while (v) {
+                                       if (!strcasecmp(v->name, "secret")) {
+                                               password = v->value;
+                                       } else if (!strcasecmp(v->name, "permit") ||
+                                                  !strcasecmp(v->name, "deny")) {
+                                                       ha = ast_append_ha(v->name, v->value, ha);
+                                       }                                               
+                                       v = v->next;
+                               }
+                               if (ha && !ast_apply_ha(ha, &(s->sin))) {
+                                       ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", inet_ntoa(s->sin.sin_addr), user);
+                                       ast_free_ha(ha);
+                                       ast_destroy(cfg);
+                                       return -1;
+                               } else if (ha)
+                                       ast_free_ha(ha);
                                if (!strcasecmp(authtype, "MD5")) {
                                        if (key && strlen(key) && s->challenge) {
                                                int x;
                                if (!strcasecmp(authtype, "MD5")) {
                                        if (key && strlen(key) && s->challenge) {
                                                int x;
@@ -240,6 +332,8 @@ static int authenticate(struct mansession *s, struct message *m)
                s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
                s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
                ast_destroy(cfg);
                s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
                s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
                ast_destroy(cfg);
+               if (events)
+                       set_eventmask(s, events);
                return 0;
        }
        ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", inet_ntoa(s->sin.sin_addr), user);
                return 0;
        }
        ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", inet_ntoa(s->sin.sin_addr), user);
@@ -249,46 +343,67 @@ static int authenticate(struct mansession *s, struct message *m)
 
 static int action_ping(struct mansession *s, struct message *m)
 {
 
 static int action_ping(struct mansession *s, struct message *m)
 {
-       send_response(s, "Pong", NULL);
+       astman_send_response(s, m, "Pong", NULL);
+       return 0;
+}
+
+static int action_events(struct mansession *s, struct message *m)
+{
+       char *mask = astman_get_header(m, "EventMask");
+       int res;
+
+       res = set_eventmask(s, mask);
+       if (res > 0)
+               astman_send_response(s, m, "Events On", NULL);
+       else if (res == 0)
+               astman_send_response(s, m, "Events Off", NULL);
+       else
+               astman_send_response(s, m, "EventMask parse error", NULL);
        return 0;
 }
 
 static int action_logoff(struct mansession *s, struct message *m)
 {
        return 0;
 }
 
 static int action_logoff(struct mansession *s, struct message *m)
 {
-       send_response(s, "Goodbye", "Thanks for all the fish.");
+       astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
        return -1;
 }
 
 static int action_hangup(struct mansession *s, struct message *m)
 {
        struct ast_channel *c = NULL;
        return -1;
 }
 
 static int action_hangup(struct mansession *s, struct message *m)
 {
        struct ast_channel *c = NULL;
-       char *name = get_header(m, "Channel");
+       char *name = astman_get_header(m, "Channel");
        if (!strlen(name)) {
        if (!strlen(name)) {
-               send_error(s, "No channel specified");
+               astman_send_error(s, m, "No channel specified");
                return 0;
        }
                return 0;
        }
-       c = ast_channel_walk(NULL);
+       c = ast_channel_walk_locked(NULL);
        while(c) {
                if (!strcasecmp(c->name, name)) {
                        break;
                }
        while(c) {
                if (!strcasecmp(c->name, name)) {
                        break;
                }
-               c = ast_channel_walk(c);
+               ast_mutex_unlock(&c->lock);
+               c = ast_channel_walk_locked(c);
        }
        if (!c) {
        }
        if (!c) {
-               send_error(s, "No such channel");
+               astman_send_error(s, m, "No such channel");
                return 0;
        }
        ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
                return 0;
        }
        ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
-       send_ack(s, "Channel Hungup");
+       ast_mutex_unlock(&c->lock);
+       astman_send_ack(s, m, "Channel Hungup");
        return 0;
 }
 
 static int action_status(struct mansession *s, struct message *m)
 {
        return 0;
 }
 
 static int action_status(struct mansession *s, struct message *m)
 {
+       char *id = astman_get_header(m,"ActionID");
+       char idText[256] = "";
        struct ast_channel *c;
        char bridge[256];
        struct ast_channel *c;
        char bridge[256];
-       send_ack(s, "Channel status will follow");
-       c = ast_channel_walk(NULL);
+       astman_send_ack(s, m, "Channel status will follow");
+       c = ast_channel_walk_locked(NULL);
+        if (id && strlen(id))
+                snprintf(idText,256,"ActionID: %s\r\n",id);
        while(c) {
                if (c->bridge)
                        snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
        while(c) {
                if (c->bridge)
                        snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
@@ -304,10 +419,12 @@ static int action_status(struct mansession *s, struct message *m)
                        "Extension: %s\r\n"
                        "Priority: %d\r\n"
                        "%s"
                        "Extension: %s\r\n"
                        "Priority: %d\r\n"
                        "%s"
+                       "Uniqueid: %s\r\n"
+                       "%s"
                        "\r\n",
                        c->name, c->callerid ? c->callerid : "<unknown>", 
                        ast_state2str(c->_state), c->context,
                        "\r\n",
                        c->name, c->callerid ? c->callerid : "<unknown>", 
                        ast_state2str(c->_state), c->context,
-                       c->exten, c->priority, bridge);
+                       c->exten, c->priority, bridge, c->uniqueid, idText);
                } else {
                        ast_cli(s->fd,
                        "Event: Status\r\n"
                } else {
                        ast_cli(s->fd,
                        "Event: Status\r\n"
@@ -315,114 +432,295 @@ static int action_status(struct mansession *s, struct message *m)
                        "CallerID: %s\r\n"
                        "State: %s\r\n"
                        "%s"
                        "CallerID: %s\r\n"
                        "State: %s\r\n"
                        "%s"
+                       "Uniqueid: %s\r\n"
+                       "%s"
                        "\r\n",
                        c->name, c->callerid ? c->callerid : "<unknown>", 
                        "\r\n",
                        c->name, c->callerid ? c->callerid : "<unknown>", 
-                       ast_state2str(c->_state), bridge);
+                       ast_state2str(c->_state), bridge, c->uniqueid, idText);
                }
                }
-               c = ast_channel_walk(c);
+               ast_mutex_unlock(&c->lock);
+               c = ast_channel_walk_locked(c);
        }
        }
+       ast_cli(s->fd,
+       "Event: StatusComplete\r\n"
+       "%s"
+       "\r\n",idText);
        return 0;
 }
 
 static int action_redirect(struct mansession *s, struct message *m)
 {
        return 0;
 }
 
 static int action_redirect(struct mansession *s, struct message *m)
 {
-       char *name = get_header(m, "Channel");
-       char *name2 = get_header(m, "ExtraChannel");
-       char *exten = get_header(m, "Exten");
-       char *context = get_header(m, "Context");
-       char *priority = get_header(m, "Priority");
+       char *name = astman_get_header(m, "Channel");
+       char *name2 = astman_get_header(m, "ExtraChannel");
+       char *exten = astman_get_header(m, "Exten");
+       char *context = astman_get_header(m, "Context");
+       char *priority = astman_get_header(m, "Priority");
+       struct ast_channel *chan, *chan2 = NULL;
        int pi = 0;
        int res;
        if (!name || !strlen(name)) {
        int pi = 0;
        int res;
        if (!name || !strlen(name)) {
-               send_error(s, "Channel not specified");
+               astman_send_error(s, m, "Channel not specified");
                return 0;
        }
        if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
                return 0;
        }
        if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
-               send_error(s, "Invalid priority\n");
+               astman_send_error(s, m, "Invalid priority\n");
+               return 0;
+       }
+       chan = ast_get_channel_by_name_locked(name);
+       if (!chan) {
+               astman_send_error(s, m, "Channel not existant");
                return 0;
        }
                return 0;
        }
-       res = ast_async_goto_by_name(name, context, exten, pi);
+       if (strlen(name2))
+               chan2 = ast_get_channel_by_name_locked(name2);
+       res = ast_async_goto(chan, context, exten, pi);
        if (!res) {
                if (strlen(name2)) {
        if (!res) {
                if (strlen(name2)) {
-                       res = ast_async_goto_by_name(name2, context, exten, pi);
+                       if (chan2)
+                               res = ast_async_goto(chan2, context, exten, pi);
+                       else
+                               res = -1;
                        if (!res)
                        if (!res)
-                               send_ack(s, "Dual Redirect successful");
+                               astman_send_ack(s, m, "Dual Redirect successful");
                        else
                        else
-                               send_error(s, "Secondary redirect failed");
+                               astman_send_error(s, m, "Secondary redirect failed");
                } else
                } else
-                       send_ack(s, "Redirect successful");
+                       astman_send_ack(s, m, "Redirect successful");
        } else
        } else
-               send_error(s, "Redirect failed");
+               astman_send_error(s, m, "Redirect failed");
+       if (chan)
+               ast_mutex_unlock(&chan->lock);
+       if (chan2)
+               ast_mutex_unlock(&chan2->lock);
        return 0;
 }
 
 static int action_command(struct mansession *s, struct message *m)
 {
        return 0;
 }
 
 static int action_command(struct mansession *s, struct message *m)
 {
-       char *cmd = get_header(m, "Command");
-       ast_pthread_mutex_lock(&s->lock);
+       char *cmd = astman_get_header(m, "Command");
+       char *id = astman_get_header(m, "ActionID");
+       ast_mutex_lock(&s->lock);
        s->blocking = 1;
        s->blocking = 1;
-       ast_pthread_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->lock);
        ast_cli(s->fd, "Response: Follows\r\n");
        ast_cli(s->fd, "Response: Follows\r\n");
+       if (id && strlen(id))
+               ast_cli(s->fd, "ActionID: %s\r\n", id);
+       /* FIXME: Wedge a ActionID response in here, waiting for later changes */
        ast_cli_command(s->fd, cmd);
        ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
        ast_cli_command(s->fd, cmd);
        ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
-       ast_pthread_mutex_lock(&s->lock);
+       ast_mutex_lock(&s->lock);
        s->blocking = 0;
        s->blocking = 0;
-       ast_pthread_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->lock);
        return 0;
 }
 
        return 0;
 }
 
+static void *fast_originate(void *data)
+{
+       struct fast_originate_helper *in = data;
+       int res;
+       int reason = 0;
+       if (strlen(in->app)) {
+               res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, strlen(in->callerid) ? in->callerid : NULL, in->variable, in->account);
+       } else {
+               res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, strlen(in->callerid) ? in->callerid : NULL, in->variable, in->account);
+       }   
+       free(in);
+       return NULL;
+}
+
 static int action_originate(struct mansession *s, struct message *m)
 {
 static int action_originate(struct mansession *s, struct message *m)
 {
-       char *name = get_header(m, "Channel");
-       char *exten = get_header(m, "Exten");
-       char *context = get_header(m, "Context");
-       char *priority = get_header(m, "Priority");
-       char *timeout = get_header(m, "Timeout");
-       char *callerid = get_header(m, "CallerID");
+       char *name = astman_get_header(m, "Channel");
+       char *exten = astman_get_header(m, "Exten");
+       char *context = astman_get_header(m, "Context");
+       char *priority = astman_get_header(m, "Priority");
+       char *timeout = astman_get_header(m, "Timeout");
+       char *callerid = astman_get_header(m, "CallerID");
+       char *variable = astman_get_header(m, "Variable");
+       char *account = astman_get_header(m, "Account");
+       char *app = astman_get_header(m, "Application");
+       char *appdata = astman_get_header(m, "Data");
+       char *async = astman_get_header(m, "Async");
        char *tech, *data;
        int pi = 0;
        int res;
        int to = 30000;
        int reason = 0;
        char tmp[256];
        char *tech, *data;
        int pi = 0;
        int res;
        int to = 30000;
        int reason = 0;
        char tmp[256];
+       pthread_t th;
+       pthread_attr_t attr;
        if (!name) {
        if (!name) {
-               send_error(s, "Channel not specified");
+               astman_send_error(s, m, "Channel not specified");
                return 0;
        }
        if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
                return 0;
        }
        if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
-               send_error(s, "Invalid priority\n");
+               astman_send_error(s, m, "Invalid priority\n");
                return 0;
        }
        if (strlen(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
                return 0;
        }
        if (strlen(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
-               send_error(s, "Invalid timeout\n");
+               astman_send_error(s, m, "Invalid timeout\n");
                return 0;
        }
        strncpy(tmp, name, sizeof(tmp) - 1);
        tech = tmp;
        data = strchr(tmp, '/');
        if (!data) {
                return 0;
        }
        strncpy(tmp, name, sizeof(tmp) - 1);
        tech = tmp;
        data = strchr(tmp, '/');
        if (!data) {
-               send_error(s, "Invalid channel\n");
+               astman_send_error(s, m, "Invalid channel\n");
                return 0;
        }
        *data = '\0';
        data++;
                return 0;
        }
        *data = '\0';
        data++;
-       res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, strlen(callerid) ? callerid : NULL, NULL );
+       if (ast_true(async))
+       {
+               struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
+               if (!fast)
+               {
+                       res = -1;
+               }
+               else
+               {
+                       memset(fast, 0, sizeof(struct fast_originate_helper));
+                       strncpy(fast->tech, tech, sizeof(fast->tech) - 1);
+                       strncpy(fast->data, data, sizeof(fast->data) - 1);
+                       strncpy(fast->app, app, sizeof(fast->app) - 1);
+                       strncpy(fast->appdata, appdata, sizeof(fast->appdata) - 1);
+                       strncpy(fast->callerid, callerid, sizeof(fast->callerid) - 1);
+                       strncpy(fast->variable, variable, sizeof(fast->variable) - 1);
+                       strncpy(fast->account, account, sizeof(fast->account) - 1);
+                       strncpy(fast->context, context, sizeof(fast->context) - 1);
+                       strncpy(fast->exten, exten, sizeof(fast->exten) - 1);
+                       fast->timeout = to;
+                       fast->priority = pi;
+                       pthread_attr_init(&attr);
+                       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+                       if (pthread_create(&th, &attr, fast_originate, fast))
+                       {
+                               res = -1;
+                       }
+                       else
+                       {
+                               res = 0;
+                       }
+               }
+       } else if (strlen(app)) {
+               res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 0, strlen(callerid) ? callerid : NULL, variable, account);
+       } else {
+               if (exten && context && pi)
+                       res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, strlen(callerid) ? callerid : NULL, variable, account);
+               else {
+                       astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
+                       return 0;
+               }
+       }   
        if (!res)
        if (!res)
-               send_ack(s, "Originate successfully queued");
+               astman_send_ack(s, m, "Originate successfully queued");
        else
        else
-               send_error(s, "Originate failed");
+               astman_send_error(s, m, "Originate failed");
        return 0;
 }
 
 static int action_mailboxstatus(struct mansession *s, struct message *m)
 {
        return 0;
 }
 
 static int action_mailboxstatus(struct mansession *s, struct message *m)
 {
-       char *mailbox = get_header(m, "Mailbox");
+       char *mailbox = astman_get_header(m, "Mailbox");
+       char *id = astman_get_header(m,"ActionID");
+       char idText[256] = "";
        if (!mailbox || !strlen(mailbox)) {
        if (!mailbox || !strlen(mailbox)) {
-               send_error(s, "Mailbox not specified");
+               astman_send_error(s, m, "Mailbox not specified");
                return 0;
        }
                return 0;
        }
-       send_ack(s, "Mailbox status will follow");
-       manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting:%d\r\n", mailbox, ast_app_has_voicemail(mailbox));
+        if (id && strlen(id))
+                snprintf(idText,256,"ActionID: %s\r\n",id);
+       ast_cli(s->fd, "Response: Success\r\n"
+                                  "%s"
+                                  "Message: Mailbox Status\r\n"
+                                  "Mailbox: %s\r\n"
+                                  "Waiting: %d\r\n\r\n", idText, mailbox, ast_app_has_voicemail(mailbox));
+       return 0;
+}
+
+static int action_mailboxcount(struct mansession *s, struct message *m)
+{
+       char *mailbox = astman_get_header(m, "Mailbox");
+       char *id = astman_get_header(m,"ActionID");
+       char idText[256] = "";
+       int newmsgs = 0, oldmsgs = 0;
+       if (!mailbox || !strlen(mailbox)) {
+               astman_send_error(s, m, "Mailbox not specified");
+               return 0;
+       }
+       ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
+        if (id && strlen(id)) {
+                snprintf(idText,256,"ActionID: %s\r\n",id);
+        }
+       ast_cli(s->fd, "Response: Success\r\n"
+                                  "%s"
+                                  "Message: Mailbox Message Count\r\n"
+                                  "Mailbox: %s\r\n"
+                                  "NewMessages: %d\r\n"
+                                  "OldMessages: %d\r\n" 
+                                  "\r\n",
+                                   idText,mailbox, newmsgs, oldmsgs);
+       return 0;
+}
+
+static int action_extensionstate(struct mansession *s, struct message *m)
+{
+       char *exten = astman_get_header(m, "Exten");
+       char *context = astman_get_header(m, "Context");
+       char *id = astman_get_header(m,"ActionID");
+       char idText[256] = "";
+       char hint[256] = "";
+       int status;
+       if (!exten || !strlen(exten)) {
+               astman_send_error(s, m, "Extension not specified");
+               return 0;
+       }
+       if (!context || !strlen(context))
+               context = "default";
+       status = ast_extension_state(NULL, context, exten);
+       ast_get_hint(hint, sizeof(hint) - 1, NULL, context, exten);
+        if (id && strlen(id)) {
+                snprintf(idText,256,"ActionID: %s\r\n",id);
+        }
+       ast_cli(s->fd, "Response: Success\r\n"
+                                  "%s"
+                                  "Message: Extension Status\r\n"
+                                  "Exten: %s\r\n"
+                                  "Context: %s\r\n"
+                                  "Hint: %s\r\n"
+                                  "Status: %d\r\n\r\n",
+                                  idText,exten, context, hint, status);
+       return 0;
+}
+
+static int action_timeout(struct mansession *s, struct message *m)
+{
+       struct ast_channel *c = NULL;
+       char *name = astman_get_header(m, "Channel");
+       int timeout = atoi(astman_get_header(m, "Timeout"));
+       if (!strlen(name)) {
+               astman_send_error(s, m, "No channel specified");
+               return 0;
+       }
+       if (!timeout) {
+               astman_send_error(s, m, "No timeout specified");
+               return 0;
+       }
+       c = ast_channel_walk_locked(NULL);
+       while(c) {
+               if (!strcasecmp(c->name, name)) {
+                       break;
+               }
+               ast_mutex_unlock(&c->lock);
+               c = ast_channel_walk_locked(c);
+       }
+       if (!c) {
+               astman_send_error(s, m, "No such channel");
+               return 0;
+       }
+       ast_channel_setwhentohangup(c, timeout);
+       ast_mutex_unlock(&c->lock);
+       astman_send_ack(s, m, "Timeout Set");
        return 0;
 }
 
        return 0;
 }
 
@@ -430,43 +728,55 @@ static int process_message(struct mansession *s, struct message *m)
 {
        char action[80];
        struct manager_action *tmp = first_action;
 {
        char action[80];
        struct manager_action *tmp = first_action;
+       char *id = astman_get_header(m,"ActionID");
+       char idText[256] = "";
 
 
-       strncpy(action, get_header(m, "Action"), sizeof(action));
+       strncpy(action, astman_get_header(m, "Action"), sizeof(action));
+       ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
 
        if (!strlen(action)) {
 
        if (!strlen(action)) {
-               send_error(s, "Missing action in request");
+               astman_send_error(s, m, "Missing action in request");
                return 0;
        }
                return 0;
        }
+        if (id && strlen(id)) {
+                snprintf(idText,256,"ActionID: %s\r\n",id);
+        }
        if (!s->authenticated) {
                if (!strcasecmp(action, "Challenge")) {
                        char *authtype;
        if (!s->authenticated) {
                if (!strcasecmp(action, "Challenge")) {
                        char *authtype;
-                       authtype = get_header(m, "AuthType");
+                       authtype = astman_get_header(m, "AuthType");
                        if (!strcasecmp(authtype, "MD5")) {
                                if (!s->challenge || !strlen(s->challenge)) {
                        if (!strcasecmp(authtype, "MD5")) {
                                if (!s->challenge || !strlen(s->challenge)) {
-                                       ast_pthread_mutex_lock(&s->lock);
+                                       ast_mutex_lock(&s->lock);
                                        snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
                                        snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
-                                       ast_pthread_mutex_unlock(&s->lock);
+                                       ast_mutex_unlock(&s->lock);
                                }
                                }
-                               ast_cli(s->fd, "Challenge: %s\r\n\r\n", s->challenge);
+                               ast_cli(s->fd, "Response: Success\r\n"
+                                               "%s"
+                                               "Challenge: %s\r\n\r\n",
+                                               idText,s->challenge);
                                return 0;
                        } else {
                                return 0;
                        } else {
-                               send_error(s, "Must specify AuthType");
+                               astman_send_error(s, m, "Must specify AuthType");
                                return 0;
                        }
                } else if (!strcasecmp(action, "Login")) {
                        if (authenticate(s, m)) {
                                sleep(1);
                                return 0;
                        }
                } else if (!strcasecmp(action, "Login")) {
                        if (authenticate(s, m)) {
                                sleep(1);
-                               send_error(s, "Authentication failed");
+                               astman_send_error(s, m, "Authentication failed");
                                return -1;
                        } else {
                                s->authenticated = 1;
                                if (option_verbose > 1) 
                                        ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
                                ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
                                return -1;
                        } else {
                                s->authenticated = 1;
                                if (option_verbose > 1) 
                                        ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
                                ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
-                               send_ack(s, "Authentication accepted");
+                               astman_send_ack(s, m, "Authentication accepted");
                        }
                        }
-               } else 
-                       send_error(s, "Authentication Required");
+               } else if (!strcasecmp(action, "Logoff")) {
+                       astman_send_ack(s, m, "See ya");
+                       return -1;
+               } else
+                       astman_send_error(s, m, "Authentication Required");
        } else {
                while( tmp ) {          
                        if (!strcasecmp(action, tmp->action)) {
        } else {
                while( tmp ) {          
                        if (!strcasecmp(action, tmp->action)) {
@@ -474,13 +784,13 @@ static int process_message(struct mansession *s, struct message *m)
                                        if (tmp->func(s, m))
                                                return -1;
                                } else {
                                        if (tmp->func(s, m))
                                                return -1;
                                } else {
-                                       send_error(s, "Permission denied");
+                                       astman_send_error(s, m, "Permission denied");
                                }
                                return 0;
                        }
                        tmp = tmp->next;
                }
                                }
                                return 0;
                        }
                        tmp = tmp->next;
                }
-               send_error(s, "Invalid/unknown command");
+               astman_send_error(s, m, "Invalid/unknown command");
        }
        return 0;
 }
        }
        return 0;
 }
@@ -490,7 +800,7 @@ static int get_input(struct mansession *s, char *output)
        /* output must have at least sizeof(s->inbuf) space */
        int res;
        int x;
        /* output must have at least sizeof(s->inbuf) space */
        int res;
        int x;
-       fd_set fds;
+       struct pollfd fds[1];
        for (x=1;x<s->inlen;x++) {
                if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
                        /* Copy output data up to and including \r\n */
        for (x=1;x<s->inlen;x++) {
                if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
                        /* Copy output data up to and including \r\n */
@@ -507,15 +817,15 @@ static int get_input(struct mansession *s, char *output)
                ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
                s->inlen = 0;
        }
                ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
                s->inlen = 0;
        }
-       FD_ZERO(&fds);
-       FD_SET(s->fd, &fds);
-       res = select(s->fd + 1, &fds, NULL, NULL, NULL);
+       fds[0].fd = s->fd;
+       fds[0].events = POLLIN;
+       res = poll(fds, 1, -1);
        if (res < 0) {
                ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
        } else if (res > 0) {
        if (res < 0) {
                ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
        } else if (res > 0) {
-               ast_pthread_mutex_lock(&s->lock);
+               ast_mutex_lock(&s->lock);
                res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
                res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
-               ast_pthread_mutex_unlock(&s->lock);
+               ast_mutex_unlock(&s->lock);
                if (res < 1)
                        return -1;
        }
                if (res < 1)
                        return -1;
        }
@@ -530,9 +840,9 @@ static void *session_do(void *data)
        struct message m;
        int res;
        
        struct message m;
        int res;
        
-       ast_pthread_mutex_lock(&s->lock);
+       ast_mutex_lock(&s->lock);
        ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
        ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
-       ast_pthread_mutex_unlock(&s->lock);
+       ast_mutex_unlock(&s->lock);
        memset(&m, 0, sizeof(&m));
        for (;;) {
                res = get_input(s, m.headers[m.hdrcount]);
        memset(&m, 0, sizeof(&m));
        for (;;) {
                res = get_input(s, m.headers[m.hdrcount]);
@@ -569,17 +879,27 @@ static void *accept_thread(void *ignore)
        struct sockaddr_in sin;
        int sinlen;
        struct mansession *s;
        struct sockaddr_in sin;
        int sinlen;
        struct mansession *s;
+       struct protoent *p;
+       int arg = 1;
+       int flags;
        pthread_attr_t attr;
 
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        pthread_attr_t attr;
 
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
        for (;;) {
                sinlen = sizeof(sin);
        for (;;) {
                sinlen = sizeof(sin);
-               as = accept(asock, &sin, &sinlen);
+               as = accept(asock, (struct sockaddr *)&sin, &sinlen);
                if (as < 0) {
                        ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
                        continue;
                }
                if (as < 0) {
                        ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
                        continue;
                }
+               p = getprotobyname("tcp");
+               if( p ) {
+                       if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
+                               ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
+                       }
+               }
                s = malloc(sizeof(struct mansession));
                if (!s) {
                        ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
                s = malloc(sizeof(struct mansession));
                if (!s) {
                        ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
@@ -587,12 +907,19 @@ static void *accept_thread(void *ignore)
                } 
                memset(s, 0, sizeof(struct mansession));
                memcpy(&s->sin, &sin, sizeof(sin));
                } 
                memset(s, 0, sizeof(struct mansession));
                memcpy(&s->sin, &sin, sizeof(sin));
-               ast_pthread_mutex_init(&s->lock);
+
+               if(! block_sockets) {
+                       /* For safety, make sure socket is non-blocking */
+                       flags = fcntl(as, F_GETFL);
+                       fcntl(as, F_SETFL, flags | O_NONBLOCK);
+               }
+               ast_mutex_init(&s->lock);
                s->fd = as;
                s->fd = as;
-               ast_pthread_mutex_lock(&sessionlock);
+               s->send_events = 1;
+               ast_mutex_lock(&sessionlock);
                s->next = sessions;
                sessions = s;
                s->next = sessions;
                sessions = s;
-               ast_pthread_mutex_unlock(&sessionlock);
+               ast_mutex_unlock(&sessionlock);
                if (pthread_create(&t, &attr, session_do, s))
                        destroy_session(s);
        }
                if (pthread_create(&t, &attr, session_do, s))
                        destroy_session(s);
        }
@@ -606,44 +933,51 @@ int manager_event(int category, char *event, char *fmt, ...)
        char tmp[4096];
        va_list ap;
 
        char tmp[4096];
        va_list ap;
 
-       ast_pthread_mutex_lock(&sessionlock);
+       ast_mutex_lock(&sessionlock);
        s = sessions;
        while(s) {
        s = sessions;
        while(s) {
-               if ((s->readperm & category) == category) {
-                       ast_pthread_mutex_lock(&s->lock);
+               if (((s->readperm & category) == category) && s->send_events) {
+                       ast_mutex_lock(&s->lock);
                        if (!s->blocking) {
                                ast_cli(s->fd, "Event: %s\r\n", event);
                                va_start(ap, fmt);
                                vsnprintf(tmp, sizeof(tmp), fmt, ap);
                                va_end(ap);
                        if (!s->blocking) {
                                ast_cli(s->fd, "Event: %s\r\n", event);
                                va_start(ap, fmt);
                                vsnprintf(tmp, sizeof(tmp), fmt, ap);
                                va_end(ap);
-                               write(s->fd, tmp, strlen(tmp));
+                               ast_carefulwrite(s->fd,tmp,strlen(tmp),100);
                                ast_cli(s->fd, "\r\n");
                        }
                                ast_cli(s->fd, "\r\n");
                        }
-                       ast_pthread_mutex_unlock(&s->lock);
+                       ast_mutex_unlock(&s->lock);
                }
                s = s->next;
        }
                }
                s = s->next;
        }
-       ast_pthread_mutex_unlock(&sessionlock);
+       ast_mutex_unlock(&sessionlock);
        return 0;
 }
 
 int ast_manager_unregister( char *action ) {
        struct manager_action *cur = first_action, *prev = first_action;
 
        return 0;
 }
 
 int ast_manager_unregister( char *action ) {
        struct manager_action *cur = first_action, *prev = first_action;
 
-       ast_pthread_mutex_lock(&actionlock);
+       ast_mutex_lock(&actionlock);
        while( cur ) {          
                if (!strcasecmp(action, cur->action)) {
                        prev->next = cur->next;
                        free(cur);
                        if (option_verbose > 1) 
                                ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
        while( cur ) {          
                if (!strcasecmp(action, cur->action)) {
                        prev->next = cur->next;
                        free(cur);
                        if (option_verbose > 1) 
                                ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
-                       ast_pthread_mutex_unlock(&actionlock);
+                       ast_mutex_unlock(&actionlock);
                        return 0;
                }
                prev = cur;
                cur = cur->next;
        }
                        return 0;
                }
                prev = cur;
                cur = cur->next;
        }
-       ast_pthread_mutex_unlock(&actionlock);
+       ast_mutex_unlock(&actionlock);
+       return 0;
+}
+
+static int manager_state_cb(char *context, char *exten, int state, void *data)
+{
+       /* Notify managers of change */
+       manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
        return 0;
 }
 
        return 0;
 }
 
@@ -652,15 +986,20 @@ int ast_manager_register( char *action, int auth,
 {
        struct manager_action *cur = first_action, *prev = NULL;
 
 {
        struct manager_action *cur = first_action, *prev = NULL;
 
-       ast_pthread_mutex_lock(&actionlock);
+       ast_mutex_lock(&actionlock);
        while(cur) { /* Walk the list of actions */
        while(cur) { /* Walk the list of actions */
+               if (!strcasecmp(cur->action, action)) {
+                       ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", action);
+                       ast_mutex_unlock(&actionlock);
+                       return -1;
+               }
                prev = cur; 
                cur = cur->next;
        }
        cur = malloc( sizeof(struct manager_action) );
        if( !cur ) {
                ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
                prev = cur; 
                cur = cur->next;
        }
        cur = malloc( sizeof(struct manager_action) );
        if( !cur ) {
                ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
-               ast_pthread_mutex_unlock(&actionlock);
+               ast_mutex_unlock(&actionlock);
                return -1;
        }
        strncpy( cur->action, action, 255 );
                return -1;
        }
        strncpy( cur->action, action, 255 );
@@ -674,7 +1013,7 @@ int ast_manager_register( char *action, int auth,
 
        if (option_verbose > 1) 
                ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", action);
 
        if (option_verbose > 1) 
                ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", action);
-       ast_pthread_mutex_unlock(&actionlock);
+       ast_mutex_unlock(&actionlock);
        return 0;
 }
 
        return 0;
 }
 
@@ -690,6 +1029,7 @@ int init_manager(void)
        if (!registered) {
                /* Register default actions */
                ast_manager_register( "Ping", 0, action_ping, "Ping" );
        if (!registered) {
                /* Register default actions */
                ast_manager_register( "Ping", 0, action_ping, "Ping" );
+               ast_manager_register( "Events", 0, action_events, "Contol Event Flow" );
                ast_manager_register( "Logoff", 0, action_logoff, "Logoff Manager" );
                ast_manager_register( "Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel" );
                ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
                ast_manager_register( "Logoff", 0, action_logoff, "Logoff Manager" );
                ast_manager_register( "Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel" );
                ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
@@ -697,9 +1037,13 @@ int init_manager(void)
                ast_manager_register( "Originate", EVENT_FLAG_CALL, action_originate, "Originate Call" );
                ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" );
                ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
                ast_manager_register( "Originate", EVENT_FLAG_CALL, action_originate, "Originate Call" );
                ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" );
                ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
+               ast_manager_register( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status" );
+               ast_manager_register( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout" );
+               ast_manager_register( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count" );
 
                ast_cli_register(&show_mancmds_cli);
                ast_cli_register(&show_manconn_cli);
 
                ast_cli_register(&show_mancmds_cli);
                ast_cli_register(&show_manconn_cli);
+               ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
                registered = 1;
        }
        portno = DEFAULT_MANAGER_PORT;
                registered = 1;
        }
        portno = DEFAULT_MANAGER_PORT;
@@ -713,11 +1057,21 @@ int init_manager(void)
        if (val)
                enabled = ast_true(val);
 
        if (val)
                enabled = ast_true(val);
 
-       if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
+       val = ast_variable_retrieve(cfg, "general", "block-sockets");
+       if(val)
+               block_sockets = ast_true(val);
+
+       if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
+               if (sscanf(val, "%d", &portno) != 1) {
+                       ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
+                       portno = DEFAULT_MANAGER_PORT;
+               }
+       } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
                if (sscanf(val, "%d", &portno) != 1) {
                        ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
                        portno = DEFAULT_MANAGER_PORT;
                }
                if (sscanf(val, "%d", &portno) != 1) {
                        ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
                        portno = DEFAULT_MANAGER_PORT;
                }
+               ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated.  Please use 'port=%s' instead.\n", val);
        }
        
        ba.sin_family = AF_INET;
        }
        
        ba.sin_family = AF_INET;
@@ -730,7 +1084,7 @@ int init_manager(void)
                        memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
                }
        }
                        memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
                }
        }
-
+       
        if ((asock > -1) && ((portno != oldportno) || !enabled)) {
 #if 0
                /* Can't be done yet */
        if ((asock > -1) && ((portno != oldportno) || !enabled)) {
 #if 0
                /* Can't be done yet */
@@ -740,9 +1094,12 @@ int init_manager(void)
                ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
 #endif
        }
                ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
 #endif
        }
+       ast_destroy(cfg);
+       
        /* If not enabled, do nothing */
        /* If not enabled, do nothing */
-       if (!enabled)
+       if (!enabled) {
                return 0;
                return 0;
+       }
        if (asock < 0) {
                asock = socket(AF_INET, SOCK_STREAM, 0);
                if (asock < 0) {
        if (asock < 0) {
                asock = socket(AF_INET, SOCK_STREAM, 0);
                if (asock < 0) {
@@ -750,7 +1107,7 @@ int init_manager(void)
                        return -1;
                }
                setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
                        return -1;
                }
                setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
-               if (bind(asock, &ba, sizeof(ba))) {
+               if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
                        ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
                        close(asock);
                        asock = -1;
                        ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
                        close(asock);
                        asock = -1;
@@ -766,12 +1123,11 @@ int init_manager(void)
                        ast_verbose("Asterisk Management interface listening on port %d\n", portno);
                pthread_create(&t, NULL, accept_thread, NULL);
        }
                        ast_verbose("Asterisk Management interface listening on port %d\n", portno);
                pthread_create(&t, NULL, accept_thread, NULL);
        }
-       ast_destroy(cfg);
        return 0;
 }
 
 int reload_manager(void)
 {
        return 0;
 }
 
 int reload_manager(void)
 {
-       manager_event(EVENT_FLAG_SYSTEM, "Reload", NULL);
+       manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
        return init_manager();
 }
        return init_manager();
 }