2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief The Asterisk Management Interface - AMI
23 * \author Mark Spencer <markster@digium.com>
25 * Channel Management and more
30 /*! \addtogroup Group_AMI AMI functions
39 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <arpa/inet.h>
51 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
53 #include "asterisk/channel.h"
54 #include "asterisk/file.h"
55 #include "asterisk/manager.h"
56 #include "asterisk/config.h"
57 #include "asterisk/callerid.h"
58 #include "asterisk/lock.h"
59 #include "asterisk/logger.h"
60 #include "asterisk/options.h"
61 #include "asterisk/cli.h"
62 #include "asterisk/app.h"
63 #include "asterisk/pbx.h"
64 #include "asterisk/md5.h"
65 #include "asterisk/acl.h"
66 #include "asterisk/utils.h"
68 struct fast_originate_helper {
80 struct ast_variable *vars;
83 static int enabled = 0;
84 static int portno = DEFAULT_MANAGER_PORT;
85 static int asock = -1;
86 static int displayconnects = 1;
87 static int timestampevents = 0;
90 AST_MUTEX_DEFINE_STATIC(sessionlock);
91 static int block_sockets = 0;
93 static struct permalias {
97 { EVENT_FLAG_SYSTEM, "system" },
98 { EVENT_FLAG_CALL, "call" },
99 { EVENT_FLAG_LOG, "log" },
100 { EVENT_FLAG_VERBOSE, "verbose" },
101 { EVENT_FLAG_COMMAND, "command" },
102 { EVENT_FLAG_AGENT, "agent" },
103 { EVENT_FLAG_USER, "user" },
108 static struct mansession *sessions = NULL;
109 static struct manager_action *first_action = NULL;
110 AST_MUTEX_DEFINE_STATIC(actionlock);
112 /*! If you are calling ast_carefulwrite, it is assumed that you are calling
113 it on a file descriptor that _DOES_ have NONBLOCK set. This way,
114 there is only one system call made to do a write, unless we actually
115 have a need to wait. This way, we get better performance. */
116 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
118 /* Try to write string, but wait no more than ms milliseconds
121 struct pollfd fds[1];
123 res = write(fd, s, len);
124 if ((res < 0) && (errno != EAGAIN)) {
127 if (res < 0) res = 0;
133 fds[0].events = POLLOUT;
134 /* Wait until writable again */
135 res = poll(fds, 1, timeoutms);
143 /*! authority_to_str: Convert authority code to string with serveral options */
144 static char *authority_to_str(int authority, char *res, int reslen)
146 int running_total = 0, i;
147 memset(res, 0, reslen);
148 for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
149 if (authority & perms[i].num) {
151 strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
154 strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
155 running_total += strlen(perms[i].label);
158 if (ast_strlen_zero(res)) {
159 ast_copy_string(res, "<none>", reslen);
164 static char *complete_show_mancmd(const char *line, const char *word, int pos, int state)
166 struct manager_action *cur = first_action;
169 ast_mutex_lock(&actionlock);
170 while (cur) { /* Walk the list of actions */
171 if (!strncasecmp(word, cur->action, strlen(word))) {
172 if (++which > state) {
173 char *ret = strdup(cur->action);
174 ast_mutex_unlock(&actionlock);
180 ast_mutex_unlock(&actionlock);
184 static int handle_showmancmd(int fd, int argc, char *argv[])
186 struct manager_action *cur = first_action;
191 return RESULT_SHOWUSAGE;
192 ast_mutex_lock(&actionlock);
193 while (cur) { /* Walk the list of actions */
194 for (num = 3; num < argc; num++) {
195 if (!strcasecmp(cur->action, argv[num])) {
196 ast_cli(fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n", cur->action, cur->synopsis, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->description ? cur->description : "");
202 ast_mutex_unlock(&actionlock);
203 return RESULT_SUCCESS;
206 /*! \brief handle_showmancmds: CLI command */
207 /* Should change to "manager show commands" */
208 static int handle_showmancmds(int fd, int argc, char *argv[])
210 struct manager_action *cur = first_action;
212 char *format = " %-15.15s %-15.15s %-55.55s\n";
214 ast_mutex_lock(&actionlock);
215 ast_cli(fd, format, "Action", "Privilege", "Synopsis");
216 ast_cli(fd, format, "------", "---------", "--------");
217 while (cur) { /* Walk the list of actions */
218 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
222 ast_mutex_unlock(&actionlock);
223 return RESULT_SUCCESS;
226 /*! \brief handle_showmanconn: CLI command show manager connected */
227 /* Should change to "manager show connected" */
228 static int handle_showmanconn(int fd, int argc, char *argv[])
230 struct mansession *s;
231 char iabuf[INET_ADDRSTRLEN];
232 char *format = " %-15.15s %-15.15s\n";
233 ast_mutex_lock(&sessionlock);
235 ast_cli(fd, format, "Username", "IP Address");
237 ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
241 ast_mutex_unlock(&sessionlock);
242 return RESULT_SUCCESS;
245 static char showmancmd_help[] =
246 "Usage: show manager command <actionname>\n"
247 " Shows the detailed description for a specific Asterisk manager interface command.\n";
249 static char showmancmds_help[] =
250 "Usage: show manager commands\n"
251 " Prints a listing of all the available Asterisk manager interface commands.\n";
253 static char showmanconn_help[] =
254 "Usage: show manager connected\n"
255 " Prints a listing of the users that are currently connected to the\n"
256 "Asterisk manager interface.\n";
258 static struct ast_cli_entry show_mancmd_cli =
259 { { "show", "manager", "command", NULL },
260 handle_showmancmd, "Show a manager interface command", showmancmd_help, complete_show_mancmd };
262 static struct ast_cli_entry show_mancmds_cli =
263 { { "show", "manager", "commands", NULL },
264 handle_showmancmds, "List manager interface commands", showmancmds_help };
266 static struct ast_cli_entry show_manconn_cli =
267 { { "show", "manager", "connected", NULL },
268 handle_showmanconn, "Show connected manager interface users", showmanconn_help };
270 static void free_session(struct mansession *s)
272 struct eventqent *eqe;
275 ast_mutex_destroy(&s->__lock);
278 s->eventq = s->eventq->next;
284 static void destroy_session(struct mansession *s)
286 struct mansession *cur, *prev = NULL;
287 ast_mutex_lock(&sessionlock);
297 prev->next = cur->next;
299 sessions = cur->next;
302 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
303 ast_mutex_unlock(&sessionlock);
307 char *astman_get_header(struct message *m, char *var)
311 snprintf(cmp, sizeof(cmp), "%s: ", var);
312 for (x=0;x<m->hdrcount;x++)
313 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
314 return m->headers[x] + strlen(cmp);
318 struct ast_variable *astman_get_variables(struct message *m)
321 struct ast_variable *head = NULL, *cur;
325 AST_DECLARE_APP_ARGS(args,
326 AST_APP_ARG(vars)[32];
329 varlen = strlen("Variable: ");
331 for (x = 0; x < m->hdrcount; x++) {
332 if (strncasecmp("Variable: ", m->headers[x], varlen))
335 if (!(parse = ast_strdupa(m->headers[x] + varlen)))
338 AST_STANDARD_APP_ARGS(args, parse);
340 for (y = 0; y < args.argc; y++) {
343 var = val = ast_strdupa(args.vars[y]);
345 if (!val || ast_strlen_zero(var))
347 cur = ast_variable_new(var, val);
361 Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
362 hold the session lock _or_ be running in an action callback (in which case s->busy will
363 be non-zero). In either of these cases, there is no need to lock-protect the session's
364 fd, since no other output will be sent (events will be queued), and no input will
365 be read until either the current action finishes or get_input() obtains the session
368 void astman_send_error(struct mansession *s, struct message *m, char *error)
370 char *id = astman_get_header(m,"ActionID");
372 ast_cli(s->fd, "Response: Error\r\n");
373 if (!ast_strlen_zero(id))
374 ast_cli(s->fd, "ActionID: %s\r\n",id);
375 ast_cli(s->fd, "Message: %s\r\n\r\n", error);
378 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
380 char *id = astman_get_header(m,"ActionID");
382 ast_cli(s->fd, "Response: %s\r\n", resp);
383 if (!ast_strlen_zero(id))
384 ast_cli(s->fd, "ActionID: %s\r\n",id);
386 ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
388 ast_cli(s->fd, "\r\n");
391 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
393 astman_send_response(s, m, "Success", msg);
396 /*! Tells you if smallstr exists inside bigstr
397 which is delim by delim and uses no buf or stringsep
398 ast_instring("this|that|more","this",',') == 1;
400 feel free to move this to app.c -anthm */
401 static int ast_instring(char *bigstr, char *smallstr, char delim)
403 char *val = bigstr, *next;
406 if ((next = strchr(val, delim))) {
407 if (!strncmp(val, smallstr, (next - val)))
412 return !strcmp(smallstr, val);
414 } while (*(val = (next + 1)));
419 static int get_perm(char *instr)
426 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
427 if (ast_instring(instr, perms[x].label, ','))
433 static int ast_is_number(char *string)
440 for (x=0; x < strlen(string); x++) {
441 if (!(string[x] >= 48 && string[x] <= 57)) {
447 return ret ? atoi(string) : 0;
450 static int ast_strings_to_mask(char *string)
454 x = ast_is_number(string);
458 } else if (ast_strlen_zero(string)) {
460 } else if (ast_false(string)) {
462 } else if (ast_true(string)) {
464 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
468 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
469 if (ast_instring(string, perms[x].label, ','))
478 Rather than braindead on,off this now can also accept a specific int mask value
479 or a ',' delim list of mask strings (the same as manager.conf) -anthm
482 static int set_eventmask(struct mansession *s, char *eventmask)
484 int maskint = ast_strings_to_mask(eventmask);
486 ast_mutex_lock(&s->__lock);
488 s->send_events = maskint;
489 ast_mutex_unlock(&s->__lock);
494 static int authenticate(struct mansession *s, struct message *m)
496 struct ast_config *cfg;
497 char iabuf[INET_ADDRSTRLEN];
499 char *user = astman_get_header(m, "Username");
500 char *pass = astman_get_header(m, "Secret");
501 char *authtype = astman_get_header(m, "AuthType");
502 char *key = astman_get_header(m, "Key");
503 char *events = astman_get_header(m, "Events");
505 cfg = ast_config_load("manager.conf");
508 cat = ast_category_browse(cfg, NULL);
510 if (strcasecmp(cat, "general")) {
512 if (!strcasecmp(cat, user)) {
513 struct ast_variable *v;
514 struct ast_ha *ha = NULL;
515 char *password = NULL;
516 v = ast_variable_browse(cfg, cat);
518 if (!strcasecmp(v->name, "secret")) {
520 } else if (!strcasecmp(v->name, "permit") ||
521 !strcasecmp(v->name, "deny")) {
522 ha = ast_append_ha(v->name, v->value, ha);
523 } else if (!strcasecmp(v->name, "writetimeout")) {
524 int val = atoi(v->value);
527 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
529 s->writetimeout = val;
534 if (ha && !ast_apply_ha(ha, &(s->sin))) {
535 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
537 ast_config_destroy(cfg);
541 if (!strcasecmp(authtype, "MD5")) {
542 if (!ast_strlen_zero(key) && s->challenge) {
545 char md5key[256] = "";
546 struct MD5Context md5;
547 unsigned char digest[16];
549 MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
550 MD5Update(&md5, (unsigned char *) password, strlen(password));
551 MD5Final(digest, &md5);
553 len += sprintf(md5key + len, "%2.2x", digest[x]);
554 if (!strcmp(md5key, key))
557 ast_config_destroy(cfg);
561 } else if (password && !strcasecmp(password, pass)) {
564 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
565 ast_config_destroy(cfg);
570 cat = ast_category_browse(cfg, cat);
573 ast_copy_string(s->username, cat, sizeof(s->username));
574 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
575 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
576 ast_config_destroy(cfg);
578 set_eventmask(s, events);
581 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
582 ast_config_destroy(cfg);
586 /*! \brief PING: Manager PING */
587 static char mandescr_ping[] =
588 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the "
589 " manager connection open.\n"
592 static int action_ping(struct mansession *s, struct message *m)
594 astman_send_response(s, m, "Pong", NULL);
598 static char mandescr_listcommands[] =
599 "Description: Returns the action name and synopsis for every\n"
600 " action that is available to the user\n"
603 static int action_listcommands(struct mansession *s, struct message *m)
605 struct manager_action *cur = first_action;
606 char idText[256] = "";
608 char *id = astman_get_header(m,"ActionID");
610 if (!ast_strlen_zero(id))
611 snprintf(idText,256,"ActionID: %s\r\n",id);
612 ast_cli(s->fd, "Response: Success\r\n%s", idText);
613 ast_mutex_lock(&actionlock);
614 while (cur) { /* Walk the list of actions */
615 if ((s->writeperm & cur->authority) == cur->authority)
616 ast_cli(s->fd, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)) );
619 ast_mutex_unlock(&actionlock);
620 ast_cli(s->fd, "\r\n");
625 static char mandescr_events[] =
626 "Description: Enable/Disable sending of events to this manager\n"
629 " EventMask: 'on' if all events should be sent,\n"
630 " 'off' if no events should be sent,\n"
631 " 'system,call,log' to select which flags events should have to be sent.\n";
633 static int action_events(struct mansession *s, struct message *m)
635 char *mask = astman_get_header(m, "EventMask");
638 res = set_eventmask(s, mask);
640 astman_send_response(s, m, "Events On", NULL);
642 astman_send_response(s, m, "Events Off", NULL);
647 static char mandescr_logoff[] =
648 "Description: Logoff this manager session\n"
651 static int action_logoff(struct mansession *s, struct message *m)
653 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
657 static char mandescr_hangup[] =
658 "Description: Hangup a channel\n"
660 " Channel: The channel name to be hungup\n";
662 static int action_hangup(struct mansession *s, struct message *m)
664 struct ast_channel *c = NULL;
665 char *name = astman_get_header(m, "Channel");
666 if (ast_strlen_zero(name)) {
667 astman_send_error(s, m, "No channel specified");
670 c = ast_get_channel_by_name_locked(name);
672 astman_send_error(s, m, "No such channel");
675 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
676 ast_mutex_unlock(&c->lock);
677 astman_send_ack(s, m, "Channel Hungup");
681 static char mandescr_setvar[] =
682 "Description: Set a global or local channel variable.\n"
683 "Variables: (Names marked with * are required)\n"
684 " Channel: Channel to set variable for\n"
685 " *Variable: Variable name\n"
688 static int action_setvar(struct mansession *s, struct message *m)
690 struct ast_channel *c = NULL;
691 char *name = astman_get_header(m, "Channel");
692 char *varname = astman_get_header(m, "Variable");
693 char *varval = astman_get_header(m, "Value");
695 if (ast_strlen_zero(varname)) {
696 astman_send_error(s, m, "No variable specified");
700 if (ast_strlen_zero(varval)) {
701 astman_send_error(s, m, "No value specified");
705 if (!ast_strlen_zero(name)) {
706 c = ast_get_channel_by_name_locked(name);
708 astman_send_error(s, m, "No such channel");
713 pbx_builtin_setvar_helper(c, varname, varval);
716 ast_mutex_unlock(&c->lock);
718 astman_send_ack(s, m, "Variable Set");
723 static char mandescr_getvar[] =
724 "Description: Get the value of a global or local channel variable.\n"
725 "Variables: (Names marked with * are required)\n"
726 " Channel: Channel to read variable from\n"
727 " *Variable: Variable name\n"
728 " ActionID: Optional Action id for message matching.\n";
730 static int action_getvar(struct mansession *s, struct message *m)
732 struct ast_channel *c = NULL;
733 char *name = astman_get_header(m, "Channel");
734 char *varname = astman_get_header(m, "Variable");
735 char *id = astman_get_header(m,"ActionID");
737 char workspace[1024];
739 if (ast_strlen_zero(varname)) {
740 astman_send_error(s, m, "No variable specified");
744 if (!ast_strlen_zero(name)) {
745 c = ast_get_channel_by_name_locked(name);
747 astman_send_error(s, m, "No such channel");
752 if (varname[strlen(varname) - 1] == ')') {
753 varval = ast_func_read(c, varname, workspace, sizeof(workspace));
755 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
759 ast_mutex_unlock(&c->lock);
760 ast_cli(s->fd, "Response: Success\r\n"
761 "Variable: %s\r\nValue: %s\r\n", varname, varval);
762 if (!ast_strlen_zero(id))
763 ast_cli(s->fd, "ActionID: %s\r\n",id);
764 ast_cli(s->fd, "\r\n");
770 /*! \brief action_status: Manager "status" command to show channels */
771 /* Needs documentation... */
772 static int action_status(struct mansession *s, struct message *m)
774 char *id = astman_get_header(m,"ActionID");
775 char *name = astman_get_header(m,"Channel");
776 char idText[256] = "";
777 struct ast_channel *c;
779 struct timeval now = ast_tvnow();
780 long elapsed_seconds=0;
781 int all = ast_strlen_zero(name); /* set if we want all channels */
783 astman_send_ack(s, m, "Channel status will follow");
784 if (!ast_strlen_zero(id))
785 snprintf(idText,256,"ActionID: %s\r\n",id);
787 c = ast_channel_walk_locked(NULL);
789 c = ast_get_channel_by_name_locked(name);
791 astman_send_error(s, m, "No such channel");
795 /* if we look by name, we break after the first iteration */
798 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
803 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
807 "Privilege: Call\r\n"
810 "CallerIDName: %s\r\n"
822 c->cid.cid_num ? c->cid.cid_num : "<unknown>",
823 c->cid.cid_name ? c->cid.cid_name : "<unknown>",
825 ast_state2str(c->_state), c->context,
826 c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
830 "Privilege: Call\r\n"
833 "CallerIDName: %s\r\n"
841 c->cid.cid_num ? c->cid.cid_num : "<unknown>",
842 c->cid.cid_name ? c->cid.cid_name : "<unknown>",
844 ast_state2str(c->_state), bridge, c->uniqueid, idText);
846 ast_mutex_unlock(&c->lock);
849 c = ast_channel_walk_locked(c);
852 "Event: StatusComplete\r\n"
858 static char mandescr_redirect[] =
859 "Description: Redirect (transfer) a call.\n"
860 "Variables: (Names marked with * are required)\n"
861 " *Channel: Channel to redirect\n"
862 " ExtraChannel: Second call leg to transfer (optional)\n"
863 " *Exten: Extension to transfer to\n"
864 " *Context: Context to transfer to\n"
865 " *Priority: Priority to transfer to\n"
866 " ActionID: Optional Action id for message matching.\n";
868 /*! \brief action_redirect: The redirect manager command */
869 static int action_redirect(struct mansession *s, struct message *m)
871 char *name = astman_get_header(m, "Channel");
872 char *name2 = astman_get_header(m, "ExtraChannel");
873 char *exten = astman_get_header(m, "Exten");
874 char *context = astman_get_header(m, "Context");
875 char *priority = astman_get_header(m, "Priority");
876 struct ast_channel *chan, *chan2 = NULL;
880 if (ast_strlen_zero(name)) {
881 astman_send_error(s, m, "Channel not specified");
884 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
885 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
886 astman_send_error(s, m, "Invalid priority\n");
890 chan = ast_get_channel_by_name_locked(name);
893 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
894 astman_send_error(s, m, buf);
897 if (!ast_strlen_zero(name2))
898 chan2 = ast_get_channel_by_name_locked(name2);
899 res = ast_async_goto(chan, context, exten, pi);
901 if (!ast_strlen_zero(name2)) {
903 res = ast_async_goto(chan2, context, exten, pi);
907 astman_send_ack(s, m, "Dual Redirect successful");
909 astman_send_error(s, m, "Secondary redirect failed");
911 astman_send_ack(s, m, "Redirect successful");
913 astman_send_error(s, m, "Redirect failed");
915 ast_mutex_unlock(&chan->lock);
917 ast_mutex_unlock(&chan2->lock);
921 static char mandescr_command[] =
922 "Description: Run a CLI command.\n"
923 "Variables: (Names marked with * are required)\n"
924 " *Command: Asterisk CLI command to run\n"
925 " ActionID: Optional Action id for message matching.\n";
927 /*! \brief action_command: Manager command "command" - execute CLI command */
928 static int action_command(struct mansession *s, struct message *m)
930 char *cmd = astman_get_header(m, "Command");
931 char *id = astman_get_header(m, "ActionID");
932 ast_cli(s->fd, "Response: Follows\r\nPrivilege: Command\r\n");
933 if (!ast_strlen_zero(id))
934 ast_cli(s->fd, "ActionID: %s\r\n", id);
935 /* FIXME: Wedge a ActionID response in here, waiting for later changes */
936 ast_cli_command(s->fd, cmd);
937 ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
941 static void *fast_originate(void *data)
943 struct fast_originate_helper *in = data;
946 struct ast_channel *chan = NULL;
948 if (!ast_strlen_zero(in->app)) {
949 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1,
950 !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
951 !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
954 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
955 !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
956 !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
960 /* Tell the manager what happened with the channel */
961 manager_event(EVENT_FLAG_CALL,
962 res ? "OriginateSuccess" : "OriginateFailure",
970 "CallerIDName: %s\r\n",
971 in->idtext, in->tech, in->data, in->context, in->exten, reason,
972 chan ? chan->uniqueid : "<null>",
973 in->cid_num ? in->cid_num : "<unknown>",
974 in->cid_name ? in->cid_name : "<unknown>"
977 /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
979 ast_mutex_unlock(&chan->lock);
984 static char mandescr_originate[] =
985 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
986 " Application/Data\n"
987 "Variables: (Names marked with * are required)\n"
988 " *Channel: Channel name to call\n"
989 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
990 " Context: Context to use (requires 'Exten' and 'Priority')\n"
991 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
992 " Application: Application to use\n"
993 " Data: Data to use (requires 'Application')\n"
994 " Timeout: How long to wait for call to be answered (in ms)\n"
995 " CallerID: Caller ID to be set on the outgoing channel\n"
996 " Variable: Channel variable to set, multiple Variable: headers are allowed\n"
997 " Account: Account code\n"
998 " Async: Set to 'true' for fast origination\n";
1000 static int action_originate(struct mansession *s, struct message *m)
1002 char *name = astman_get_header(m, "Channel");
1003 char *exten = astman_get_header(m, "Exten");
1004 char *context = astman_get_header(m, "Context");
1005 char *priority = astman_get_header(m, "Priority");
1006 char *timeout = astman_get_header(m, "Timeout");
1007 char *callerid = astman_get_header(m, "CallerID");
1008 char *account = astman_get_header(m, "Account");
1009 char *app = astman_get_header(m, "Application");
1010 char *appdata = astman_get_header(m, "Data");
1011 char *async = astman_get_header(m, "Async");
1012 char *id = astman_get_header(m, "ActionID");
1013 struct ast_variable *vars = astman_get_variables(m);
1015 char *l=NULL, *n=NULL;
1024 pthread_attr_t attr;
1026 astman_send_error(s, m, "Channel not specified");
1029 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
1030 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
1031 astman_send_error(s, m, "Invalid priority\n");
1035 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
1036 astman_send_error(s, m, "Invalid timeout\n");
1039 ast_copy_string(tmp, name, sizeof(tmp));
1041 data = strchr(tmp, '/');
1043 astman_send_error(s, m, "Invalid channel\n");
1048 ast_copy_string(tmp2, callerid, sizeof(tmp2));
1049 ast_callerid_parse(tmp2, &n, &l);
1051 if (ast_strlen_zero(n))
1055 ast_shrink_phone_number(l);
1056 if (ast_strlen_zero(l))
1060 struct ast_variable *newvar;
1061 newvar = ast_variable_new("CDR(accountcode|r)", account);
1062 newvar->next = vars;
1065 if (ast_true(async)) {
1066 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
1070 memset(fast, 0, sizeof(struct fast_originate_helper));
1071 if (!ast_strlen_zero(id))
1072 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
1073 ast_copy_string(fast->tech, tech, sizeof(fast->tech));
1074 ast_copy_string(fast->data, data, sizeof(fast->data));
1075 ast_copy_string(fast->app, app, sizeof(fast->app));
1076 ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
1078 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
1080 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
1082 ast_copy_string(fast->context, context, sizeof(fast->context));
1083 ast_copy_string(fast->exten, exten, sizeof(fast->exten));
1085 fast->priority = pi;
1086 pthread_attr_init(&attr);
1087 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1088 if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
1094 } else if (!ast_strlen_zero(app)) {
1095 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, NULL);
1097 if (exten && context && pi)
1098 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, NULL);
1100 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
1105 astman_send_ack(s, m, "Originate successfully queued");
1107 astman_send_error(s, m, "Originate failed");
1111 /*! \brief Help text for manager command mailboxstatus
1113 static char mandescr_mailboxstatus[] =
1114 "Description: Checks a voicemail account for status.\n"
1115 "Variables: (Names marked with * are required)\n"
1116 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1117 " ActionID: Optional ActionID for message matching.\n"
1118 "Returns number of messages.\n"
1119 " Message: Mailbox Status\n"
1120 " Mailbox: <mailboxid>\n"
1121 " Waiting: <count>\n"
1124 static int action_mailboxstatus(struct mansession *s, struct message *m)
1126 char *mailbox = astman_get_header(m, "Mailbox");
1127 char *id = astman_get_header(m,"ActionID");
1128 char idText[256] = "";
1130 if (ast_strlen_zero(mailbox)) {
1131 astman_send_error(s, m, "Mailbox not specified");
1134 if (!ast_strlen_zero(id))
1135 snprintf(idText,256,"ActionID: %s\r\n",id);
1136 ret = ast_app_has_voicemail(mailbox, NULL);
1137 ast_cli(s->fd, "Response: Success\r\n"
1139 "Message: Mailbox Status\r\n"
1141 "Waiting: %d\r\n\r\n", idText, mailbox, ret);
1145 static char mandescr_mailboxcount[] =
1146 "Description: Checks a voicemail account for new messages.\n"
1147 "Variables: (Names marked with * are required)\n"
1148 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
1149 " ActionID: Optional ActionID for message matching.\n"
1150 "Returns number of new and old messages.\n"
1151 " Message: Mailbox Message Count\n"
1152 " Mailbox: <mailboxid>\n"
1153 " NewMessages: <count>\n"
1154 " OldMessages: <count>\n"
1156 static int action_mailboxcount(struct mansession *s, struct message *m)
1158 char *mailbox = astman_get_header(m, "Mailbox");
1159 char *id = astman_get_header(m,"ActionID");
1160 char idText[256] = "";
1161 int newmsgs = 0, oldmsgs = 0;
1162 if (ast_strlen_zero(mailbox)) {
1163 astman_send_error(s, m, "Mailbox not specified");
1166 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
1167 if (!ast_strlen_zero(id)) {
1168 snprintf(idText,256,"ActionID: %s\r\n",id);
1170 ast_cli(s->fd, "Response: Success\r\n"
1172 "Message: Mailbox Message Count\r\n"
1174 "NewMessages: %d\r\n"
1175 "OldMessages: %d\r\n"
1177 idText,mailbox, newmsgs, oldmsgs);
1181 static char mandescr_extensionstate[] =
1182 "Description: Report the extension state for given extension.\n"
1183 " If the extension has a hint, will use devicestate to check\n"
1184 " the status of the device connected to the extension.\n"
1185 "Variables: (Names marked with * are required)\n"
1186 " *Exten: Extension to check state on\n"
1187 " *Context: Context for extension\n"
1188 " ActionId: Optional ID for this transaction\n"
1189 "Will return an \"Extension Status\" message.\n"
1190 "The response will include the hint for the extension and the status.\n";
1192 static int action_extensionstate(struct mansession *s, struct message *m)
1194 char *exten = astman_get_header(m, "Exten");
1195 char *context = astman_get_header(m, "Context");
1196 char *id = astman_get_header(m,"ActionID");
1197 char idText[256] = "";
1198 char hint[256] = "";
1200 if (ast_strlen_zero(exten)) {
1201 astman_send_error(s, m, "Extension not specified");
1204 if (ast_strlen_zero(context))
1205 context = "default";
1206 status = ast_extension_state(NULL, context, exten);
1207 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
1208 if (!ast_strlen_zero(id)) {
1209 snprintf(idText,256,"ActionID: %s\r\n",id);
1211 ast_cli(s->fd, "Response: Success\r\n"
1213 "Message: Extension Status\r\n"
1217 "Status: %d\r\n\r\n",
1218 idText,exten, context, hint, status);
1222 static char mandescr_timeout[] =
1223 "Description: Hangup a channel after a certain time.\n"
1224 "Variables: (Names marked with * are required)\n"
1225 " *Channel: Channel name to hangup\n"
1226 " *Timeout: Maximum duration of the call (sec)\n"
1227 "Acknowledges set time with 'Timeout Set' message\n";
1229 static int action_timeout(struct mansession *s, struct message *m)
1231 struct ast_channel *c = NULL;
1232 char *name = astman_get_header(m, "Channel");
1233 int timeout = atoi(astman_get_header(m, "Timeout"));
1234 if (ast_strlen_zero(name)) {
1235 astman_send_error(s, m, "No channel specified");
1239 astman_send_error(s, m, "No timeout specified");
1242 c = ast_get_channel_by_name_locked(name);
1244 astman_send_error(s, m, "No such channel");
1247 ast_channel_setwhentohangup(c, timeout);
1248 ast_mutex_unlock(&c->lock);
1249 astman_send_ack(s, m, "Timeout Set");
1253 static int process_message(struct mansession *s, struct message *m)
1255 char action[80] = "";
1256 struct manager_action *tmp = first_action;
1257 char *id = astman_get_header(m,"ActionID");
1258 char idText[256] = "";
1259 char iabuf[INET_ADDRSTRLEN];
1261 ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
1262 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
1264 if (ast_strlen_zero(action)) {
1265 astman_send_error(s, m, "Missing action in request");
1268 if (!ast_strlen_zero(id)) {
1269 snprintf(idText,256,"ActionID: %s\r\n",id);
1271 if (!s->authenticated) {
1272 if (!strcasecmp(action, "Challenge")) {
1274 authtype = astman_get_header(m, "AuthType");
1275 if (!strcasecmp(authtype, "MD5")) {
1276 if (ast_strlen_zero(s->challenge))
1277 snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
1278 ast_mutex_lock(&s->__lock);
1279 ast_cli(s->fd, "Response: Success\r\n"
1281 "Challenge: %s\r\n\r\n",
1282 idText,s->challenge);
1283 ast_mutex_unlock(&s->__lock);
1286 astman_send_error(s, m, "Must specify AuthType");
1289 } else if (!strcasecmp(action, "Login")) {
1290 if (authenticate(s, m)) {
1292 astman_send_error(s, m, "Authentication failed");
1295 s->authenticated = 1;
1296 if (option_verbose > 1) {
1297 if ( displayconnects ) {
1298 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1301 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1302 astman_send_ack(s, m, "Authentication accepted");
1304 } else if (!strcasecmp(action, "Logoff")) {
1305 astman_send_ack(s, m, "See ya");
1308 astman_send_error(s, m, "Authentication Required");
1311 struct eventqent *eqe;
1312 ast_mutex_lock(&s->__lock);
1314 ast_mutex_unlock(&s->__lock);
1316 if (!strcasecmp(action, tmp->action)) {
1317 if ((s->writeperm & tmp->authority) == tmp->authority) {
1318 if (tmp->func(s, m))
1321 astman_send_error(s, m, "Permission denied");
1328 astman_send_error(s, m, "Invalid/unknown command");
1329 ast_mutex_lock(&s->__lock);
1332 if (ast_carefulwrite(s->fd, s->eventq->eventdata, strlen(s->eventq->eventdata), s->writetimeout) < 0) {
1337 s->eventq = s->eventq->next;
1340 ast_mutex_unlock(&s->__lock);
1346 static int get_input(struct mansession *s, char *output)
1348 /* output must have at least sizeof(s->inbuf) space */
1351 struct pollfd fds[1];
1352 char iabuf[INET_ADDRSTRLEN];
1353 for (x=1;x<s->inlen;x++) {
1354 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
1355 /* Copy output data up to and including \r\n */
1356 memcpy(output, s->inbuf, x + 1);
1357 /* Add trailing \0 */
1359 /* Move remaining data back to the front */
1360 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
1361 s->inlen -= (x + 1);
1365 if (s->inlen >= sizeof(s->inbuf) - 1) {
1366 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf);
1370 fds[0].events = POLLIN;
1372 res = poll(fds, 1, -1);
1374 if (errno == EINTR) {
1379 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
1381 } else if (res > 0) {
1382 ast_mutex_lock(&s->__lock);
1383 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
1384 ast_mutex_unlock(&s->__lock);
1391 s->inbuf[s->inlen] = '\0';
1395 static void *session_do(void *data)
1397 struct mansession *s = data;
1399 char iabuf[INET_ADDRSTRLEN];
1402 ast_mutex_lock(&s->__lock);
1403 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
1404 ast_mutex_unlock(&s->__lock);
1405 memset(&m, 0, sizeof(m));
1407 res = get_input(s, m.headers[m.hdrcount]);
1409 /* Strip trailing \r\n */
1410 if (strlen(m.headers[m.hdrcount]) < 2)
1412 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
1413 if (ast_strlen_zero(m.headers[m.hdrcount])) {
1414 if (process_message(s, &m))
1416 memset(&m, 0, sizeof(m));
1417 } else if (m.hdrcount < MAX_HEADERS - 1)
1422 if (s->authenticated) {
1423 if (option_verbose > 1) {
1424 if (displayconnects)
1425 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1427 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1429 if (option_verbose > 1) {
1430 if ( displayconnects )
1431 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1433 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
1439 static void *accept_thread(void *ignore)
1442 struct sockaddr_in sin;
1444 struct mansession *s;
1448 pthread_attr_t attr;
1450 pthread_attr_init(&attr);
1451 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1454 sinlen = sizeof(sin);
1455 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
1457 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
1460 p = getprotobyname("tcp");
1462 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
1463 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
1466 s = malloc(sizeof(struct mansession));
1468 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
1471 memset(s, 0, sizeof(struct mansession));
1472 memcpy(&s->sin, &sin, sizeof(sin));
1473 s->writetimeout = 100;
1475 if(! block_sockets) {
1476 /* For safety, make sure socket is non-blocking */
1477 flags = fcntl(as, F_GETFL);
1478 fcntl(as, F_SETFL, flags | O_NONBLOCK);
1480 ast_mutex_init(&s->__lock);
1482 s->send_events = -1;
1483 ast_mutex_lock(&sessionlock);
1486 ast_mutex_unlock(&sessionlock);
1487 if (ast_pthread_create(&s->t, &attr, session_do, s))
1490 pthread_attr_destroy(&attr);
1494 static int append_event(struct mansession *s, const char *str)
1496 struct eventqent *tmp, *prev=NULL;
1497 tmp = malloc(sizeof(struct eventqent) + strlen(str));
1500 strcpy(tmp->eventdata, str);
1514 /*! \brief manager_event: Send AMI event to client */
1515 int manager_event(int category, const char *event, const char *fmt, ...)
1517 struct mansession *s;
1519 char tmp[4096] = "";
1520 char *tmp_next = tmp;
1521 size_t tmp_left = sizeof(tmp) - 2;
1524 ast_mutex_lock(&sessionlock);
1525 for (s = sessions; s; s = s->next) {
1526 if ((s->readperm & category) != category)
1529 if ((s->send_events & category) != category)
1532 if (ast_strlen_zero(tmp)) {
1535 ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
1536 event, authority_to_str(category, auth, sizeof(auth)));
1537 if (timestampevents) {
1539 ast_build_string(&tmp_next, &tmp_left, "Timestamp: %ld.%06lu\r\n",
1540 now.tv_sec, (unsigned long) now.tv_usec);
1543 ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
1550 ast_mutex_lock(&s->__lock);
1552 append_event(s, tmp);
1553 } else if (!s->dead) {
1554 if (ast_carefulwrite(s->fd, tmp, tmp_next - tmp, s->writetimeout) < 0) {
1555 ast_log(LOG_WARNING, "Disconnecting slow (or gone) manager session!\n");
1557 pthread_kill(s->t, SIGURG);
1560 ast_mutex_unlock(&s->__lock);
1562 ast_mutex_unlock(&sessionlock);
1567 int ast_manager_unregister( char *action )
1569 struct manager_action *cur = first_action, *prev = first_action;
1571 ast_mutex_lock(&actionlock);
1573 if (!strcasecmp(action, cur->action)) {
1574 prev->next = cur->next;
1576 if (option_verbose > 1)
1577 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
1578 ast_mutex_unlock(&actionlock);
1584 ast_mutex_unlock(&actionlock);
1588 static int manager_state_cb(char *context, char *exten, int state, void *data)
1590 /* Notify managers of change */
1591 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
1595 static int ast_manager_register_struct(struct manager_action *act)
1597 struct manager_action *cur = first_action, *prev = NULL;
1600 ast_mutex_lock(&actionlock);
1601 while(cur) { /* Walk the list of actions */
1602 ret = strcasecmp(cur->action, act->action);
1604 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
1605 ast_mutex_unlock(&actionlock);
1607 } else if (ret > 0) {
1608 /* Insert these alphabetically */
1610 act->next = prev->next;
1613 act->next = first_action;
1630 if (option_verbose > 1)
1631 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
1632 ast_mutex_unlock(&actionlock);
1636 /*! \brief register a new command with manager, including online help. This is
1637 the preferred way to register a manager command */
1638 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
1640 struct manager_action *cur;
1642 cur = malloc(sizeof(struct manager_action));
1644 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
1647 cur->action = action;
1648 cur->authority = auth;
1650 cur->synopsis = synopsis;
1651 cur->description = description;
1654 ast_manager_register_struct(cur);
1659 END Doxygen group */
1661 static int registered = 0;
1663 int init_manager(void)
1665 struct ast_config *cfg;
1667 int oldportno = portno;
1668 static struct sockaddr_in ba;
1671 /* Register default actions */
1672 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
1673 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
1674 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
1675 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
1676 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
1677 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
1678 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
1679 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
1680 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
1681 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
1682 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
1683 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
1684 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
1685 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
1686 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
1688 ast_cli_register(&show_mancmd_cli);
1689 ast_cli_register(&show_mancmds_cli);
1690 ast_cli_register(&show_manconn_cli);
1691 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
1694 portno = DEFAULT_MANAGER_PORT;
1695 displayconnects = 1;
1696 cfg = ast_config_load("manager.conf");
1698 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
1701 memset(&ba, 0, sizeof(ba));
1702 val = ast_variable_retrieve(cfg, "general", "enabled");
1704 enabled = ast_true(val);
1706 val = ast_variable_retrieve(cfg, "general", "block-sockets");
1708 block_sockets = ast_true(val);
1710 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
1711 if (sscanf(val, "%d", &portno) != 1) {
1712 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
1713 portno = DEFAULT_MANAGER_PORT;
1717 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects")))
1718 displayconnects = ast_true(val);
1720 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents")))
1721 timestampevents = ast_true(val);
1723 ba.sin_family = AF_INET;
1724 ba.sin_port = htons(portno);
1725 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1727 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
1728 if (!inet_aton(val, &ba.sin_addr)) {
1729 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
1730 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
1734 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
1736 /* Can't be done yet */
1740 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
1743 ast_config_destroy(cfg);
1745 /* If not enabled, do nothing */
1750 asock = socket(AF_INET, SOCK_STREAM, 0);
1752 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1755 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
1756 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
1757 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
1762 if (listen(asock, 2)) {
1763 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
1769 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
1770 ast_pthread_create(&t, NULL, accept_thread, NULL);
1775 int reload_manager(void)
1777 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
1778 return init_manager();