Sat Nov 1 06:28:34 2008

Asterisk developer's documentation


manager.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, 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  * \author Mark Spencer <markster@digium.com>
00024  *
00025  * Channel Management and more
00026  * 
00027  * \ref amiconf
00028  */
00029 
00030 /*! \addtogroup Group_AMI AMI functions 
00031 */
00032 /*! @{ 
00033  Doxygen group */
00034 
00035 #include "asterisk.h"
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 150816 $")
00038 
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 #include <ctype.h>
00043 #include <sys/time.h>
00044 #include <sys/types.h>
00045 #include <netdb.h>
00046 #include <sys/socket.h>
00047 #include <netinet/in.h>
00048 #include <netinet/tcp.h>
00049 #include <arpa/inet.h>
00050 #include <signal.h>
00051 #include <errno.h>
00052 #include <unistd.h>
00053 
00054 #include "asterisk/channel.h"
00055 #include "asterisk/file.h"
00056 #include "asterisk/manager.h"
00057 #include "asterisk/config.h"
00058 #include "asterisk/callerid.h"
00059 #include "asterisk/lock.h"
00060 #include "asterisk/logger.h"
00061 #include "asterisk/options.h"
00062 #include "asterisk/cli.h"
00063 #include "asterisk/app.h"
00064 #include "asterisk/pbx.h"
00065 #include "asterisk/md5.h"
00066 #include "asterisk/acl.h"
00067 #include "asterisk/utils.h"
00068 #include "asterisk/http.h"
00069 #include "asterisk/threadstorage.h"
00070 #include "asterisk/linkedlists.h"
00071 #include "asterisk/term.h"
00072 #include "asterisk/astobj2.h"
00073 
00074 struct fast_originate_helper {
00075    char tech[AST_MAX_EXTENSION];
00076    char data[AST_MAX_EXTENSION];
00077    int timeout;
00078    int format;
00079    char app[AST_MAX_APP];
00080    char appdata[AST_MAX_EXTENSION];
00081    char cid_name[AST_MAX_EXTENSION];
00082    char cid_num[AST_MAX_EXTENSION];
00083    char context[AST_MAX_CONTEXT];
00084    char exten[AST_MAX_EXTENSION];
00085    char idtext[AST_MAX_EXTENSION];
00086    char account[AST_MAX_ACCOUNT_CODE];
00087    int priority;
00088    struct ast_variable *vars;
00089 };
00090 
00091 struct eventqent {
00092    int usecount;
00093    int category;
00094    struct eventqent *next;
00095    char eventdata[1];
00096 };
00097 
00098 static int enabled;
00099 static int portno = DEFAULT_MANAGER_PORT;
00100 static int asock = -1;
00101 static int displayconnects = 1;
00102 static int timestampevents;
00103 static int httptimeout = 60;
00104 
00105 static pthread_t t;
00106 static int block_sockets;
00107 static int num_sessions;
00108 
00109 /* Protected by the sessions list lock */
00110 struct eventqent *master_eventq = NULL;
00111 
00112 AST_THREADSTORAGE(manager_event_buf, manager_event_buf_init);
00113 #define MANAGER_EVENT_BUF_INITSIZE   256
00114 
00115 AST_THREADSTORAGE(astman_append_buf, astman_append_buf_init);
00116 #define ASTMAN_APPEND_BUF_INITSIZE   256
00117 
00118 static struct permalias {
00119    int num;
00120    char *label;
00121 } perms[] = {
00122    { EVENT_FLAG_SYSTEM, "system" },
00123    { EVENT_FLAG_CALL, "call" },
00124    { EVENT_FLAG_LOG, "log" },
00125    { EVENT_FLAG_VERBOSE, "verbose" },
00126    { EVENT_FLAG_COMMAND, "command" },
00127    { EVENT_FLAG_AGENT, "agent" },
00128    { EVENT_FLAG_USER, "user" },
00129    { EVENT_FLAG_CONFIG, "config" },
00130    { -1, "all" },
00131    { 0, "none" },
00132 };
00133 
00134 #define MAX_BLACKLIST_CMD_LEN 2
00135 static struct {
00136    char *words[AST_MAX_CMD_LEN];
00137 } command_blacklist[] = {
00138    {{ "module", "load", NULL }},
00139    {{ "module", "unload", NULL }},
00140 };
00141 
00142 struct mansession {
00143    /*! Execution thread */
00144    pthread_t t;
00145    /*! Thread lock -- don't use in action callbacks, it's already taken care of  */
00146    ast_mutex_t __lock;
00147    /*! socket address */
00148    struct sockaddr_in sin;
00149    /*! TCP socket */
00150    int fd;
00151    /*! Whether an HTTP manager is in use */
00152    int inuse;
00153    /*! Whether an HTTP session should be destroyed */
00154    int needdestroy;
00155    /*! Whether an HTTP session has someone waiting on events */
00156    pthread_t waiting_thread;
00157    /*! Unique manager identifer */
00158    uint32_t managerid;
00159    /*! Session timeout if HTTP */
00160    time_t sessiontimeout;
00161    /*! Output from manager interface */
00162    struct ast_dynamic_str *outputstr;
00163    /*! Logged in username */
00164    char username[80];
00165    /*! Authentication challenge */
00166    char challenge[10];
00167    /*! Authentication status */
00168    int authenticated;
00169    /*! Authorization for reading */
00170    int readperm;
00171    /*! Authorization for writing */
00172    int writeperm;
00173    /*! Buffer */
00174    char inbuf[1024];
00175    int inlen;
00176    int send_events;
00177    int displaysystemname;     /*!< Add system name to manager responses and events */
00178    /* Queued events that we've not had the ability to send yet */
00179    struct eventqent *eventq;
00180    /* Timeout for ast_carefulwrite() */
00181    int writetimeout;
00182    int pending_event;         /*!< Pending events indicator in case when waiting_thread is NULL */
00183    AST_LIST_ENTRY(mansession) list;
00184 };
00185 
00186 static AST_LIST_HEAD_STATIC(sessions, mansession);
00187 
00188 struct ast_manager_user {
00189    char username[80];
00190    char *secret;
00191    char *deny;
00192    char *permit;
00193    char *read;
00194    char *write;
00195    unsigned int displayconnects:1;
00196    int keep;
00197    AST_LIST_ENTRY(ast_manager_user) list;
00198 };
00199 
00200 static AST_LIST_HEAD_STATIC(users, ast_manager_user);
00201 
00202 static struct manager_action *first_action;
00203 AST_RWLOCK_DEFINE_STATIC(actionlock);
00204 
00205 /*! \brief Convert authority code to string with serveral options */
00206 static char *authority_to_str(int authority, char *res, int reslen)
00207 {
00208    int running_total = 0, i;
00209 
00210    memset(res, 0, reslen);
00211    for (i = 0; i < (sizeof(perms) / sizeof(perms[0])) - 1; i++) {
00212       if (authority & perms[i].num) {
00213          if (*res) {
00214             strncat(res, ",", (reslen > running_total) ? reslen - running_total - 1 : 0);
00215             running_total++;
00216          }
00217          strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total - 1 : 0);
00218          running_total += strlen(perms[i].label);
00219       }
00220    }
00221 
00222    if (ast_strlen_zero(res))
00223       ast_copy_string(res, "<none>", reslen);
00224    
00225    return res;
00226 }
00227 
00228 static char *complete_show_mancmd(const char *line, const char *word, int pos, int state)
00229 {
00230    struct manager_action *cur;
00231    int which = 0;
00232    char *ret = NULL;
00233 
00234    ast_rwlock_rdlock(&actionlock);
00235    for (cur = first_action; cur; cur = cur->next) { /* Walk the list of actions */
00236       if (!strncasecmp(word, cur->action, strlen(word)) && ++which > state) {
00237          ret = ast_strdup(cur->action);
00238          break;   /* make sure we exit even if ast_strdup() returns NULL */
00239       }
00240    }
00241    ast_rwlock_unlock(&actionlock);
00242 
00243    return ret;
00244 }
00245 
00246 static void xml_copy_escape(char **dst, size_t *maxlen, const char *src, int lower)
00247 {
00248    while (*src && (*maxlen > 6)) {
00249       switch (*src) {
00250       case '<':
00251          strcpy(*dst, "&lt;");
00252          (*dst) += 4;
00253          *maxlen -= 4;
00254          break;
00255       case '>':
00256          strcpy(*dst, "&gt;");
00257          (*dst) += 4;
00258          *maxlen -= 4;
00259          break;
00260       case '\"':
00261          strcpy(*dst, "&quot;");
00262          (*dst) += 6;
00263          *maxlen -= 6;
00264          break;
00265       case '\'':
00266          strcpy(*dst, "&apos;");
00267          (*dst) += 6;
00268          *maxlen -= 6;
00269          break;
00270       case '&':
00271          strcpy(*dst, "&amp;");
00272          (*dst) += 5;
00273          *maxlen -= 5;
00274          break;      
00275       default:
00276          *(*dst)++ = lower ? tolower(*src) : *src;
00277          (*maxlen)--;
00278       }
00279       src++;
00280    }
00281 }
00282 
00283 struct variable_count {
00284    char *varname;
00285    int count;
00286 };
00287 
00288 static int compress_char(char c)
00289 {
00290    c &= 0x7f;
00291    if (c < 32)
00292       return 0;
00293    else if (c >= 'a' && c <= 'z')
00294       return c - 64;
00295    else if (c > 'z')
00296       return '_';
00297    else
00298       return c - 32;
00299 }
00300 
00301 static int variable_count_hash_fn(const void *vvc, const int flags)
00302 {
00303    const struct variable_count *vc = vvc;
00304    int res = 0, i;
00305    for (i = 0; i < 5; i++) {
00306       if (vc->varname[i] == '\0')
00307          break;
00308       res += compress_char(vc->varname[i]) << (i * 6);
00309    }
00310    return res;
00311 }
00312 
00313 static int variable_count_cmp_fn(void *obj, void *vstr, int flags)
00314 {
00315    /* Due to the simplicity of struct variable_count, it makes no difference
00316     * if you pass in objects or strings, the same operation applies. This is
00317     * due to the fact that the hash occurs on the first element, which means
00318     * the address of both the struct and the string are exactly the same. */
00319    struct variable_count *vc = obj;
00320    char *str = vstr;
00321    return !strcmp(vc->varname, str) ? CMP_MATCH | CMP_STOP : 0;
00322 }
00323 
00324 static char *xml_translate(char *in, struct ast_variable *vars)
00325 {
00326    struct ast_variable *v;
00327    char *dest = NULL;
00328    char *out, *tmp, *var, *val;
00329    char *objtype = NULL;
00330    int colons = 0;
00331    int breaks = 0;
00332    size_t len;
00333    int count = 1;
00334    int escaped = 0;
00335    int inobj = 0;
00336    int x;
00337    struct variable_count *vc = NULL;
00338    struct ao2_container *vco = NULL;
00339 
00340    for (v = vars; v; v = v->next) {
00341       if (!dest && !strcasecmp(v->name, "ajaxdest"))
00342          dest = v->value;
00343       else if (!objtype && !strcasecmp(v->name, "ajaxobjtype")) 
00344          objtype = v->value;
00345    }
00346    if (!dest)
00347       dest = "unknown";
00348    if (!objtype)
00349       objtype = "generic";
00350    for (x = 0; in[x]; x++) {
00351       if (in[x] == ':')
00352          colons++;
00353       else if (in[x] == '\n')
00354          breaks++;
00355       else if (strchr("&\"<>\'", in[x]))
00356          escaped++;
00357    }
00358    len = (size_t) (strlen(in) + colons * 5 + breaks * (40 + strlen(dest) + strlen(objtype)) + escaped * 10); /* foo="bar", "<response type=\"object\" id=\"dest\"", "&amp;" */
00359    out = ast_malloc(len);
00360    if (!out)
00361       return 0;
00362    tmp = out;
00363    while (*in) {
00364       var = in;
00365       while (*in && (*in >= 32))
00366          in++;
00367       if (*in) {
00368          if ((count > 3) && inobj) {
00369             ast_build_string(&tmp, &len, " /></response>\n");
00370             inobj = 0;
00371 
00372             /* Entity is closed, so close out the name cache */
00373             ao2_ref(vco, -1);
00374             vco = NULL;
00375          }
00376          count = 0;
00377          while (*in && (*in < 32)) {
00378             *in = '\0';
00379             in++;
00380             count++;
00381          }
00382          val = strchr(var, ':');
00383          if (val) {
00384             *val = '\0';
00385             val++;
00386             if (*val == ' ')
00387                val++;
00388             if (!inobj) {
00389                vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
00390                ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype);
00391                inobj = 1;
00392             }
00393 
00394             /* Check if the var has been used already */
00395             if ((vc = ao2_find(vco, var, 0)))
00396                vc->count++;
00397             else {
00398                /* Create a new entry for this one */
00399                vc = ao2_alloc(sizeof(*vc), NULL);
00400                vc->varname = var;
00401                vc->count = 1;
00402                ao2_link(vco, vc);
00403             }
00404 
00405             ast_build_string(&tmp, &len, " ");
00406             xml_copy_escape(&tmp, &len, var, 1);
00407             if (vc->count > 1)
00408                ast_build_string(&tmp, &len, "-%d", vc->count);
00409             ast_build_string(&tmp, &len, "='");
00410             xml_copy_escape(&tmp, &len, val, 0);
00411             ast_build_string(&tmp, &len, "'");
00412             ao2_ref(vc, -1);
00413          }
00414       }
00415    }
00416    if (inobj)
00417       ast_build_string(&tmp, &len, " /></response>\n");
00418    if (vco)
00419       ao2_ref(vco, -1);
00420    return out;
00421 }
00422 
00423 static char *html_translate(char *in)
00424 {
00425    int x;
00426    int colons = 0;
00427    int breaks = 0;
00428    size_t len;
00429    int count = 1;
00430    char *tmp, *var, *val, *out;
00431 
00432    for (x=0; in[x]; x++) {
00433       if (in[x] == ':')
00434          colons++;
00435       if (in[x] == '\n')
00436          breaks++;
00437    }
00438    len = strlen(in) + colons * 40 + breaks * 40; /* <tr><td></td><td></td></tr>, "<tr><td colspan=\"2\"><hr></td></tr> */
00439    out = ast_malloc(len);
00440    if (!out)
00441       return 0;
00442    tmp = out;
00443    while (*in) {
00444       var = in;
00445       while (*in && (*in >= 32))
00446          in++;
00447       if (*in) {
00448          if ((count % 4) == 0){
00449             ast_build_string(&tmp, &len, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00450          }
00451          count = 0;
00452          while (*in && (*in < 32)) {
00453             *in = '\0';
00454             in++;
00455             count++;
00456          }
00457          val = strchr(var, ':');
00458          if (val) {
00459             *val = '\0';
00460             val++;
00461             if (*val == ' ')
00462                val++;
00463             ast_build_string(&tmp, &len, "<tr><td>%s</td><td>%s</td></tr>\r\n", var, val);
00464          }
00465       }
00466    }
00467    return out;
00468 }
00469 
00470 
00471 
00472 static struct ast_manager_user *ast_get_manager_by_name_locked(const char *name)
00473 {
00474    struct ast_manager_user *user = NULL;
00475 
00476    AST_LIST_TRAVERSE(&users, user, list)
00477       if (!strcasecmp(user->username, name))
00478          break;
00479    return user;
00480 }
00481 
00482 void astman_append(struct mansession *s, const char *fmt, ...)
00483 {
00484    va_list ap;
00485    struct ast_dynamic_str *buf;
00486 
00487    ast_mutex_lock(&s->__lock);
00488 
00489    if (!(buf = ast_dynamic_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
00490       ast_mutex_unlock(&s->__lock);
00491       return;
00492    }
00493 
00494    va_start(ap, fmt);
00495    ast_dynamic_str_thread_set_va(&buf, 0, &astman_append_buf, fmt, ap);
00496    va_end(ap);
00497    
00498    if (s->fd > -1)
00499       ast_carefulwrite(s->fd, buf->str, strlen(buf->str), s->writetimeout);
00500    else {
00501       if (!s->outputstr && !(s->outputstr = ast_calloc(1, sizeof(*s->outputstr)))) {
00502          ast_mutex_unlock(&s->__lock);
00503          return;
00504       }
00505 
00506       ast_dynamic_str_append(&s->outputstr, 0, "%s", buf->str);   
00507    }
00508 
00509    ast_mutex_unlock(&s->__lock);
00510 }
00511 
00512 static int handle_showmancmd(int fd, int argc, char *argv[])
00513 {
00514    struct manager_action *cur;
00515    char authority[80];
00516    int num;
00517 
00518    if (argc != 4)
00519       return RESULT_SHOWUSAGE;
00520 
00521    ast_rwlock_rdlock(&actionlock);
00522    for (cur = first_action; cur; cur = cur->next) { /* Walk the list of actions */
00523       for (num = 3; num < argc; num++) {
00524          if (!strcasecmp(cur->action, argv[num])) {
00525             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 : "");
00526          }
00527       }
00528    }
00529    ast_rwlock_unlock(&actionlock);
00530 
00531    return RESULT_SUCCESS;
00532 }
00533 
00534 static int handle_showmanager(int fd, int argc, char *argv[])
00535 {
00536    struct ast_manager_user *user = NULL;
00537 
00538    if (argc != 4)
00539       return RESULT_SHOWUSAGE;
00540 
00541    AST_LIST_LOCK(&users);
00542 
00543    if (!(user = ast_get_manager_by_name_locked(argv[3]))) {
00544       ast_cli(fd, "There is no manager called %s\n", argv[3]);
00545       AST_LIST_UNLOCK(&users);
00546       return -1;
00547    }
00548 
00549    ast_cli(fd,"\n");
00550    ast_cli(fd,
00551       "       username: %s\n"
00552       "         secret: %s\n"
00553       "           deny: %s\n"
00554       "         permit: %s\n"
00555       "           read: %s\n"
00556       "          write: %s\n"
00557       "displayconnects: %s\n",
00558       (user->username ? user->username : "(N/A)"),
00559       (user->secret ? "<Set>" : "(N/A)"),
00560       (user->deny ? user->deny : "(N/A)"),
00561       (user->permit ? user->permit : "(N/A)"),
00562       (user->read ? user->read : "(N/A)"),
00563       (user->write ? user->write : "(N/A)"),
00564       (user->displayconnects ? "yes" : "no"));
00565 
00566    AST_LIST_UNLOCK(&users);
00567 
00568    return RESULT_SUCCESS;
00569 }
00570 
00571 
00572 static int handle_showmanagers(int fd, int argc, char *argv[])
00573 {
00574    struct ast_manager_user *user = NULL;
00575    int count_amu = 0;
00576 
00577    if (argc != 3)
00578       return RESULT_SHOWUSAGE;
00579 
00580    AST_LIST_LOCK(&users);
00581 
00582    /* If there are no users, print out something along those lines */
00583    if (AST_LIST_EMPTY(&users)) {
00584       ast_cli(fd, "There are no manager users.\n");
00585       AST_LIST_UNLOCK(&users);
00586       return RESULT_SUCCESS;
00587    }
00588 
00589    ast_cli(fd, "\nusername\n--------\n");
00590 
00591    AST_LIST_TRAVERSE(&users, user, list) {
00592       ast_cli(fd, "%s\n", user->username);
00593       count_amu++;
00594    }
00595 
00596    AST_LIST_UNLOCK(&users);
00597 
00598    ast_cli(fd,"-------------------\n");
00599    ast_cli(fd,"%d manager users configured.\n", count_amu);
00600 
00601    return RESULT_SUCCESS;
00602 }
00603 
00604 
00605 /*! \brief  CLI command 
00606    Should change to "manager show commands" */
00607 static int handle_showmancmds(int fd, int argc, char *argv[])
00608 {
00609    struct manager_action *cur;
00610    char authority[80];
00611    char *format = "  %-15.15s  %-15.15s  %-55.55s\n";
00612 
00613    ast_cli(fd, format, "Action", "Privilege", "Synopsis");
00614    ast_cli(fd, format, "------", "---------", "--------");
00615    
00616    ast_rwlock_rdlock(&actionlock);
00617    for (cur = first_action; cur; cur = cur->next) /* Walk the list of actions */
00618       ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
00619    ast_rwlock_unlock(&actionlock);
00620    
00621    return RESULT_SUCCESS;
00622 }
00623 
00624 /*! \brief CLI command show manager connected */
00625 /* Should change to "manager show connected" */
00626 static int handle_showmanconn(int fd, int argc, char *argv[])
00627 {
00628    struct mansession *s;
00629    char *format = "  %-15.15s  %-15.15s\n";
00630 
00631    ast_cli(fd, format, "Username", "IP Address");
00632    
00633    AST_LIST_LOCK(&sessions);
00634    AST_LIST_TRAVERSE(&sessions, s, list)
00635       ast_cli(fd, format,s->username, ast_inet_ntoa(s->sin.sin_addr));
00636    AST_LIST_UNLOCK(&sessions);
00637 
00638    return RESULT_SUCCESS;
00639 }
00640 
00641 /*! \brief CLI command show manager connected */
00642 /* Should change to "manager show connected" */
00643 static int handle_showmaneventq(int fd, int argc, char *argv[])
00644 {
00645    struct eventqent *s;
00646 
00647    AST_LIST_LOCK(&sessions);
00648    for (s = master_eventq; s; s = s->next) {
00649       ast_cli(fd, "Usecount: %d\n",s->usecount);
00650       ast_cli(fd, "Category: %d\n", s->category);
00651       ast_cli(fd, "Event:\n%s", s->eventdata);
00652    }
00653    AST_LIST_UNLOCK(&sessions);
00654 
00655    return RESULT_SUCCESS;
00656 }
00657 
00658 static char showmancmd_help[] = 
00659 "Usage: manager show command <actionname>\n"
00660 "  Shows the detailed description for a specific Asterisk manager interface command.\n";
00661 
00662 static char showmancmds_help[] = 
00663 "Usage: manager show commands\n"
00664 "  Prints a listing of all the available Asterisk manager interface commands.\n";
00665 
00666 static char showmanconn_help[] = 
00667 "Usage: manager show connected\n"
00668 "  Prints a listing of the users that are currently connected to the\n"
00669 "Asterisk manager interface.\n";
00670 
00671 static char showmaneventq_help[] = 
00672 "Usage: manager show eventq\n"
00673 "  Prints a listing of all events pending in the Asterisk manger\n"
00674 "event queue.\n";
00675 
00676 static char showmanagers_help[] =
00677 "Usage: manager show users\n"
00678 "       Prints a listing of all managers that are currently configured on that\n"
00679 " system.\n";
00680 
00681 static char showmanager_help[] =
00682 " Usage: manager show user <user>\n"
00683 "        Display all information related to the manager user specified.\n";
00684 
00685 static struct ast_cli_entry cli_show_manager_command_deprecated = {
00686    { "show", "manager", "command", NULL },
00687    handle_showmancmd, NULL,
00688    NULL, complete_show_mancmd };
00689 
00690 static struct ast_cli_entry cli_show_manager_commands_deprecated = {
00691    { "show", "manager", "commands", NULL },
00692    handle_showmancmds, NULL,
00693    NULL };
00694 
00695 static struct ast_cli_entry cli_show_manager_connected_deprecated = {
00696    { "show", "manager", "connected", NULL },
00697    handle_showmanconn, NULL,
00698    NULL };
00699 
00700 static struct ast_cli_entry cli_show_manager_eventq_deprecated = {
00701    { "show", "manager", "eventq", NULL },
00702    handle_showmaneventq, NULL,
00703    NULL };
00704 
00705 static struct ast_cli_entry cli_manager[] = {
00706    { { "manager", "show", "command", NULL },
00707    handle_showmancmd, "Show a manager interface command",
00708    showmancmd_help, complete_show_mancmd, &cli_show_manager_command_deprecated },
00709 
00710    { { "manager", "show", "commands", NULL },
00711    handle_showmancmds, "List manager interface commands",
00712    showmancmds_help, NULL, &cli_show_manager_commands_deprecated },
00713 
00714    { { "manager", "show", "connected", NULL },
00715    handle_showmanconn, "List connected manager interface users",
00716    showmanconn_help, NULL, &cli_show_manager_connected_deprecated },
00717 
00718    { { "manager", "show", "eventq", NULL },
00719    handle_showmaneventq, "List manager interface queued events",
00720    showmaneventq_help, NULL, &cli_show_manager_eventq_deprecated },
00721 
00722    { { "manager", "show", "users", NULL },
00723    handle_showmanagers, "List configured manager users",
00724    showmanagers_help, NULL, NULL },
00725 
00726    { { "manager", "show", "user", NULL },
00727    handle_showmanager, "Display information on a specific manager user",
00728    showmanager_help, NULL, NULL },
00729 };
00730 
00731 static void unuse_eventqent(struct eventqent *e)
00732 {
00733    if (ast_atomic_dec_and_test(&e->usecount) && e->next)
00734       pthread_kill(t, SIGURG);
00735 }
00736 
00737 static void free_session(struct mansession *s)
00738 {
00739    struct eventqent *eqe;
00740    if (s->fd > -1)
00741       close(s->fd);
00742    if (s->outputstr)
00743       free(s->outputstr);
00744    ast_mutex_destroy(&s->__lock);
00745    while (s->eventq) {
00746       eqe = s->eventq;
00747       s->eventq = s->eventq->next;
00748       unuse_eventqent(eqe);
00749    }
00750    free(s);
00751 }
00752 
00753 static void destroy_session(struct mansession *s)
00754 {
00755    AST_LIST_LOCK(&sessions);
00756    AST_LIST_REMOVE(&sessions, s, list);
00757    num_sessions--;
00758    free_session(s);
00759    AST_LIST_UNLOCK(&sessions);
00760 }
00761 
00762 const char *astman_get_header(const struct message *m, char *var)
00763 {
00764    char cmp[80];
00765    int x;
00766 
00767    snprintf(cmp, sizeof(cmp), "%s: ", var);
00768 
00769    for (x = 0; x < m->hdrcount; x++) {
00770       if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
00771          return m->headers[x] + strlen(cmp);
00772    }
00773 
00774    return "";
00775 }
00776 
00777 struct ast_variable *astman_get_variables(const struct message *m)
00778 {
00779    int varlen, x, y;
00780    struct ast_variable *head = NULL, *cur;
00781    char *var, *val;
00782 
00783    char *parse;    
00784    AST_DECLARE_APP_ARGS(args,
00785       AST_APP_ARG(vars)[32];
00786    );
00787 
00788    varlen = strlen("Variable: ");   
00789 
00790    for (x = 0; x < m->hdrcount; x++) {
00791       if (strncasecmp("Variable: ", m->headers[x], varlen))
00792          continue;
00793 
00794       parse = ast_strdupa(m->headers[x] + varlen);
00795 
00796       AST_STANDARD_APP_ARGS(args, parse);
00797       if (args.argc) {
00798          for (y = 0; y < args.argc; y++) {
00799             if (!args.vars[y])
00800                continue;
00801             var = val = ast_strdupa(args.vars[y]);
00802             strsep(&val, "=");
00803             if (!val || ast_strlen_zero(var))
00804                continue;
00805             cur = ast_variable_new(var, val);
00806             if (head) {
00807                cur->next = head;
00808                head = cur;
00809             } else
00810                head = cur;
00811          }
00812       }
00813    }
00814 
00815    return head;
00816 }
00817 
00818 /*! \note NOTE:
00819    Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
00820    hold the session lock _or_ be running in an action callback (in which case s->busy will
00821    be non-zero). In either of these cases, there is no need to lock-protect the session's
00822    fd, since no other output will be sent (events will be queued), and no input will
00823    be read until either the current action finishes or get_input() obtains the session
00824    lock.
00825  */
00826 void astman_send_error(struct mansession *s, const struct message *m, char *error)
00827 {
00828    const char *id = astman_get_header(m,"ActionID");
00829 
00830    astman_append(s, "Response: Error\r\n");
00831    if (!ast_strlen_zero(id))
00832       astman_append(s, "ActionID: %s\r\n", id);
00833    astman_append(s, "Message: %s\r\n\r\n", error);
00834 }
00835 
00836 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
00837 {
00838    const char *id = astman_get_header(m,"ActionID");
00839 
00840    astman_append(s, "Response: %s\r\n", resp);
00841    if (!ast_strlen_zero(id))
00842       astman_append(s, "ActionID: %s\r\n", id);
00843    if (msg)
00844       astman_append(s, "Message: %s\r\n\r\n", msg);
00845    else
00846       astman_append(s, "\r\n");
00847 }
00848 
00849 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
00850 {
00851    astman_send_response(s, m, "Success", msg);
00852 }
00853 
00854 /*! Tells you if smallstr exists inside bigstr
00855    which is delim by delim and uses no buf or stringsep
00856    ast_instring("this|that|more","this",',') == 1;
00857 
00858    feel free to move this to app.c -anthm */
00859 static int ast_instring(const char *bigstr, const char *smallstr, char delim) 
00860 {
00861    const char *val = bigstr, *next;
00862 
00863    do {
00864       if ((next = strchr(val, delim))) {
00865          if (!strncmp(val, smallstr, (next - val)))
00866             return 1;
00867          else
00868             continue;
00869       } else
00870          return !strcmp(smallstr, val);
00871 
00872    } while (*(val = (next + 1)));
00873 
00874    return 0;
00875 }
00876 
00877 static int get_perm(const char *instr)
00878 {
00879    int x = 0, ret = 0;
00880 
00881    if (!instr)
00882       return 0;
00883 
00884    for (x = 0; x < (sizeof(perms) / sizeof(perms[0])); x++) {
00885       if (ast_instring(instr, perms[x].label, ','))
00886          ret |= perms[x].num;
00887    }
00888    
00889    return ret;
00890 }
00891 
00892 static int ast_is_number(const char *string) 
00893 {
00894    int ret = 1, x = 0;
00895 
00896    if (!string)
00897       return 0;
00898 
00899    for (x = 0; x < strlen(string); x++) {
00900       if (!(string[x] >= 48 && string[x] <= 57)) {
00901          ret = 0;
00902          break;
00903       }
00904    }
00905    
00906    return ret ? atoi(string) : 0;
00907 }
00908 
00909 static int strings_to_mask(const char *string) 
00910 {
00911    int x, ret = -1;
00912    
00913    x = ast_is_number(string);
00914 
00915    if (x)
00916       ret = x;
00917    else if (ast_strlen_zero(string))
00918       ret = -1;
00919    else if (ast_false(string))
00920       ret = 0;
00921    else if (ast_true(string)) {
00922       ret = 0;
00923       for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
00924          ret |= perms[x].num;    
00925    } else {
00926       ret = 0;
00927       for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
00928          if (ast_instring(string, perms[x].label, ',')) 
00929             ret |= perms[x].num;    
00930       }
00931    }
00932 
00933    return ret;
00934 }
00935 
00936 /*! \brief
00937    Rather than braindead on,off this now can also accept a specific int mask value 
00938    or a ',' delim list of mask strings (the same as manager.conf) -anthm
00939 */
00940 static int set_eventmask(struct mansession *s, const char *eventmask)
00941 {
00942    int maskint = strings_to_mask(eventmask);
00943 
00944    ast_mutex_lock(&s->__lock);
00945    if (maskint >= 0) 
00946       s->send_events = maskint;
00947    ast_mutex_unlock(&s->__lock);
00948    
00949    return maskint;
00950 }
00951 
00952 static int authenticate(struct mansession *s, const struct message *m)
00953 {
00954    struct ast_config *cfg;
00955    char *cat;
00956    const char *user = astman_get_header(m, "Username");
00957    const char *pass = astman_get_header(m, "Secret");
00958    const char *authtype = astman_get_header(m, "AuthType");
00959    const char *key = astman_get_header(m, "Key");
00960    const char *events = astman_get_header(m, "Events");
00961    
00962    cfg = ast_config_load("manager.conf");
00963    if (!cfg)
00964       return -1;
00965    cat = ast_category_browse(cfg, NULL);
00966    while (cat) {
00967       if (strcasecmp(cat, "general")) {
00968          /* This is a user */
00969          if (!strcasecmp(cat, user)) {
00970             struct ast_variable *v;
00971             struct ast_ha *ha = NULL;
00972             char *password = NULL;
00973 
00974             for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
00975                if (!strcasecmp(v->name, "secret")) {
00976                   password = v->value;
00977                } else if (!strcasecmp(v->name, "displaysystemname")) {
00978                   if (ast_true(v->value)) {
00979                      if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
00980                         s->displaysystemname = 1;
00981                      } else {
00982                         ast_log(LOG_ERROR, "Can't enable displaysystemname in manager.conf - no system name configured in asterisk.conf\n");
00983                      }
00984