Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:54 2009

## Asterisk developer's documentation

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Directories

# manager.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2005, Digium, Inc.
    00005  *
    00006  * Mark Spencer <markster@digium.com>
    00007  *
    00008  * See http://www.asterisk.org for more information about
    00009  * the Asterisk project. Please do not directly contact
    00010  * any of the maintainers of this project for assistance;
    00011  * the project provides a web site, mailing lists and IRC
    00012  * channels for your use.
    00013  *
    00014  * This program is free software, distributed under the terms of
    00015  * the GNU General Public License Version 2. See the LICENSE file
    00016  * at the top of the source tree.
    00017  */
    00018
    00019 /*! \file
    00020  *
    00021  * \brief The Asterisk Management Interface - AMI
    00022  *
    00023  * Channel Management and more
    00024  *
    00025  * \ref amiconf
    00026  */
    00027
    00028 /*! \addtogroup Group_AMI AMI functions
    00029 */
    00030 /*! @{
    00031  Doxygen group */
    00032
    00033 #include <stdio.h>
    00034 #include <stdlib.h>
    00035 #include <string.h>
    00036 #include <sys/time.h>
    00037 #include <sys/types.h>
    00038 #include <netdb.h>
    00039 #include <sys/socket.h>
    00040 #include <netinet/in.h>
    00041 #include <netinet/tcp.h>
    00042 #include <arpa/inet.h>
    00043 #include <signal.h>
    00044 #include <errno.h>
    00045 #include <unistd.h>
    00046
    00047 #include "asterisk.h"
    00048
    00049 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211526 $")
    00050
    00051 #include "asterisk/channel.h"
    00052 #include "asterisk/file.h"
    00053 #include "asterisk/manager.h"
    00054 #include "asterisk/config.h"
    00055 #include "asterisk/callerid.h"
    00056 #include "asterisk/lock.h"
    00057 #include "asterisk/logger.h"
    00058 #include "asterisk/options.h"
    00059 #include "asterisk/cli.h"
    00060 #include "asterisk/app.h"
    00061 #include "asterisk/pbx.h"
    00062 #include "asterisk/md5.h"
    00063 #include "asterisk/acl.h"
    00064 #include "asterisk/utils.h"
    00065
    00066 struct fast_originate_helper {
    00067    char tech[AST_MAX_MANHEADER_LEN];
    00068    char data[AST_MAX_MANHEADER_LEN];
    00069    int timeout;
    00070    char app[AST_MAX_APP];
    00071    char appdata[AST_MAX_MANHEADER_LEN];
    00072    char cid_name[AST_MAX_MANHEADER_LEN];
    00073    char cid_num[AST_MAX_MANHEADER_LEN];
    00074    char context[AST_MAX_CONTEXT];
    00075    char exten[AST_MAX_EXTENSION];
    00076    char idtext[AST_MAX_MANHEADER_LEN];
    00077    char account[AST_MAX_ACCOUNT_CODE];
    00078    int priority;
    00079    struct ast_variable *vars;
    00080 };
    00081
    00082 static int enabled = 0;
    00083 static int portno = DEFAULT_MANAGER_PORT;
    00084 static int asock = -1;
    00085 static int displayconnects = 1;
    00086
    00087 static pthread_t t;
    00088 AST_MUTEX_DEFINE_STATIC(sessionlock);
    00089 static int block_sockets = 0;
    00090
    00091 static struct permalias {
    00092    int num;
    00093    char *label;
    00094 } perms[] = {
    00095    { EVENT_FLAG_SYSTEM, "system" },
    00096    { EVENT_FLAG_CALL, "call" },
    00097    { EVENT_FLAG_LOG, "log" },
    00098    { EVENT_FLAG_VERBOSE, "verbose" },
    00099    { EVENT_FLAG_COMMAND, "command" },
    00100    { EVENT_FLAG_AGENT, "agent" },
    00101    { EVENT_FLAG_USER, "user" },
    00102    { -1, "all" },
    00103    { 0, "none" },
    00104 };
    00105
    00106 static struct mansession *sessions = NULL;
    00107 static struct manager_action *first_action = NULL;
    00108 AST_MUTEX_DEFINE_STATIC(actionlock);
    00109
    00110 /*! If you are calling ast_carefulwrite, it is assumed that you are calling
    00111    it on a file descriptor that _DOES_ have NONBLOCK set.  This way,
    00112    there is only one system call made to do a write, unless we actually
    00113    have a need to wait.  This way, we get better performance. */
    00114 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
    00115 {
    00116    /* Try to write string, but wait no more than ms milliseconds
    00117       before timing out */
    00118    int res=0;
    00119    struct pollfd fds[1];
    00120    while(len) {
    00121       res = write(fd, s, len);
    00122       if ((res < 0) && (errno != EAGAIN)) {
    00123          return -1;
    00124       }
    00125       if (res < 0) res = 0;
    00126       len -= res;
    00127       s += res;
    00128       res = 0;
    00129       if (len) {
    00130          fds[0].fd = fd;
    00131          fds[0].events = POLLOUT;
    00132          /* Wait until writable again */
    00133          res = poll(fds, 1, timeoutms);
    00134          if (res < 1)
    00135             return -1;
    00136       }
    00137    }
    00138    return res;
    00139 }
    00140
    00141 /*! authority_to_str: Convert authority code to string with serveral options */
    00142 static char *authority_to_str(int authority, char *res, int reslen)
    00143 {
    00144    int running_total = 0, i;
    00145    memset(res, 0, reslen);
    00146    for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
    00147       if (authority & perms[i].num) {
    00148          if (*res) {
    00149             strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
    00150             running_total++;
    00151          }
    00152          strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
    00153          running_total += strlen(perms[i].label);
    00154       }
    00155    }
    00156    if (ast_strlen_zero(res)) {
    00157       ast_copy_string(res, "<none>", reslen);
    00158    }
    00159    return res;
    00160 }
    00161
    00162 static char *complete_show_mancmd(char *line, char *word, int pos, int state)
    00163 {
    00164    struct manager_action *cur = first_action;
    00165    int which = 0;
    00166
    00167    ast_mutex_lock(&actionlock);
    00168    while (cur) { /* Walk the list of actions */
    00169       if (!strncasecmp(word, cur->action, strlen(word))) {
    00170          if (++which > state) {
    00171             char *ret = strdup(cur->action);
    00172             ast_mutex_unlock(&actionlock);
    00173             return ret;
    00174          }
    00175       }
    00176       cur = cur->next;
    00177    }
    00178    ast_mutex_unlock(&actionlock);
    00179    return NULL;
    00180 }
    00181
    00182 static int handle_showmancmd(int fd, int argc, char *argv[])
    00183 {
    00184    struct manager_action *cur = first_action;
    00185    char authority[80];
    00186    int num;
    00187
    00188    if (argc != 4)
    00189       return RESULT_SHOWUSAGE;
    00190    ast_mutex_lock(&actionlock);
    00191    while (cur) { /* Walk the list of actions */
    00192       for (num = 3; num < argc; num++) {
    00193          if (!strcasecmp(cur->action, argv[num])) {
    00194             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 : "");
    00195          }
    00196       }
    00197       cur = cur->next;
    00198    }
    00199
    00200    ast_mutex_unlock(&actionlock);
    00201    return RESULT_SUCCESS;
    00202 }
    00203
    00204 /*! \brief  handle_showmancmds: CLI command */
    00205 /* Should change to "manager show commands" */
    00206 static int handle_showmancmds(int fd, int argc, char *argv[])
    00207 {
    00208    struct manager_action *cur = first_action;
    00209    char authority[80];
    00210    char *format = "  %-15.15s  %-15.15s  %-55.55s\n";
    00211
    00212    ast_mutex_lock(&actionlock);
    00213    ast_cli(fd, format, "Action", "Privilege", "Synopsis");
    00214    ast_cli(fd, format, "------", "---------", "--------");
    00215    while (cur) { /* Walk the list of actions */
    00216       ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
    00217       cur = cur->next;
    00218    }
    00219
    00220    ast_mutex_unlock(&actionlock);
    00221    return RESULT_SUCCESS;
    00222 }
    00223
    00224 /*! \brief  handle_showmanconn: CLI command show manager connected */
    00225 /* Should change to "manager show connected" */
    00226 static int handle_showmanconn(int fd, int argc, char *argv[])
    00227 {
    00228    struct mansession *s;
    00229    char iabuf[INET_ADDRSTRLEN];
    00230    char *format = "  %-15.15s  %-15.15s\n";
    00231    ast_mutex_lock(&sessionlock);
    00232    s = sessions;
    00233    ast_cli(fd, format, "Username", "IP Address");
    00234    while (s) {
    00235       ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
    00236       s = s->next;
    00237    }
    00238
    00239    ast_mutex_unlock(&sessionlock);
    00240    return RESULT_SUCCESS;
    00241 }
    00242
    00243 static char showmancmd_help[] =
    00244 "Usage: show manager command <actionname>\n"
    00245 "  Shows the detailed description for a specific Asterisk manager interface command.\n";
    00246
    00247 static char showmancmds_help[] =
    00248 "Usage: show manager commands\n"
    00249 "  Prints a listing of all the available Asterisk manager interface commands.\n";
    00250
    00251 static char showmanconn_help[] =
    00252 "Usage: show manager connected\n"
    00253 "  Prints a listing of the users that are currently connected to the\n"
    00254 "Asterisk manager interface.\n";
    00255
    00256 static struct ast_cli_entry show_mancmd_cli =
    00257    { { "show", "manager", "command", NULL },
    00258    handle_showmancmd, "Show a manager interface command", showmancmd_help, complete_show_mancmd };
    00259
    00260 static struct ast_cli_entry show_mancmds_cli =
    00261    { { "show", "manager", "commands", NULL },
    00262    handle_showmancmds, "List manager interface commands", showmancmds_help };
    00263
    00264 static struct ast_cli_entry show_manconn_cli =
    00265    { { "show", "manager", "connected", NULL },
    00266    handle_showmanconn, "Show connected manager interface users", showmanconn_help };
    00267
    00268 static void free_session(struct mansession *s)
    00269 {
    00270    struct eventqent *eqe;
    00271    if (s->fd > -1)
    00272       close(s->fd);
    00273    ast_mutex_destroy(&s->__lock);
    00274    while(s->eventq) {
    00275       eqe = s->eventq;
    00276       s->eventq = s->eventq->next;
    00277       free(eqe);
    00278    }
    00279    free(s);
    00280 }
    00281
    00282 static void destroy_session(struct mansession *s)
    00283 {
    00284    struct mansession *cur, *prev = NULL;
    00285    ast_mutex_lock(&sessionlock);
    00286    cur = sessions;
    00287    while(cur) {
    00288       if (cur == s)
    00289          break;
    00290       prev = cur;
    00291       cur = cur->next;
    00292    }
    00293    if (cur) {
    00294       if (prev)
    00295          prev->next = cur->next;
    00296       else
    00297          sessions = cur->next;
    00298       free_session(s);
    00299    } else
    00300       ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
    00301    ast_mutex_unlock(&sessionlock);
    00302
    00303 }
    00304
    00305 char *astman_get_header(struct message *m, char *var)
    00306 {
    00307    char cmp[80];
    00308    int x;
    00309    snprintf(cmp, sizeof(cmp), "%s: ", var);
    00310    for (x=0;x<m->hdrcount;x++)
    00311       if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
    00312          return m->headers[x] + strlen(cmp);
    00313    return "";
    00314 }
    00315
    00316 struct ast_variable *astman_get_variables(struct message *m)
    00317 {
    00318    int varlen, x, y;
    00319    struct ast_variable *head = NULL, *cur;
    00320    char *var, *val;
    00321    unsigned int var_count;
    00322         char *vars[32];
    00323
    00324    varlen = strlen("Variable: ");
    00325
    00326    for (x = 0; x < m->hdrcount; x++) {
    00327       if (strncasecmp("Variable: ", m->headers[x], varlen))
    00328          continue;
    00329
    00330       if (!(var = ast_strdupa(m->headers[x] + varlen)))
    00331          return head;
    00332
    00333       if ((var_count = ast_app_separate_args(var, '|', vars, sizeof(vars) / sizeof(vars[0])))) {
    00334          for (y = 0; y < var_count; y++) {
    00335             if (!vars[y])
    00336                continue;
    00337             var = val = ast_strdupa(vars[y]);
    00338             strsep(&val, "=");
    00339             if (!val || ast_strlen_zero(var))
    00340                continue;
    00341             cur = ast_variable_new(var, val);
    00342             if (head) {
    00343                cur->next = head;
    00344                head = cur;
    00345             } else
    00346                head = cur;
    00347          }
    00348       }
    00349    }
    00350
    00351    return head;
    00352 }
    00353
    00354 /*! NOTE:
    00355    Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
    00356    hold the session lock _or_ be running in an action callback (in which case s->busy will
    00357    be non-zero). In either of these cases, there is no need to lock-protect the session's
    00358    fd, since no other output will be sent (events will be queued), and no input will
    00359    be read until either the current action finishes or get_input() obtains the session
    00360    lock.
    00361  */
    00362 void astman_send_error(struct mansession *s, struct message *m, char *error)
    00363 {
    00364    char *id = astman_get_header(m,"ActionID");
    00365
    00366    ast_cli(s->fd, "Response: Error\r\n");
    00367    if (!ast_strlen_zero(id))
    00368       ast_cli(s->fd, "ActionID: %s\r\n",id);
    00369    ast_cli(s->fd, "Message: %s\r\n\r\n", error);
    00370 }
    00371
    00372 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
    00373 {
    00374    char *id = astman_get_header(m,"ActionID");
    00375
    00376    ast_cli(s->fd, "Response: %s\r\n", resp);
    00377    if (!ast_strlen_zero(id))
    00378       ast_cli(s->fd, "ActionID: %s\r\n",id);
    00379    if (msg)
    00380       ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
    00381    else
    00382       ast_cli(s->fd, "\r\n");
    00383 }
    00384
    00385 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
    00386 {
    00387    astman_send_response(s, m, "Success", msg);
    00388 }
    00389
    00390 /*! Tells you if smallstr exists inside bigstr
    00391    which is delim by delim and uses no buf or stringsep
    00392    ast_instring("this|that|more","this",',') == 1;
    00393
    00394    feel free to move this to app.c -anthm */
    00395 static int ast_instring(char *bigstr, char *smallstr, char delim)
    00396 {
    00397    char *val = bigstr, *next;
    00398
    00399    do {
    00400       if ((next = strchr(val, delim))) {
    00401          if (!strncmp(val, smallstr, (next - val)))
    00402             return 1;
    00403          else
    00404             continue;
    00405       } else
    00406          return !strcmp(smallstr, val);
    00407
    00408    } while (*(val = (next + 1)));
    00409
    00410    return 0;
    00411 }
    00412
    00413 static int get_perm(char *instr)
    00414 {
    00415    int x = 0, ret = 0;
    00416
    00417    if (!instr)
    00418       return 0;
    00419
    00420    for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
    00421       if (ast_instring(instr, perms[x].label, ','))
    00422          ret |= perms[x].num;
    00423
    00424    return ret;
    00425 }
    00426
    00427 static int ast_is_number(char *string)
    00428 {
    00429    int ret = 1, x = 0;
    00430
    00431    if (!string)
    00432       return 0;
    00433
    00434    for (x=0; x < strlen(string); x++) {
    00435       if (!(string[x] >= 48 && string[x] <= 57)) {
    00436          ret = 0;
    00437          break;
    00438       }
    00439    }
    00440
    00441    return ret ? atoi(string) : 0;
    00442 }
    00443
    00444 static int ast_strings_to_mask(char *string)
    00445 {
    00446    int x, ret = -1;
    00447
    00448    x = ast_is_number(string);
    00449
    00450    if (x) {
    00451       ret = x;
    00452    } else if (ast_strlen_zero(string)) {
    00453       ret = -1;
    00454    } else if (ast_false(string)) {
    00455       ret = 0;
    00456    } else if (ast_true(string)) {
    00457       ret = 0;
    00458       for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
    00459          ret |= perms[x].num;
    00460    } else {
    00461       ret = 0;
    00462       for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
    00463          if (ast_instring(string, perms[x].label, ','))
    00464             ret |= perms[x].num;
    00465       }
    00466    }
    00467
    00468    return ret;
    00469 }
    00470
    00471 /*!
    00472    Rather than braindead on,off this now can also accept a specific int mask value
    00473    or a ',' delim list of mask strings (the same as manager.conf) -anthm
    00474 */
    00475
    00476 static int set_eventmask(struct mansession *s, char *eventmask)
    00477 {
    00478    int maskint = ast_strings_to_mask(eventmask);
    00479
    00480    ast_mutex_lock(&s->__lock);
    00481    if (maskint >= 0)
    00482       s->send_events = maskint;
    00483    ast_mutex_unlock(&s->__lock);
    00484
    00485    return maskint;
    00486 }
    00487
    00488 static int authenticate(struct mansession *s, struct message *m)
    00489 {
    00490    struct ast_config *cfg;
    00491    char iabuf[INET_ADDRSTRLEN];
    00492    char *cat;
    00493    char *user = astman_get_header(m, "Username");
    00494    char *pass = astman_get_header(m, "Secret");
    00495    char *authtype = astman_get_header(m, "AuthType");
    00496    char *key = astman_get_header(m, "Key");
    00497    char *events = astman_get_header(m, "Events");
    00498
    00499    cfg = ast_config_load("manager.conf");
    00500    if (!cfg)
    00501       return -1;
    00502    cat = ast_category_browse(cfg, NULL);
    00503    while(cat) {
    00504       if (strcasecmp(cat, "general")) {
    00505          /* This is a user */
    00506          if (!strcasecmp(cat, user)) {
    00507             struct ast_variable *v;
    00508             struct ast_ha *ha = NULL;
    00509             char *password = NULL;
    00510             v = ast_variable_browse(cfg, cat);
    00511             while (v) {
    00512                if (!strcasecmp(v->name, "secret")) {
    00513                   password = v->value;
    00514                } else if (!strcasecmp(v->name, "permit") ||
    00515                      !strcasecmp(v->name, "deny")) {
    00516                   ha = ast_append_ha(v->name, v->value, ha);
    00517                } else if (!strcasecmp(v->name, "writetimeout")) {
    00518                   int val = atoi(v->value);
    00519
    00520                   if (val < 100)
    00521                      ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
    00522                   else
    00523                      s->writetimeout = val;
    00524                }
    00525
    00526                v = v->next;
    00527             }
    00528             if (ha && !ast_apply_ha(ha, &(s->sin))) {
    00529                ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
    00530                ast_free_ha(ha);
    00531                ast_config_destroy(cfg);
    00532                return -1;
    00533             } else if (ha)
    00534                ast_free_ha(ha);
    00535             if (!strcasecmp(authtype, "MD5")) {
    00536                if (!ast_strlen_zero(key) &&
    00537                    !ast_strlen_zero(s->challenge) && !ast_strlen_zero(password)) {
    00538                   int x;
    00539                   int len=0;
    00540                   char md5key[256] = "";
    00541                   struct MD5Context md5;
    00542                   unsigned char digest[16];
    00543                   MD5Init(&md5);
    00544                   MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
    00545                   MD5Update(&md5, (unsigned char *) password, strlen(password));
    00546                   MD5Final(digest, &md5);
    00547                   for (x=0;x<16;x++)
    00548                      len += sprintf(md5key + len, "%2.2x", digest[x]);
    00549                   if (!strcmp(md5key, key))
    00550                      break;
    00551                   else {
    00552                      ast_config_destroy(cfg);
    00553                      return -1;
    00554                   }
    00555                }
    00556             } else if (password && !strcasecmp(password, pass)) {
    00557                break;
    00558             } else {
    00559                ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
    00560                ast_config_destroy(cfg);
    00561                return -1;
    00562             }
    00563          }
    00564       }
    00565       cat = ast_category_browse(cfg, cat);
    00566    }
    00567    if (cat) {
    00568       ast_copy_string(s->username, cat, sizeof(s->username));
    00569       s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
    00570       s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
    00571       ast_config_destroy(cfg);
    00572       if (events)
    00573          set_eventmask(s, events);
    00574       return 0;
    00575    }
    00576    ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
    00577    ast_config_destroy(cfg);
    00578    return -1;
    00579 }
    00580
    00581 /*! \brief PING: Manager PING */
    00582 static char mandescr_ping[] =
    00583 "Description: A 'Ping' action will ellicit a 'Pong' response.  Used to keep the "
    00584 "  manager connection open.\n"
    00585 "Variables: NONE\n";
    00586
    00587 static int action_ping(struct mansession *s, struct message *m)
    00588 {
    00589    astman_send_response(s, m, "Pong", NULL);
    00590    return 0;
    00591 }
    00592
    00593 static char mandescr_listcommands[] =
    00594 "Description: Returns the action name and synopsis for every\n"
    00595 "  action that is available to the user\n"
    00596 "Variables: NONE\n";
    00597
    00598 static int action_listcommands(struct mansession *s, struct message *m)
    00599 {
    00600    struct manager_action *cur = first_action;
    00601    char idText[256] = "";
    00602    char temp[BUFSIZ];
    00603    char *id = astman_get_header(m,"ActionID");
    00604
    00605    if (!ast_strlen_zero(id))
    00606       snprintf(idText,256,"ActionID: %s\r\n",id);
    00607    ast_cli(s->fd, "Response: Success\r\n%s", idText);
    00608    ast_mutex_lock(&actionlock);
    00609    while (cur) { /* Walk the list of actions */
    00610       if ((s->writeperm & cur->authority) == cur->authority)
    00611          ast_cli(s->fd, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)) );
    00612       cur = cur->next;
    00613    }
    00614    ast_mutex_unlock(&actionlock);
    00615    ast_cli(s->fd, "\r\n");
    00616
    00617    return 0;
    00618 }
    00619
    00620 static char mandescr_events[] =
    00621 "Description: Enable/Disable sending of events to this manager\n"
    00622 "  client.\n"
    00623 "Variables:\n"
    00624 "  EventMask: 'on' if all events should be sent,\n"
    00625 "     'off' if no events should be sent,\n"
    00626 "     'system,call,log' to select which flags events should have to be sent.\n";
    00627
    00628 static int action_events(struct mansession *s, struct message *m)
    00629 {
    00630    char *mask = astman_get_header(m, "EventMask");
    00631    int res;
    00632
    00633    res = set_eventmask(s, mask);
    00634    if (res > 0)
    00635       astman_send_response(s, m, "Events On", NULL);
    00636    else if (res == 0)
    00637       astman_send_response(s, m, "Events Off", NULL);
    00638
    00639    return 0;
    00640 }
    00641
    00642 static char mandescr_logoff[] =
    00643 "Description: Logoff this manager session\n"
    00644 "Variables: NONE\n";
    00645
    00646 static int action_logoff(struct mansession *s, struct message *m)
    00647 {
    00648    astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
    00649    return -1;
    00650 }
    00651
    00652 static char mandescr_hangup[] =
    00653 "Description: Hangup a channel\n"
    00654 "Variables: \n"
    00655 "  Channel: The channel name to be hungup\n";
    00656
    00657 static int action_hangup(struct mansession *s, struct message *m)
    00658 {
    00659    struct ast_channel *c = NULL;
    00660    char *name = astman_get_header(m, "Channel");
    00661    if (ast_strlen_zero(name)) {
    00662       astman_send_error(s, m, "No channel specified");
    00663       return 0;
    00664    }
    00665    c = ast_get_channel_by_name_locked(name);
    00666    if (!c) {
    00667       astman_send_error(s, m, "No such channel");
    00668       return 0;
    00669    }
    00670    ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
    00671    ast_mutex_unlock(&c->lock);
    00672    astman_send_ack(s, m, "Channel Hungup");
    00673    return 0;
    00674 }
    00675
    00676 static char mandescr_setvar[] =
    00677 "Description: Set a global or local channel variable.\n"
    00678 "Variables: (Names marked with * are required)\n"
    00679 "  Channel: Channel to set variable for\n"
    00680 "  *Variable: Variable name\n"
    00681 "  *Value: Value\n";
    00682
    00683 static int action_setvar(struct mansession *s, struct message *m)
    00684 {
    00685         struct ast_channel *c = NULL;
    00686         char *name = astman_get_header(m, "Channel");
    00687         char *varname = astman_get_header(m, "Variable");
    00688         char *varval = astman_get_header(m, "Value");
    00689
    00690    if (ast_strlen_zero(varname)) {
    00691       astman_send_error(s, m, "No variable specified");
    00692       return 0;
    00693    }
    00694
    00695    if (!ast_strlen_zero(name)) {
    00696       c = ast_get_channel_by_name_locked(name);
    00697       if (!c) {
    00698          astman_send_error(s, m, "No such channel");
    00699          return 0;
    00700       }
    00701    }
    00702
    00703    pbx_builtin_setvar_helper(c, varname, varval ? varval : "");
    00704
    00705    if (c)
    00706       ast_mutex_unlock(&c->lock);
    00707
    00708    astman_send_ack(s, m, "Variable Set");
    00709
    00710    return 0;
    00711 }
    00712
    00713 static char mandescr_getvar[] =
    00714 "Description: Get the value of a global or local channel variable.\n"
    00715 "Variables: (Names marked with * are required)\n"
    00716 "  Channel: Channel to read variable from\n"
    00717 "  *Variable: Variable name\n"
    00718 "  ActionID: Optional Action id for message matching.\n";
    00719
    00720 static int action_getvar(struct mansession *s, struct message *m)
    00721 {
    00722         struct ast_channel *c = NULL;
    00723         char *name = astman_get_header(m, "Channel");
    00724         char *varname = astman_get_header(m, "Variable");
    00725    char *id = astman_get_header(m,"ActionID");
    00726    char *varval;
    00727    char *varval2=NULL;
    00728
    00729    if (!strlen(varname)) {
    00730       astman_send_error(s, m, "No variable specified");
    00731       return 0;
    00732    }
    00733
    00734    if (strlen(name)) {
    00735       c = ast_get_channel_by_name_locked(name);
    00736       if (!c) {
    00737          astman_send_error(s, m, "No such channel");
    00738          return 0;
    00739       }
    00740    }
    00741
    00742    varval=pbx_builtin_getvar_helper(c,varname);
    00743    if (varval)
    00744       varval2 = ast_strdupa(varval);
    00745    if (!varval2)
    00746       varval2 = "";
    00747    if (c)
    00748       ast_mutex_unlock(&c->lock);
    00749    ast_cli(s->fd, "Response: Success\r\n"
    00750       "Variable: %s\r\nValue: %s\r\n" ,varname,varval2);
    00751    if (!ast_strlen_zero(id))
    00752       ast_cli(s->fd, "ActionID: %s\r\n",id);
    00753    ast_cli(s->fd, "\r\n");
    00754
    00755    return 0;
    00756 }
    00757
    00758
    00759 /*! \brief  action_status: Manager "status" command to show channels */
    00760 /* Needs documentation... */
    00761 static int action_status(struct mansession *s, struct message *m)
    00762 {
    00763    char *id = astman_get_header(m,"ActionID");
    00764       char *name = astman_get_header(m,"Channel");
    00765    char idText[256] = "";
    00766    struct ast_channel *c;
    00767    char bridge[256];
    00768    struct timeval now = ast_tvnow();
    00769    long elapsed_seconds=0;
    00770    int all = ast_strlen_zero(name); /* set if we want all channels */
    00771
    00772         if (!ast_strlen_zero(id))
    00773                 snprintf(idText,256,"ActionID: %s\r\n",id);
    00774    if (all)
    00775       c = ast_channel_walk_locked(NULL);
    00776    else {
    00777       c = ast_get_channel_by_name_locked(name);
    00778       if (!c) {
    00779          astman_send_error(s, m, "No such channel");
    00780          return 0;
    00781       }
    00782    }
    00783    astman_send_ack(s, m, "Channel status will follow");
    00784    /* if we look by name, we break after the first iteration */
    00785    while(c) {
    00786       if (c->_bridge)
    00787          snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
    00788       else
    00789          bridge[0] = '\0';
    00790       if (c->pbx) {
    00791          if (c->cdr) {
    00792             elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
    00793          }
    00794          ast_cli(s->fd,
    00795          "Event: Status\r\n"
    00796          "Privilege: Call\r\n"
    00797          "Channel: %s\r\n"
    00798          "CallerID: %s\r\n"
    00799          "CallerIDName: %s\r\n"
    00800          "Account: %s\r\n"
    00801          "State: %s\r\n"
    00802          "Context: %s\r\n"
    00803          "Extension: %s\r\n"
    00804          "Priority: %d\r\n"
    00805          "Seconds: %ld\r\n"
    00806          "%s"
    00807          "Uniqueid: %s\r\n"
    00808          "%s"
    00809          "\r\n",
    00810          c->name,
    00811          c->cid.cid_num ? c->cid.cid_num : "<unknown>",
    00812          c->cid.cid_name ? c->cid.cid_name : "<unknown>",
    00813          c->accountcode,
    00814          ast_state2str(c->_state), c->context,
    00815          c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
    00816       } else {
    00817          ast_cli(s->fd,
    00818          "Event: Status\r\n"
    00819          "Privilege: Call\r\n"
    00820          "Channel: %s\r\n"
    00821          "CallerID: %s\r\n"
    00822          "CallerIDName: %s\r\n"
    00823          "Account: %s\r\n"
    00824          "State: %s\r\n"
    00825          "%s"
    00826          "Uniqueid: %s\r\n"
    00827          "%s"
    00828          "\r\n",
    00829          c->name,
    00830          c->cid.cid_num ? c->cid.cid_num : "<unknown>",
    00831          c->cid.cid_name ? c->cid.cid_name : "<unknown>",
    00832          c->accountcode,
    00833          ast_state2str(c->_state), bridge, c->uniqueid, idText);
    00834       }
    00835       ast_mutex_unlock(&c->lock);
    00836       if (!all)
    00837          break;
    00838       c = ast_channel_walk_locked(c);
    00839    }
    00840    ast_cli(s->fd,
    00841    "Event: StatusComplete\r\n"
    00842    "%s"
    00843    "\r\n",idText);
    00844    return 0;
    00845 }
    00846
    00847 static char mandescr_redirect[] =
    00848 "Description: Redirect (transfer) a call.\n"
    00849 "Variables: (Names marked with * are required)\n"
    00850 "  *Channel: Channel to redirect\n"
    00851 "  ExtraChannel: Second call leg to transfer (optional)\n"
    00852 "  *Exten: Extension to transfer to\n"
    00853 "  *Context: Context to transfer to\n"
    00854 "  *Priority: Priority to transfer to\n"
    00855 "  ActionID: Optional Action id for message matching.\n";
    00856
    00857 /*! \brief  action_redirect: The redirect manager command */
    00858 static int action_redirect(struct mansession *s, struct message *m)
    00859 {
    00860    char *name = astman_get_header(m, "Channel");
    00861    char *name2 = astman_get_header(m, "ExtraChannel");
    00862    char *exten = astman_get_header(m, "Exten");
    00863    char *context = astman_get_header(m, "Context");
    00864    char *priority = astman_get_header(m, "Priority");
    00865    struct ast_channel *chan, *chan2 = NULL;
    00866    int pi = 0;
    00867    int res;
    00868
    00869    if (ast_strlen_zero(name)) {
    00870       astman_send_error(s, m, "Channel not specified");
    00871       return 0;
    00872    }
    00873    if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
    00874       astman_send_error(s, m, "Invalid priority\n");
    00875       return 0;
    00876    }
    00877    chan = ast_get_channel_by_name_locked(name);
    00878    if (!chan) {
    00879       char buf[BUFSIZ];
    00880       snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
    00881       astman_send_error(s, m, buf);
    00882       return 0;
    00883    }
    00884    if (ast_check_hangup(chan)) {
    00885       astman_send_error(s, m, "Redirect failed, channel hung up.\n");
    00886       ast_mutex_unlock(&chan->lock);
    00887       return 0;
    00888    }
    00889    if (!ast_strlen_zero(name2))
    00890       chan2 = ast_get_channel_by_name_locked(name2);
    00891    if (chan2 && ast_check_hangup(chan2)) {
    00892       astman_send_error(s, m, "Redirect failed, extra channel hung up.\n");
    00893       ast_mutex_unlock(&chan->lock);
    00894       ast_mutex_unlock(&chan2->lock);
    00895       return 0;
    00896    }
    00897    res = ast_async_goto(chan, context, exten, pi);
    00898    if (!res) {
    00899       if (!ast_strlen_zero(name2)) {
    00900          if (chan2)
    00901             res = ast_async_goto(chan2, context, exten, pi);
    00902          else
    00903             res = -1;
    00904          if (!res)
    00905             astman_send_ack(s, m, "Dual Redirect successful");
    00906          else
    00907             astman_send_error(s, m, "Secondary redirect failed");
    00908       } else
    00909          astman_send_ack(s, m, "Redirect successful");
    00910    } else
    00911       astman_send_error(s, m, "Redirect failed");
    00912    if (chan)
    00913       ast_mutex_unlock(&chan->lock);
    00914    if (chan2)
    00915       ast_mutex_unlock(&chan2->lock);
    00916    return 0;
    00917 }
    00918
    00919 static char mandescr_command[] =
    00920 "Description: Run a CLI command.\n"
    00921 "Variables: (Names marked with * are required)\n"
    00922 "  *Command: Asterisk CLI command to run\n"
    00923 "  ActionID: Optional Action id for message matching.\n";
    00924
    00925 /*! \brief  action_command: Manager command "command" - execute CLI command */
    00926 static int action_command(struct mansession *s, struct message *m)
    00927 {
    00928    char *cmd = astman_get_header(m, "Command");
    00929    char *id = astman_get_header(m, "ActionID");
    00930    ast_cli(s->fd, "Response: Follows\r\nPrivilege: Command\r\n");
    00931    if (!ast_strlen_zero(id))
    00932       ast_cli(s->fd, "ActionID: %s\r\n", id);
    00933    /* FIXME: Wedge a ActionID response in here, waiting for later changes */
    00934    ast_cli_command(s->fd, cmd);
    00935    ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
    00936    return 0;
    00937 }
    00938
    00939 static void *fast_originate(void *data)
    00940 {
    00941    struct fast_originate_helper *in = data;
    00942    int res;
    00943    int reason = 0;
    00944    struct ast_channel *chan = NULL;
    00945
    00946    if (!ast_strlen_zero(in->app)) {
    00947       res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1,
    00948          !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
    00949          !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
    00950          in->vars, in->account, &chan);
    00951    } else {
    00952       res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
    00953          !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
    00954          !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
    00955          in->vars, in->account, &chan);
    00956    }
    00957    if (!res)
    00958       manager_event(EVENT_FLAG_CALL,
    00959          "OriginateSuccess",
    00960          "%s"
    00961          "Channel: %s/%s\r\n"
    00962          "Context: %s\r\n"
    00963          "Exten: %s\r\n"
    00964          "Reason: %d\r\n"
    00965          "Uniqueid: %s\r\n",
    00966          in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
    00967    else
    00968       manager_event(EVENT_FLAG_CALL,
    00969          "OriginateFailure",
    00970          "%s"
    00971          "Channel: %s/%s\r\n"
    00972          "Context: %s\r\n"
    00973          "Exten: %s\r\n"
    00974          "Reason: %d\r\n"
    00975          "Uniqueid: %s\r\n",
    00976          in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
    00977
    00978    /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
    00979    if (chan)
    00980       ast_mutex_unlock(&chan->lock);
    00981    free(in);
    00982    return NULL;
    00983 }
    00984
    00985 static char mandescr_originate[] =
    00986 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
    00987 "  Application/Data\n"
    00988 "Variables: (Names marked with * are required)\n"
    00989 "  *Channel: Channel name to call\n"
    00990 "  Exten: Extension to use (requires 'Context' and 'Priority')\n"
    00991 "  Context: Context to use (requires 'Exten' and 'Priority')\n"
    00992 "  Priority: Priority to use (requires 'Exten' and 'Context')\n"
    00993 "  Application: Application to use\n"
    00994 "  Data: Data to use (requires 'Application')\n"
    00995 "  Timeout: How long to wait for call to be answered (in ms)\n"
    00996 "  CallerID: Caller ID to be set on the outgoing channel\n"
    00997 "  Variable: Channel variable to set, multiple Variable: headers are allowed\n"
    00998 "  Account: Account code\n"
    00999 "  Async: Set to 'true' for fast origination\n";
    01000
    01001 static int action_originate(struct mansession *s, struct message *m)
    01002 {
    01003    char *name = astman_get_header(m, "Channel");
    01004    char *exten = astman_get_header(m, "Exten");
    01005    char *context = astman_get_header(m, "Context");
    01006    char *priority = astman_get_header(m, "Priority");
    01007    char *timeout = astman_get_header(m, "Timeout");
    01008    char *callerid = astman_get_header(m, "CallerID");
    01009    char *account = astman_get_header(m, "Account");
    01010    char *app = astman_get_header(m, "Application");
    01011    char *appdata = astman_get_header(m, "Data");
    01012    char *async = astman_get_header(m, "Async");
    01013    char *id = astman_get_header(m, "ActionID");
    01014    struct ast_variable *vars = astman_get_variables(m);
    01015    char *tech, *data;
    01016    char *l=NULL, *n=NULL;
    01017    int pi = 0;
    01018    int res;
    01019    int to = 30000;
    01020    int reason = 0;
    01021    char tmp[256];
    01022    char tmp2[256];
    01023
    01024    pthread_t th;
    01025    pthread_attr_t attr;
    01026    if (!name) {
    01027       astman_send_error(s, m, "Channel not specified");
    01028       return 0;
    01029    }
    01030    if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
    01031       astman_send_error(s, m, "Invalid priority\n");
    01032       return 0;
    01033    }
    01034    if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
    01035       astman_send_error(s, m, "Invalid timeout\n");
    01036       return 0;
    01037    }
    01038    ast_copy_string(tmp, name, sizeof(tmp));
    01039    tech = tmp;
    01040    data = strchr(tmp, '/');
    01041    if (!data) {
    01042       astman_send_error(s, m, "Invalid channel\n");
    01043       return 0;
    01044    }
    01045    *data = '\0';
    01046    data++;
    01047    ast_copy_string(tmp2, callerid, sizeof(tmp2));
    01048    ast_callerid_parse(tmp2, &n, &l);
    01049    if (n) {
    01050       if (ast_strlen_zero(n))
    01051          n = NULL;
    01052    }
    01053    if (l) {
    01054       ast_shrink_phone_number(l);
    01055       if (ast_strlen_zero(l))
    01056          l = NULL;
    01057    }
    01058    if (ast_true(async)) {
    01059       struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
    01060       if (!fast) {
    01061          res = -1;
    01062       } else {
    01063          memset(fast, 0, sizeof(struct fast_originate_helper));
    01064          if (!ast_strlen_zero(id))
    01065             snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
    01066          ast_copy_string(fast->tech, tech, sizeof(fast->tech));
    01067             ast_copy_string(fast->data, data, sizeof(fast->data));
    01068          ast_copy_string(fast->app, app, sizeof(fast->app));
    01069          ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
    01070          if (l)
    01071             ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
    01072          if (n)
    01073             ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
    01074          fast->vars = vars;
    01075          ast_copy_string(fast->context, context, sizeof(fast->context));
    01076          ast_copy_string(fast->exten, exten, sizeof(fast->exten));
    01077          ast_copy_string(fast->account, account, sizeof(fast->account));
    01078          fast->timeout = to;
    01079          fast->priority = pi;
    01080          pthread_attr_init(&attr);
    01081          pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    01082          if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
    01083             res = -1;
    01084          } else {
    01085             res = 0;
    01086          }
    01087          pthread_attr_destroy(&attr);
    01088       }
    01089    } else if (!ast_strlen_zero(app)) {
    01090          res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
    01091       } else {
    01092       if (exten && context && pi)
    01093             res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
    01094       else {
    01095          astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
    01096          return 0;
    01097       }
    01098    }
    01099    if (!res)
    01100       astman_send_ack(s, m, "Originate successfully queued");
    01101    else
    01102       astman_send_error(s, m, "Originate failed");
    01103    return 0;
    01104 }
    01105
    01106 /*!   \brief Help text for manager command mailboxstatus
    01107  */
    01108 static char mandescr_mailboxstatus[] =
    01109 "Description: Checks a voicemail account for status.\n"
    01110 "Variables: (Names marked with * are required)\n"
    01111 "  *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
    01112 "  ActionID: Optional ActionID for message matching.\n"
    01113 "Returns number of messages.\n"
    01114 "  Message: Mailbox Status\n"
    01115 "  Mailbox: <mailboxid>\n"
    01116 "  Waiting: <count>\n"
    01117 "\n";
    01118
    01119 static int action_mailboxstatus(struct mansession *s, struct message *m)
    01120 {
    01121    char *mailbox = astman_get_header(m, "Mailbox");
    01122    char *id = astman_get_header(m,"ActionID");
    01123    char idText[256] = "";
    01124    int ret;
    01125    if (ast_strlen_zero(mailbox)) {
    01126       astman_send_error(s, m, "Mailbox not specified");
    01127       return 0;
    01128    }
    01129         if (!ast_strlen_zero(id))
    01130                 snprintf(idText,256,"ActionID: %s\r\n",id);
    01131    ret = ast_app_has_voicemail(mailbox, NULL);
    01132    ast_cli(s->fd, "Response: Success\r\n"
    01133                "%s"
    01134                "Message: Mailbox Status\r\n"
    01135                "Mailbox: %s\r\n"
    01136                "Waiting: %d\r\n\r\n", idText, mailbox, ret);
    01137    return 0;
    01138 }
    01139
    01140 static char mandescr_mailboxcount[] =
    01141 "Description: Checks a voicemail account for new messages.\n"
    01142 "Variables: (Names marked with * are required)\n"
    01143 "  *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
    01144 "  ActionID: Optional ActionID for message matching.\n"
    01145 "Returns number of new and old messages.\n"
    01146 "  Message: Mailbox Message Count\n"
    01147 "  Mailbox: <mailboxid>\n"
    01148 "  NewMessages: <count>\n"
    01149 "  OldMessages: <count>\n"
    01150 "\n";
    01151 static int action_mailboxcount(struct mansession *s, struct message *m)
    01152 {
    01153    char *mailbox = astman_get_header(m, "Mailbox");
    01154    char *id = astman_get_header(m,"ActionID");
    01155    char idText[256] = "";
    01156    int newmsgs = 0, oldmsgs = 0;
    01157    if (ast_strlen_zero(mailbox)) {
    01158       astman_send_error(s, m, "Mailbox not specified");
    01159       return 0;
    01160    }
    01161    ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
    01162    if (!ast_strlen_zero(id)) {
    01163       snprintf(idText,256,"ActionID: %s\r\n",id);
    01164    }
    01165    ast_cli(s->fd, "Response: Success\r\n"
    01166                "%s"
    01167                "Message: Mailbox Message Count\r\n"
    01168                "Mailbox: %s\r\n"
    01169                "NewMessages: %d\r\n"
    01170                "OldMessages: %d\r\n"
    01171                "\r\n",
    01172                 idText,mailbox, newmsgs, oldmsgs);
    01173    return 0;
    01174 }
    01175
    01176 static char mandescr_extensionstate[] =
    01177 "Description: Report the extension state for given extension.\n"
    01178 "  If the extension has a hint, will use devicestate to check\n"
    01179 "  the status of the device connected to the extension.\n"
    01180 "Variables: (Names marked with * are required)\n"
    01181 "  *Exten: Extension to check state on\n"
    01182 "  *Context: Context for extension\n"
    01183 "  ActionId: Optional ID for this transaction\n"
    01184 "Will return an \"Extension Status\" message.\n"
    01185 "The response will include the hint for the extension and the status.\n";
    01186
    01187 static int action_extensionstate(struct mansession *s, struct message *m)
    01188 {
    01189    char *exten = astman_get_header(m, "Exten");
    01190    char *context = astman_get_header(m, "Context");
    01191    char *id = astman_get_header(m,"ActionID");
    01192    char idText[256] = "";
    01193    char hint[256] = "";
    01194    int status;
    01195    if (ast_strlen_zero(exten)) {
    01196       astman_send_error(s, m, "Extension not specified");
    01197       return 0;
    01198    }
    01199    if (ast_strlen_zero(context))
    01200       context = "default";
    01201    status = ast_extension_state(NULL, context, exten);
    01202    ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
    01203         if (!ast_strlen_zero(id)) {
    01204                 snprintf(idText,256,"ActionID: %s\r\n",id);
    01205         }
    01206    ast_cli(s->fd, "Response: Success\r\n"
    01207                     "%s"
    01208                "Message: Extension Status\r\n"
    01209                "Exten: %s\r\n"
    01210                "Context: %s\r\n"
    01211                "Hint: %s\r\n"
    01212                "Status: %d\r\n\r\n",
    01213                idText,exten, context, hint, status);
    01214    return 0;
    01215 }
    01216
    01217 static char mandescr_timeout[] =
    01218 "Description: Hangup a channel after a certain time.\n"
    01219 "Variables: (Names marked with * are required)\n"
    01220 "  *Channel: Channel name to hangup\n"
    01221 "  *Timeout: Maximum duration of the call (sec)\n"
    01222 "Acknowledges set time with 'Timeout Set' message\n";
    01223
    01224 static int action_timeout(struct mansession *s, struct message *m)
    01225 {
    01226    struct ast_channel *c = NULL;
    01227    char *name = astman_get_header(m, "Channel");
    01228    int timeout = atoi(astman_get_header(m, "Timeout"));
    01229    if (ast_strlen_zero(name)) {
    01230       astman_send_error(s, m, "No channel specified");
    01231       return 0;
    01232    }
    01233    if (!timeout) {
    01234       astman_send_error(s, m, "No timeout specified");
    01235       return 0;
    01236    }
    01237    c = ast_get_channel_by_name_locked(name);
    01238    if (!c) {
    01239       astman_send_error(s, m, "No such channel");
    01240       return 0;
    01241    }
    01242    ast_channel_setwhentohangup(c, timeout);
    01243    ast_mutex_unlock(&c->lock);
    01244    astman_send_ack(s, m, "Timeout Set");
    01245    return 0;
    01246 }
    01247
    01248 static int process_message(struct mansession *s, struct message *m)
    01249 {
    01250    char action[80] = "";
    01251    struct manager_action *tmp = first_action;
    01252    char *id = astman_get_header(m,"ActionID");
    01253    char idText[256] = "";
    01254    char iabuf[INET_ADDRSTRLEN];
    01255
    01256    ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
    01257    ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
    01258
    01259    if (ast_strlen_zero(action)) {
    01260       astman_send_error(s, m, "Missing action in request");
    01261       return 0;
    01262    }
    01263         if (!ast_strlen_zero(id)) {
    01264                 snprintf(idText,256,"ActionID: %s\r\n",id);
    01265         }
    01266    if (!s->authenticated) {
    01267       if (!strcasecmp(action, "Challenge")) {
    01268          char *authtype;
    01269          authtype = astman_get_header(m, "AuthType");
    01270          if (!strcasecmp(authtype, "MD5")) {
    01271             if (ast_strlen_zero(s->challenge))
    01272                snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
    01273             ast_mutex_lock(&s->__lock);
    01274             ast_cli(s->fd, "Response: Success\r\n"
    01275                   "%s"
    01276                   "Challenge: %s\r\n\r\n",
    01277                   idText,s->challenge);
    01278             ast_mutex_unlock(&s->__lock);
    01279             return 0;
    01280          } else {
    01281             astman_send_error(s, m, "Must specify AuthType");
    01282             return 0;
    01283          }
    01284       } else if (!strcasecmp(action, "Login")) {
    01285          if (authenticate(s, m)) {
    01286             sleep(1);
    01287             astman_send_error(s, m, "Authentication failed");
    01288             return -1;
    01289          } else {
    01290             s->authenticated = 1;
    01291             if (option_verbose > 1) {
    01292                if ( displayconnects ) {
    01293                   ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
    01294                }
    01295             }
    01296             ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
    01297             astman_send_ack(s, m, "Authentication accepted");
    01298          }
    01299       } else if (!strcasecmp(action, "Logoff")) {
    01300          astman_send_ack(s, m, "See ya");
    01301          return -1;
    01302       } else
    01303          astman_send_error(s, m, "Authentication Required");
    01304    } else {
    01305       int ret=0;
    01306       struct eventqent *eqe;
    01307       ast_mutex_lock(&s->__lock);
    01308       s->busy = 1;
    01309       ast_mutex_unlock(&s->__lock);
    01310       while( tmp ) {
    01311          if (!strcasecmp(action, tmp->action)) {
    01312             if ((s->writeperm & tmp->authority) == tmp->authority) {
    01313                if (tmp->func(s, m))
    01314                   ret = -1;
    01315             } else {
    01316                astman_send_error(s, m, "Permission denied");
    01317             }
    01318             break;
    01319          }
    01320          tmp = tmp->next;
    01321       }
    01322       if (!tmp)
    01323          astman_send_error(s, m, "Invalid/unknown command");
    01324       ast_mutex_lock(&s->__lock);
    01325       s->busy = 0;
    01326       while(s->eventq) {
    01327          if (ast_carefulwrite(s->fd, s->eventq->eventdata, strlen(s->eventq->eventdata), s->writetimeout) < 0) {
    01328             ret = -1;
    01329             break;
    01330          }
    01331          eqe = s->eventq;
    01332          s->eventq = s->eventq->next;
    01333          free(eqe);
    01334       }
    01335       ast_mutex_unlock(&s->__lock);
    01336       return ret;
    01337    }
    01338    return 0;
    01339 }
    01340
    01341 static int get_input(struct mansession *s, char *output)
    01342 {
    01343    /* output must have at least sizeof(s->inbuf) space */
    01344    int res;
    01345    int x;
    01346    struct pollfd fds[1];
    01347    char iabuf[INET_ADDRSTRLEN];
    01348    for (x=1;x<s->inlen;x++) {
    01349       if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
    01350          /* Copy output data up to and including \r\n */
    01351          memcpy(output, s->inbuf, x + 1);
    01352          /* Add trailing \0 */
    01353          output[x+1] = '\0';
    01354          /* Move remaining data back to the front */
    01355          memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
    01356          s->inlen -= (x + 1);
    01357          return 1;
    01358       }
    01359    }
    01360    if (s->inlen >= sizeof(s->inbuf) - 1) {
    01361       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);
    01362       s->inlen = 0;
    01363    }
    01364    fds[0].fd = s->fd;
    01365    fds[0].events = POLLIN;
    01366    do {
    01367       res = poll(fds, 1, -1);
    01368       if (res < 0) {
    01369          if (errno == EINTR) {
    01370             if (s->dead)
    01371                return -1;
    01372             continue;
    01373          }
    01374          ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
    01375          return -1;
    01376       } else if (res > 0) {
    01377          ast_mutex_lock(&s->__lock);
    01378          res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
    01379          ast_mutex_unlock(&s->__lock);
    01380          if (res < 1)
    01381             return -1;
    01382          break;
    01383       }
    01384    } while(1);
    01385    s->inlen += res;
    01386    s->inbuf[s->inlen] = '\0';
    01387    return 0;
    01388 }
    01389
    01390 static void *session_do(void *data)
    01391 {
    01392    struct mansession *s = data;
    01393    struct message m;
    01394    char iabuf[INET_ADDRSTRLEN];
    01395    int res;
    01396
    01397    ast_mutex_lock(&s->__lock);
    01398    ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
    01399    ast_mutex_unlock(&s->__lock);
    01400    memset(&m, 0, sizeof(m));
    01401    for (;;) {
    01402       res = get_input(s, m.headers[m.hdrcount]);
    01403       if (res > 0) {
    01404          /* Strip trailing \r\n */
    01405          if (strlen(m.headers[m.hdrcount]) < 2)
    01406             continue;
    01407          m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
    01408          if (ast_strlen_zero(m.headers[m.hdrcount])) {
    01409             if (process_message(s, &m))
    01410                break;
    01411             memset(&m, 0, sizeof(m));
    01412          } else if (m.hdrcount < AST_MAX_MANHEADERS - 1)
    01413             m.hdrcount++;
    01414       } else if (res < 0)
    01415          break;
    01416    }
    01417    if (s->authenticated) {
    01418       if (option_verbose > 1) {
    01419          if (displayconnects)
    01420             ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
    01421       }
    01422       ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
    01423    } else {
    01424       if (option_verbose > 1) {
    01425          if ( displayconnects )
    01426             ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
    01427       }
    01428       ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
    01429    }
    01430    destroy_session(s);
    01431    return NULL;
    01432 }
    01433
    01434 static void *accept_thread(void *ignore)
    01435 {
    01436    int as;
    01437    struct sockaddr_in sin;
    01438    socklen_t sinlen;
    01439    struct mansession *s;
    01440    struct protoent *p;
    01441    int arg = 1;
    01442    int flags;
    01443    pthread_attr_t attr;
    01444
    01445    pthread_attr_init(&attr);
    01446    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    01447
    01448    for (;;) {
    01449       sinlen = sizeof(sin);
    01450       as = accept(asock, (struct sockaddr *)&sin, &sinlen);
    01451       if (as < 0) {
    01452          ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
    01453          continue;
    01454       }
    01455       p = getprotobyname("tcp");
    01456       if (p) {
    01457          if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
    01458             ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
    01459          }
    01460       }
    01461       s = malloc(sizeof(struct mansession));
    01462       if (!s) {
    01463          ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
    01464          continue;
    01465       }
    01466       memset(s, 0, sizeof(struct mansession));
    01467       memcpy(&s->sin, &sin, sizeof(sin));
    01468       s->writetimeout = 100;
    01469
    01470       if(! block_sockets) {
    01471          /* For safety, make sure socket is non-blocking */
    01472          flags = fcntl(as, F_GETFL);
    01473          fcntl(as, F_SETFL, flags | O_NONBLOCK);
    01474       }
    01475       ast_mutex_init(&s->__lock);
    01476       s->fd = as;
    01477       s->send_events = -1;
    01478       ast_mutex_lock(&sessionlock);
    01479       s->next = sessions;
    01480       sessions = s;
    01481       ast_mutex_unlock(&sessionlock);
    01482       if (ast_pthread_create(&s->t, &attr, session_do, s))
    01483          destroy_session(s);
    01484    }
    01485    pthread_attr_destroy(&attr);
    01486    return NULL;
    01487 }
    01488
    01489 static int append_event(struct mansession *s, const char *str)
    01490 {
    01491    struct eventqent *tmp, *prev=NULL;
    01492    tmp = malloc(sizeof(struct eventqent) + strlen(str));
    01493    if (tmp) {
    01494       tmp->next = NULL;
    01495       strcpy(tmp->eventdata, str);
    01496       if (s->eventq) {
    01497          prev = s->eventq;
    01498          while(prev->next)
    01499             prev = prev->next;
    01500          prev->next = tmp;
    01501       } else {
    01502          s->eventq = tmp;
    01503       }
    01504       return 0;
    01505    }
    01506    return -1;
    01507 }
    01508
    01509 /*! \brief  manager_event: Send AMI event to client */
    01510 int manager_event(int category, char *event, char *fmt, ...)
    01511 {
    01512    struct mansession *s;
    01513    char auth[80];
    01514    char tmp[4096] = "";
    01515    char *tmp_next = tmp;
    01516    size_t tmp_left = sizeof(tmp) - 2;
    01517    va_list ap;
    01518
    01519    ast_mutex_lock(&sessionlock);
    01520    for (s = sessions; s; s = s->next) {
    01521       if ((s->readperm & category) != category)
    01522          continue;
    01523
    01524       if ((s->send_events & category) != category)
    01525          continue;
    01526
    01527       if (ast_strlen_zero(tmp)) {
    01528          ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
    01529                 event, authority_to_str(category, auth, sizeof(auth)));
    01530          va_start(ap, fmt);
    01531          ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
    01532          va_end(ap);
    01533          *tmp_next++ = '\r';
    01534          *tmp_next++ = '\n';
    01535          *tmp_next = '\0';
    01536       }
    01537
    01538       ast_mutex_lock(&s->__lock);
    01539       if (s->busy) {
    01540          append_event(s, tmp);
    01541       } else if (!s->dead) {
    01542          if (ast_carefulwrite(s->fd, tmp, tmp_next - tmp, s->writetimeout) < 0) {
    01543             ast_log(LOG_WARNING, "Disconnecting slow (or gone) manager session!\n");
    01544             s->dead = 1;
    01545             pthread_kill(s->t, SIGURG);
    01546          }
    01547       }
    01548       ast_mutex_unlock(&s->__lock);
    01549    }
    01550    ast_mutex_unlock(&sessionlock);
    01551
    01552    return 0;
    01553 }
    01554
    01555 int ast_manager_unregister( char *action )
    01556 {
    01557    struct manager_action *cur = first_action, *prev = first_action;
    01558
    01559    ast_mutex_lock(&actionlock);
    01560    while( cur ) {
    01561       if (!strcasecmp(action, cur->action)) {
    01562          prev->next = cur->next;
    01563          free(cur);
    01564          if (option_verbose > 1)
    01565             ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
    01566          ast_mutex_unlock(&actionlock);
    01567          return 0;
    01568       }
    01569       prev = cur;
    01570       cur = cur->next;
    01571    }
    01572    ast_mutex_unlock(&actionlock);
    01573    return 0;
    01574 }
    01575
    01576 static int manager_state_cb(char *context, char *exten, int state, void *data)
    01577 {
    01578    /* Notify managers of change */
    01579    manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
    01580    return 0;
    01581 }
    01582
    01583 static int ast_manager_register_struct(struct manager_action *act)
    01584 {
    01585    struct manager_action *cur = first_action, *prev = NULL;
    01586    int ret;
    01587
    01588    ast_mutex_lock(&actionlock);
    01589    while(cur) { /* Walk the list of actions */
    01590       ret = strcasecmp(cur->action, act->action);
    01591       if (ret == 0) {
    01592          ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
    01593          ast_mutex_unlock(&actionlock);
    01594          return -1;
    01595       } else if (ret > 0) {
    01596          /* Insert these alphabetically */
    01597          if (prev) {
    01598             act->next = prev->next;
    01599             prev->next = act;
    01600          } else {
    01601             act->next = first_action;
    01602             first_action = act;
    01603          }
    01604          break;
    01605       }
    01606       prev = cur;
    01607       cur = cur->next;
    01608    }
    01609
    01610    if (!cur) {
    01611       if (prev)
    01612          prev->next = act;
    01613       else
    01614          first_action = act;
    01615       act->next = NULL;
    01616    }
    01617
    01618    if (option_verbose > 1)
    01619       ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
    01620    ast_mutex_unlock(&actionlock);
    01621    return 0;
    01622 }
    01623
    01624 /*! \brief register a new command with manager, including online help. This is
    01625    the preferred way to register a manager command */
    01626 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
    01627 {
    01628    struct manager_action *cur;
    01629
    01630    cur = malloc(sizeof(struct manager_action));
    01631    if (!cur) {
    01632       ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
    01633       return -1;
    01634    }
    01635    cur->action = action;
    01636    cur->authority = auth;
    01637    cur->func = func;
    01638    cur->synopsis = synopsis;
    01639    cur->description = description;
    01640    cur->next = NULL;
    01641
    01642    ast_manager_register_struct(cur);
    01643
    01644    return 0;
    01645 }
    01646 /*! @}
    01647  END Doxygen group */
    01648
    01649 static int registered = 0;
    01650
    01651 int init_manager(void)
    01652 {
    01653    struct ast_config *cfg;
    01654    char *val;
    01655    int oldportno = portno;
    01656    static struct sockaddr_in ba;
    01657    int x = 1;
    01658    if (!registered) {
    01659       /* Register default actions */
    01660       ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
    01661       ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
    01662       ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
    01663       ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
    01664       ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
    01665       ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
    01666       ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
    01667       ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
    01668       ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
    01669       ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
    01670       ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
    01671       ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
    01672       ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
    01673       ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
    01674       ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
    01675
    01676       ast_cli_register(&show_mancmd_cli);
    01677       ast_cli_register(&show_mancmds_cli);
    01678       ast_cli_register(&show_manconn_cli);
    01679       ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
    01680       registered = 1;
    01681    }
    01682    portno = DEFAULT_MANAGER_PORT;
    01683    displayconnects = 1;
    01684    cfg = ast_config_load("manager.conf");
    01685    if (!cfg) {
    01686       ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
    01687       return 0;
    01688    }
    01689    memset(&ba, 0, sizeof(ba));
    01690    val = ast_variable_retrieve(cfg, "general", "enabled");
    01691    if (val)
    01692       enabled = ast_true(val);
    01693
    01694    val = ast_variable_retrieve(cfg, "general", "block-sockets");
    01695    if(val)
    01696       block_sockets = ast_true(val);
    01697
    01698    if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
    01699       if (sscanf(val, "%5d", &portno) != 1) {
    01700          ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
    01701          portno = DEFAULT_MANAGER_PORT;
    01702       }
    01703    } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
    01704       if (sscanf(val, "%5d", &portno) != 1) {
    01705          ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
    01706          portno = DEFAULT_MANAGER_PORT;
    01707       }
    01708       ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated.  Please use 'port=%s' instead.\n", val);
    01709    }
    01710    /* Parsing the displayconnects */
    01711    if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) {
    01712          displayconnects = ast_true(val);;
    01713    }
    01714
    01715
    01716    ba.sin_family = AF_INET;
    01717    ba.sin_port = htons(portno);
    01718    memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
    01719
    01720    if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
    01721       if (!inet_aton(val, &ba.sin_addr)) {
    01722          ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
    01723          memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
    01724       }
    01725    }
    01726
    01727    if ((asock > -1) && ((portno != oldportno) || !enabled)) {
    01728 #if 0
    01729       /* Can't be done yet */
    01730       close(asock);
    01731       asock = -1;
    01732 #else
    01733       ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
    01734 #endif
    01735    }
    01736    ast_config_destroy(cfg);
    01737
    01738    /* If not enabled, do nothing */
    01739    if (!enabled) {
    01740       return 0;
    01741    }
    01742    if (asock < 0) {
    01743       asock = socket(AF_INET, SOCK_STREAM, 0);
    01744       if (asock < 0) {
    01745          ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
    01746          return -1;
    01747       }
    01748       setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
    01749       if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
    01750          ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
    01751          close(asock);
    01752          asock = -1;
    01753          return -1;
    01754       }
    01755       if (listen(asock, 2)) {
    01756          ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
    01757          close(asock);
    01758          asock = -1;
    01759          return -1;
    01760       }
    01761       if (option_verbose)
    01762          ast_verbose("Asterisk Management interface listening on port %d\n", portno);
    01763       ast_pthread_create(&t, NULL, accept_thread, NULL);
    01764    }
    01765    return 0;
    01766 }
    01767
    01768 int reload_manager(void)
    01769 {
    01770    manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
    01771    return init_manager();
    01772 }