00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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
00072 struct fast_originate_helper {
00073 char tech[AST_MAX_EXTENSION];
00074 char data[AST_MAX_EXTENSION];
00075 int timeout;
00076 char app[AST_MAX_APP];
00077 char appdata[AST_MAX_EXTENSION];
00078 char cid_name[AST_MAX_EXTENSION];
00079 char cid_num[AST_MAX_EXTENSION];
00080 char context[AST_MAX_CONTEXT];
00081 char exten[AST_MAX_EXTENSION];
00082 char idtext[AST_MAX_EXTENSION];
00083 char account[AST_MAX_ACCOUNT_CODE];
00084 int priority;
00085 struct ast_variable *vars;
00086 };
00087
00088 struct eventqent {
00089 int usecount;
00090 int category;
00091 struct eventqent *next;
00092 char eventdata[1];
00093 };
00094
00095 static int enabled;
00096 static int portno = DEFAULT_MANAGER_PORT;
00097 static int asock = -1;
00098 static int displayconnects = 1;
00099 static int timestampevents;
00100 static int httptimeout = 60;
00101
00102 static pthread_t t;
00103 static int block_sockets;
00104 static int num_sessions;
00105
00106
00107 struct eventqent *master_eventq = NULL;
00108
00109 AST_THREADSTORAGE(manager_event_buf, manager_event_buf_init);
00110 #define MANAGER_EVENT_BUF_INITSIZE 256
00111
00112 AST_THREADSTORAGE(astman_append_buf, astman_append_buf_init);
00113 #define ASTMAN_APPEND_BUF_INITSIZE 256
00114
00115 static struct permalias {
00116 int num;
00117 char *label;
00118 } perms[] = {
00119 { EVENT_FLAG_SYSTEM, "system" },
00120 { EVENT_FLAG_CALL, "call" },
00121 { EVENT_FLAG_LOG, "log" },
00122 { EVENT_FLAG_VERBOSE, "verbose" },
00123 { EVENT_FLAG_COMMAND, "command" },
00124 { EVENT_FLAG_AGENT, "agent" },
00125 { EVENT_FLAG_USER, "user" },
00126 { EVENT_FLAG_CONFIG, "config" },
00127 { -1, "all" },
00128 { 0, "none" },
00129 };
00130
00131 struct mansession {
00132
00133 pthread_t t;
00134
00135 ast_mutex_t __lock;
00136
00137 struct sockaddr_in sin;
00138
00139 int fd;
00140
00141 int inuse;
00142
00143 int needdestroy;
00144
00145 pthread_t waiting_thread;
00146
00147 unsigned long managerid;
00148
00149 time_t sessiontimeout;
00150
00151 struct ast_dynamic_str *outputstr;
00152
00153 char username[80];
00154
00155 char challenge[10];
00156
00157 int authenticated;
00158
00159 int readperm;
00160
00161 int writeperm;
00162
00163 char inbuf[1024];
00164 int inlen;
00165 int send_events;
00166 int displaysystemname;
00167
00168 struct eventqent *eventq;
00169
00170 int writetimeout;
00171 AST_LIST_ENTRY(mansession) list;
00172 };
00173
00174 static AST_LIST_HEAD_STATIC(sessions, mansession);
00175
00176 struct ast_manager_user {
00177 char username[80];
00178 char *secret;
00179 char *deny;
00180 char *permit;
00181 char *read;
00182 char *write;
00183 unsigned int displayconnects:1;
00184 int keep;
00185 AST_LIST_ENTRY(ast_manager_user) list;
00186 };
00187
00188 static AST_LIST_HEAD_STATIC(users, ast_manager_user);
00189
00190 static struct manager_action *first_action;
00191 AST_RWLOCK_DEFINE_STATIC(actionlock);
00192
00193
00194 static char *authority_to_str(int authority, char *res, int reslen)
00195 {
00196 int running_total = 0, i;
00197
00198 memset(res, 0, reslen);
00199 for (i = 0; i < (sizeof(perms) / sizeof(perms[0])) - 1; i++) {
00200 if (authority & perms[i].num) {
00201 if (*res) {
00202 strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
00203 running_total++;
00204 }
00205 strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
00206 running_total += strlen(perms[i].label);
00207 }
00208 }
00209
00210 if (ast_strlen_zero(res))
00211 ast_copy_string(res, "<none>", reslen);
00212
00213 return res;
00214 }
00215
00216 static char *complete_show_mancmd(const char *line, const char *word, int pos, int state)
00217 {
00218 struct manager_action *cur;
00219 int which = 0;
00220 char *ret = NULL;
00221
00222 ast_rwlock_rdlock(&actionlock);
00223 for (cur = first_action; cur; cur = cur->next) {
00224 if (!strncasecmp(word, cur->action, strlen(word)) && ++which > state) {
00225 ret = ast_strdup(cur->action);
00226 break;
00227 }
00228 }
00229 ast_rwlock_unlock(&actionlock);
00230
00231 return ret;
00232 }
00233
00234 static void xml_copy_escape(char **dst, size_t *maxlen, const char *src, int lower)
00235 {
00236 while (*src && (*maxlen > 6)) {
00237 switch (*src) {
00238 case '<':
00239 strcpy(*dst, "<");
00240 (*dst) += 4;
00241 *maxlen -= 4;
00242 break;
00243 case '>':
00244 strcpy(*dst, ">");
00245 (*dst) += 4;
00246 *maxlen -= 4;
00247 break;
00248 case '\"':
00249 strcpy(*dst, """);
00250 (*dst) += 6;
00251 *maxlen -= 6;
00252 break;
00253 case '\'':
00254 strcpy(*dst, "'");
00255 (*dst) += 6;
00256 *maxlen -= 6;
00257 break;
00258 case '&':
00259 strcpy(*dst, "&");
00260 (*dst) += 5;
00261 *maxlen -= 5;
00262 break;
00263 default:
00264 *(*dst)++ = lower ? tolower(*src) : *src;
00265 (*maxlen)--;
00266 }
00267 src++;
00268 }
00269 }
00270
00271 static char *xml_translate(char *in, struct ast_variable *vars)
00272 {
00273 struct ast_variable *v;
00274 char *dest = NULL;
00275 char *out, *tmp, *var, *val;
00276 char *objtype = NULL;
00277 int colons = 0;
00278 int breaks = 0;
00279 size_t len;
00280 int count = 1;
00281 int escaped = 0;
00282 int inobj = 0;
00283 int x;
00284
00285 for (v = vars; v; v = v->next) {
00286 if (!dest && !strcasecmp(v->name, "ajaxdest"))
00287 dest = v->value;
00288 else if (!objtype && !strcasecmp(v->name, "ajaxobjtype"))
00289 objtype = v->value;
00290 }
00291 if (!dest)
00292 dest = "unknown";
00293 if (!objtype)
00294 objtype = "generic";
00295 for (x = 0; in[x]; x++) {
00296 if (in[x] == ':')
00297 colons++;
00298 else if (in[x] == '\n')
00299 breaks++;
00300 else if (strchr("&\"<>", in[x]))
00301 escaped++;
00302 }
00303 len = (size_t) (strlen(in) + colons * 5 + breaks * (40 + strlen(dest) + strlen(objtype)) + escaped * 10);
00304 out = ast_malloc(len);
00305 if (!out)
00306 return 0;
00307 tmp = out;
00308 while (*in) {
00309 var = in;
00310 while (*in && (*in >= 32))
00311 in++;
00312 if (*in) {
00313 if ((count > 3) && inobj) {
00314 ast_build_string(&tmp, &len, " /></response>\n");
00315 inobj = 0;
00316 }
00317 count = 0;
00318 while (*in && (*in < 32)) {
00319 *in = '\0';
00320 in++;
00321 count++;
00322 }
00323 val = strchr(var, ':');
00324 if (val) {
00325 *val = '\0';
00326 val++;
00327 if (*val == ' ')
00328 val++;
00329 if (!inobj) {
00330 ast_build_string(&tmp, &len, "<response type='object' id='%s'><%s", dest, objtype);
00331 inobj = 1;
00332 }
00333 ast_build_string(&tmp, &len, " ");
00334 xml_copy_escape(&tmp, &len, var, 1);
00335 ast_build_string(&tmp, &len, "='");
00336 xml_copy_escape(&tmp, &len, val, 0);
00337 ast_build_string(&tmp, &len, "'");
00338 }
00339 }
00340 }
00341 if (inobj)
00342 ast_build_string(&tmp, &len, " /></response>\n");
00343 return out;
00344 }
00345
00346 static char *html_translate(char *in)
00347 {
00348 int x;
00349 int colons = 0;
00350 int breaks = 0;
00351 size_t len;
00352 int count = 1;
00353 char *tmp, *var, *val, *out;
00354
00355 for (x=0; in[x]; x++) {
00356 if (in[x] == ':')
00357 colons++;
00358 if (in[x] == '\n')
00359 breaks++;
00360 }
00361 len = strlen(in) + colons * 40 + breaks * 40;
00362 out = ast_malloc(len);
00363 if (!out)
00364 return 0;
00365 tmp = out;
00366 while (*in) {
00367 var = in;
00368 while (*in && (*in >= 32))
00369 in++;
00370 if (*in) {
00371 if ((count % 4) == 0){
00372 ast_build_string(&tmp, &len, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00373 }
00374 count = 0;
00375 while (*in && (*in < 32)) {
00376 *in = '\0';
00377 in++;
00378 count++;
00379 }
00380 val = strchr(var, ':');
00381 if (val) {
00382 *val = '\0';
00383 val++;
00384 if (*val == ' ')
00385 val++;
00386 ast_build_string(&tmp, &len, "<tr><td>%s</td><td>%s</td></tr>\r\n", var, val);
00387 }
00388 }
00389 }
00390 return out;
00391 }
00392
00393
00394
00395 static struct ast_manager_user *ast_get_manager_by_name_locked(const char *name)
00396 {
00397 struct ast_manager_user *user = NULL;
00398
00399 AST_LIST_TRAVERSE(&users, user, list)
00400 if (!strcasecmp(user->username, name))
00401 break;
00402 return user;
00403 }
00404
00405 void astman_append(struct mansession *s, const char *fmt, ...)
00406 {
00407 va_list ap;
00408 struct ast_dynamic_str *buf;
00409
00410 ast_mutex_lock(&s->__lock);
00411
00412 if (!(buf = ast_dynamic_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
00413 ast_mutex_unlock(&s->__lock);
00414 return;
00415 }
00416
00417 va_start(ap, fmt);
00418 ast_dynamic_str_thread_set_va(&buf, 0, &astman_append_buf, fmt, ap);
00419 va_end(ap);
00420
00421 if (s->fd > -1)
00422 ast_carefulwrite(s->fd, buf->str, strlen(buf->str), s->writetimeout);
00423 else {
00424 if (!s->outputstr && !(s->outputstr = ast_calloc(1, sizeof(*s->outputstr)))) {
00425 ast_mutex_unlock(&s->__lock);
00426 return;
00427 }
00428
00429 ast_dynamic_str_append(&s->outputstr, 0, "%s", buf->str);
00430 }
00431
00432 ast_mutex_unlock(&s->__lock);
00433 }
00434
00435
00436 static int handle_showmancmd(int fd, int argc, char *argv[])
00437 {
00438 struct manager_action *cur;
00439 char authority[80];
00440 int num;
00441
00442 if (argc != 4)
00443 return RESULT_SHOWUSAGE;
00444
00445 for (cur = first_action; cur; cur = cur->next) {
00446 for (num = 3; num < argc; num++) {
00447 if (!strcasecmp(cur->action, argv[num])) {
00448 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 : "");
00449 }
00450 }
00451 }
00452
00453 return RESULT_SUCCESS;
00454 }
00455
00456 static int handle_showmanager(int fd, int argc, char *argv[])
00457 {
00458 struct ast_manager_user *user = NULL;
00459
00460 if (argc != 4)
00461 return RESULT_SHOWUSAGE;
00462
00463 AST_LIST_LOCK(&users);
00464
00465 if (!(user = ast_get_manager_by_name_locked(argv[3]))) {
00466 ast_cli(fd, "There is no manager called %s\n", argv[3]);
00467 AST_LIST_UNLOCK(&users);
00468 return -1;
00469 }
00470
00471 ast_cli(fd,"\n");
00472 ast_cli(fd,
00473 " username: %s\n"
00474 " secret: %s\n"
00475 " deny: %s\n"
00476 " permit: %s\n"
00477 " read: %s\n"
00478 " write: %s\n"
00479 "displayconnects: %s\n",
00480 (user->username ? user->username : "(N/A)"),
00481 (user->secret ? user->secret : "(N/A)"),
00482 (user->deny ? user->deny : "(N/A)"),
00483 (user->permit ? user->permit : "(N/A)"),
00484 (user->read ? user->read : "(N/A)"),
00485 (user->write ? user->write : "(N/A)"),
00486 (user->displayconnects ? "yes" : "no"));
00487
00488 AST_LIST_UNLOCK(&users);
00489
00490 return RESULT_SUCCESS;
00491 }
00492
00493
00494 static int handle_showmanagers(int fd, int argc, char *argv[])
00495 {
00496 struct ast_manager_user *user = NULL;
00497 int count_amu = 0;
00498
00499 if (argc != 3)
00500 return RESULT_SHOWUSAGE;
00501
00502 AST_LIST_LOCK(&users);
00503
00504
00505 if (AST_LIST_EMPTY(&users)) {
00506 ast_cli(fd, "There are no manager users.\n");
00507 AST_LIST_UNLOCK(&users);
00508 return RESULT_SUCCESS;
00509 }
00510
00511 ast_cli(fd, "\nusername\n--------\n");
00512
00513 AST_LIST_TRAVERSE(&users, user, list) {
00514 ast_cli(fd, "%s\n", user->username);
00515 count_amu++;
00516 }
00517
00518 AST_LIST_UNLOCK(&users);
00519
00520 ast_cli(fd,"-------------------\n");
00521 ast_cli(fd,"%d manager users configured.\n", count_amu);
00522
00523 return RESULT_SUCCESS;
00524 }
00525
00526
00527
00528
00529 static int handle_showmancmds(int fd, int argc, char *argv[])
00530 {
00531 struct manager_action *cur;
00532 char authority[80];
00533 char *format = " %-15.15s %-15.15s %-55.55s\n";
00534
00535 ast_cli(fd, format, "Action", "Privilege", "Synopsis");
00536 ast_cli(fd, format, "------", "---------", "--------");
00537
00538 ast_rwlock_rdlock(&actionlock);
00539 for (cur = first_action; cur; cur = cur->next)
00540 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
00541 ast_rwlock_unlock(&actionlock);
00542
00543 return RESULT_SUCCESS;
00544 }
00545
00546
00547
00548 static int handle_showmanconn(int fd, int argc, char *argv[])
00549 {
00550 struct mansession *s;
00551 char *format = " %-15.15s %-15.15s\n";
00552
00553 ast_cli(fd, format, "Username", "IP Address");
00554
00555 AST_LIST_LOCK(&sessions);
00556 AST_LIST_TRAVERSE(&sessions, s, list)
00557 ast_cli(fd, format,s->username, ast_inet_ntoa(s->sin.sin_addr));
00558 AST_LIST_UNLOCK(&sessions);
00559
00560 return RESULT_SUCCESS;
00561 }
00562
00563
00564
00565 static int handle_showmaneventq(int fd, int argc, char *argv[])
00566 {
00567 struct eventqent *s;
00568
00569 AST_LIST_LOCK(&sessions);
00570 for (s = master_eventq; s; s = s->next) {
00571 ast_cli(fd, "Usecount: %d\n",s->usecount);
00572 ast_cli(fd, "Category: %d\n", s->category);
00573 ast_cli(fd, "Event:\n%s", s->eventdata);
00574 }
00575 AST_LIST_UNLOCK(&sessions);
00576
00577 return RESULT_SUCCESS;
00578 }
00579
00580 static char showmancmd_help[] =
00581 "Usage: manager show command <actionname>\n"
00582 " Shows the detailed description for a specific Asterisk manager interface command.\n";
00583
00584 static char showmancmds_help[] =
00585 "Usage: manager show commands\n"
00586 " Prints a listing of all the available Asterisk manager interface commands.\n";
00587
00588 static char showmanconn_help[] =
00589 "Usage: manager show connected\n"
00590 " Prints a listing of the users that are currently connected to the\n"
00591 "Asterisk manager interface.\n";
00592
00593 static char showmaneventq_help[] =
00594 "Usage: manager show eventq\n"
00595 " Prints a listing of all events pending in the Asterisk manger\n"
00596 "event queue.\n";
00597
00598 static char showmanagers_help[] =
00599 "Usage: manager show users\n"
00600 " Prints a listing of all managers that are currently configured on that\n"
00601 " system.\n";
00602
00603 static char showmanager_help[] =
00604 " Usage: manager show user <user>\n"
00605 " Display all information related to the manager user specified.\n";
00606
00607 static struct ast_cli_entry cli_show_manager_command_deprecated = {
00608 { "show", "manager", "command", NULL },
00609 handle_showmancmd, NULL,
00610 NULL, complete_show_mancmd };
00611
00612 static struct ast_cli_entry cli_show_manager_commands_deprecated = {
00613 { "show", "manager", "commands", NULL },
00614 handle_showmancmds, NULL,
00615 NULL };
00616
00617 static struct ast_cli_entry cli_show_manager_connected_deprecated = {
00618 { "show", "manager", "connected", NULL },
00619 handle_showmanconn, NULL,
00620 NULL };
00621
00622 static struct ast_cli_entry cli_show_manager_eventq_deprecated = {
00623 { "show", "manager", "eventq", NULL },
00624 handle_showmaneventq, NULL,
00625 NULL };
00626
00627 static struct ast_cli_entry cli_manager[] = {
00628 { { "manager", "show", "command", NULL },
00629 handle_showmancmd, "Show a manager interface command",
00630 showmancmd_help, complete_show_mancmd, &cli_show_manager_command_deprecated },
00631
00632 { { "manager", "show", "commands", NULL },
00633 handle_showmancmds, "List manager interface commands",
00634 showmancmds_help, NULL, &cli_show_manager_commands_deprecated },
00635
00636 { { "manager", "show", "connected", NULL },
00637 handle_showmanconn, "List connected manager interface users",
00638 showmanconn_help, NULL, &cli_show_manager_connected_deprecated },
00639
00640 { { "manager", "show", "eventq", NULL },
00641 handle_showmaneventq, "List manager interface queued events",
00642 showmaneventq_help, NULL, &cli_show_manager_eventq_deprecated },
00643
00644 { { "manager", "show", "users", NULL },
00645 handle_showmanagers, "List configured manager users",
00646 showmanagers_help, NULL, NULL },
00647
00648 { { "manager", "show", "user", NULL },
00649 handle_showmanager, "Display information on a specific manager user",
00650 showmanager_help, NULL, NULL },
00651 };
00652
00653 static void unuse_eventqent(struct eventqent *e)
00654 {
00655 if (ast_atomic_dec_and_test(&e->usecount) && e->next)
00656 pthread_kill(t, SIGURG);
00657 }
00658
00659 static void free_session(struct mansession *s)
00660 {
00661 struct eventqent *eqe;
00662 if (s->fd > -1)
00663 close(s->fd);
00664 if (s->outputstr)
00665 free(s->outputstr);
00666 ast_mutex_destroy(&s->__lock);
00667 while (s->eventq) {
00668 eqe = s->eventq;
00669 s->eventq = s->eventq->next;
00670 unuse_eventqent(eqe);
00671 }
00672 free(s);
00673 }
00674
00675 static void destroy_session(struct mansession *s)
00676 {
00677 AST_LIST_LOCK(&sessions);
00678 AST_LIST_REMOVE(&sessions, s, list);
00679 AST_LIST_UNLOCK(&sessions);
00680
00681 ast_atomic_fetchadd_int(&num_sessions, -1);
00682 free_session(s);
00683 }
00684
00685 const char *astman_get_header(const struct message *m, char *var)
00686 {
00687 char cmp[80];
00688 int x;
00689
00690 snprintf(cmp, sizeof(cmp), "%s: ", var);
00691
00692 for (x = 0; x < m->hdrcount; x++) {
00693 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
00694 return m->headers[x] + strlen(cmp);
00695 }
00696
00697 return "";
00698 }
00699
00700 struct ast_variable *astman_get_variables(const struct message *m)
00701 {
00702 int varlen, x, y;
00703 struct ast_variable *head = NULL, *cur;
00704 char *var, *val;
00705
00706 char *parse;
00707 AST_DECLARE_APP_ARGS(args,
00708 AST_APP_ARG(vars)[32];
00709 );
00710
00711 varlen = strlen("Variable: ");
00712
00713 for (x = 0; x < m->hdrcount; x++) {
00714 if (strncasecmp("Variable: ", m->headers[x], varlen))
00715 continue;
00716
00717 parse = ast_strdupa(m->headers[x] + varlen);
00718
00719 AST_STANDARD_APP_ARGS(args, parse);
00720 if (args.argc) {
00721 for (y = 0; y < args.argc; y++) {
00722 if (!args.vars[y])
00723 continue;
00724 var = val = ast_strdupa(args.vars[y]);
00725 strsep(&val, "=");
00726 if (!val || ast_strlen_zero(var))
00727 continue;
00728 cur = ast_variable_new(var, val);
00729 if (head) {
00730 cur->next = head;
00731 head = cur;
00732 } else
00733 head = cur;
00734 }
00735 }
00736 }
00737
00738 return head;
00739 }
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 void astman_send_error(struct mansession *s, const struct message *m, char *error)
00750 {
00751 const char *id = astman_get_header(m,"ActionID");
00752
00753 astman_append(s, "Response: Error\r\n");
00754 if (!ast_strlen_zero(id))
00755 astman_append(s, "ActionID: %s\r\n", id);
00756 astman_append(s, "Message: %s\r\n\r\n", error);
00757 }
00758
00759 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg)
00760 {
00761 const char *id = astman_get_header(m,"ActionID");
00762
00763 astman_append(s, "Response: %s\r\n", resp);
00764 if (!ast_strlen_zero(id))
00765 astman_append(s, "ActionID: %s\r\n", id);
00766 if (msg)
00767 astman_append(s, "Message: %s\r\n\r\n", msg);
00768 else
00769 astman_append(s, "\r\n");
00770 }
00771
00772 void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
00773 {
00774 astman_send_response(s, m, "Success", msg);
00775 }
00776
00777
00778
00779
00780
00781
00782 static int ast_instring(const char *bigstr, const char *smallstr, char delim)
00783 {
00784 const char *val = bigstr, *next;
00785
00786 do {
00787 if ((next = strchr(val, delim))) {
00788 if (!strncmp(val, smallstr, (next - val)))
00789 return 1;
00790 else
00791 continue;
00792 } else
00793 return !strcmp(smallstr, val);
00794
00795 } while (*(val = (next + 1)));
00796
00797 return 0;
00798 }
00799
00800 static int get_perm(const char *instr)
00801 {
00802 int x = 0, ret = 0;
00803
00804 if (!instr)
00805 return 0;
00806
00807 for (x = 0; x < (sizeof(perms) / sizeof(perms[0])); x++) {
00808 if (ast_instring(instr, perms[x].label, ','))
00809 ret |= perms[x].num;
00810 }
00811
00812 return ret;
00813 }
00814
00815 static int ast_is_number(char *string)
00816 {
00817 int ret = 1, x = 0;
00818
00819 if (!string)
00820 return 0;
00821
00822 for (x = 0; x < strlen(string); x++) {
00823 if (!(string[x] >= 48 && string[x] <= 57)) {
00824 ret = 0;
00825 break;
00826 }
00827 }
00828
00829 return ret ? atoi(string) : 0;
00830 }
00831
00832 static int strings_to_mask(const char *string)
00833 {
00834 int x, ret = -1;
00835
00836 x = ast_is_number((char *) string);
00837
00838 if (x)
00839 ret = x;
00840 else if (ast_strlen_zero(string))
00841 ret = -1;
00842 else if (ast_false(string))
00843 ret = 0;
00844 else if (ast_true(string)) {
00845 ret = 0;
00846 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
00847 ret |= perms[x].num;
00848 } else {
00849 ret = 0;
00850 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
00851 if (ast_instring(string, perms[x].label, ','))
00852 ret |= perms[x].num;
00853 }
00854 }
00855
00856 return ret;
00857 }
00858
00859
00860
00861
00862
00863 static int set_eventmask(struct mansession *s, const char *eventmask)
00864 {
00865 int maskint = strings_to_mask(eventmask);
00866
00867 ast_mutex_lock(&s->__lock);
00868 if (maskint >= 0)
00869 s->send_events = maskint;
00870 ast_mutex_unlock(&s->__lock);
00871
00872 return maskint;
00873 }
00874
00875 static int authenticate(struct mansession *s, const struct message *m)
00876 {
00877 struct ast_config *cfg;
00878 char *cat;
00879 const char *user = astman_get_header(m, "Username");
00880 const char *pass = astman_get_header(m, "Secret");
00881 const char *authtype = astman_get_header(m, "AuthType");
00882 const char *key = astman_get_header(m, "Key");
00883 const char *events = astman_get_header(m, "Events");
00884
00885 cfg = ast_config_load("manager.conf");
00886 if (!cfg)
00887 return -1;
00888 cat = ast_category_browse(cfg, NULL);
00889 while (cat) {
00890 if (strcasecmp(cat, "general")) {
00891
00892 if (!strcasecmp(cat, user)) {
00893 struct ast_variable *v;
00894 struct ast_ha *ha = NULL;
00895 char *password = NULL;
00896
00897 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
00898 if (!strcasecmp(v->name, "secret")) {
00899 password = v->value;
00900 } else if (!strcasecmp(v->name, "displaysystemname")) {
00901 if (ast_true(v->value)) {
00902 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
00903 s->displaysystemname = 1;
00904 } else {
00905 ast_log(LOG_ERROR, "Can't enable displaysystemname in manager.conf - no system name configured in asterisk.conf\n");
00906 }
00907 }
00908 } else if (!strcasecmp(v->name, "permit") ||
00909 !strcasecmp(v->name, "deny")) {
00910 ha = ast_append_ha(v->name, v->value, ha);
00911 } else if (!strcasecmp(v->name, "writetimeout")) {
00912 int val = atoi(v->value);
00913
00914 if (val < 100)
00915 ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
00916 else
00917 s->writetimeout = val;
00918 }
00919
00920 }
00921 if (ha && !ast_apply_ha(ha, &(s->sin))) {
00922 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
00923 ast_free_ha(ha);
00924 ast_config_destroy(cfg);
00925 return -1;
00926 } else if (ha)
00927 ast_free_ha(ha);
00928 if (!strcasecmp(authtype, "MD5")) {
00929 if (!ast_strlen_zero(key) &&
00930 !ast_strlen_zero(s->challenge) && !ast_strlen_zero(password)) {
00931 int x;
00932 int len = 0;
00933 char md5key[256] = "";
00934 struct MD5Context md5;
00935 unsigned char digest[16];
00936 MD5Init(&md5);
00937 MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
00938 MD5Update(&md5, (unsigned char *) password, strlen(password));
00939 MD5Final(digest, &md5);
00940 for (x=0; x<16; x++)
00941 len += sprintf(md5key + len, "%2.2x", digest[x]);
00942 if (!strcmp(md5key, key))
00943 break;
00944 else {
00945 ast_config_destroy(cfg);
00946 return -1;
00947 }
00948 }
00949 } else if (password && !strcmp(password, pass)) {
00950 break;
00951 } else {
00952 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
00953 ast_config_destroy(cfg);
00954 return -1;
00955 }
00956 }
00957 }
00958 cat = ast_category_browse(cfg, cat);
00959 }
00960 if (cat) {
00961 ast_copy_string(s->username, cat, sizeof(s->username));
00962 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
00963 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
00964 ast_config_destroy(cfg);
00965 if (events)
00966 set_eventmask(s, events);
00967 return 0;
00968 }
00969 ast_config_destroy(cfg);
00970 cfg = ast_config_load("users.conf");
00971 if (!cfg)
00972 return -1;
00973 cat = ast_category_browse(cfg, NULL);
00974 while (cat) {
00975 struct ast_variable *v;
00976 const char *password = NULL;
00977 int hasmanager = 0;
00978 if (strcasecmp(cat, user) || !strcasecmp(cat, "general")) {
00979 cat = ast_category_browse(cfg, cat);
00980 continue;
00981 }
00982 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
00983 if (!strcasecmp(v->name, "secret"))
00984 password = v->value;
00985 else if (!strcasecmp(v->name, "hasmanager"))
00986 hasmanager = ast_true(v->value);
00987 }
00988 if (!hasmanager)
00989 break;
00990 if (!password || strcmp(password, pass)) {
00991 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
00992 ast_config_destroy(cfg);
00993 return -1;
00994 }
00995 ast_copy_string(s->username, cat, sizeof(s->username));
00996 s->readperm = -1;
00997 s->writeperm = -1;
00998 ast_config_destroy(cfg);
00999 if (events)
01000 set_eventmask(s, events);
01001 return 0;
01002 }
01003 ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(s->sin.sin_addr), user);
01004 ast_config_destroy(cfg);
01005 return -1;
01006 }
01007
01008
01009 static char mandescr_ping[] =
01010 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the\n"
01011 " manager connection open.\n"
01012 "Variables: NONE\n";
01013
01014 static int action_ping(struct mansession *s, const struct message *m)
01015 {
01016 astman_send_response(s, m, "Pong", NULL);
01017 return 0;
01018 }
01019
01020 static char mandescr_getconfig[] =
01021 "Description: A 'GetConfig' action will dump the contents of a configuration\n"
01022 "file by category and contents.\n"
01023 "Variables:\n"
01024 " Filename: Configuration filename (e.g. foo.conf)\n";
01025
01026 static int action_getconfig(struct mansession *s, const struct message *m)
01027 {
01028 struct ast_config *cfg;
01029 const char *fn = astman_get_header(m, "Filename");
01030 int catcount = 0;
01031 int lineno = 0;
01032 char *category=NULL;
01033 struct ast_variable *v;
01034 char idText[256] = "";
01035 const char *id = astman_get_header(m, "ActionID");
01036
01037 if (!ast_strlen_zero(id))
01038 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01039
01040 if (ast_strlen_zero(fn)) {
01041 astman_send_error(s, m, "Filename not specified");
01042 return 0;
01043 }
01044 if (!(cfg = ast_config_load_with_comments(fn))) {
01045 astman_send_error(s, m, "Config file not found");
01046 return 0;
01047 }
01048 astman_append(s, "Response: Success\r\n%s", idText);
01049 while ((category = ast_category_browse(cfg, category))) {
01050 lineno = 0;
01051 astman_append(s, "Category-%06d: %s\r\n", catcount, category);
01052 for (v = ast_variable_browse(cfg, category); v; v = v->next)
01053 astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
01054 catcount++;
01055 }
01056 ast_config_destroy(cfg);
01057 astman_append(s, "\r\n");
01058
01059 return 0;
01060 }
01061
01062
01063 static void handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg)
01064 {
01065 int x;
01066 char hdr[40];
01067 const char *action, *cat, *var, *value, *match;
01068 struct ast_category *category;
01069 struct ast_variable *v;
01070
01071 for (x=0;x<100000;x++) {
01072 unsigned int object = 0;
01073
01074 snprintf(hdr, sizeof(hdr), "Action-%06d", x);
01075 action = astman_get_header(m, hdr);
01076 if (ast_strlen_zero(action))
01077 break;
01078 snprintf(hdr, sizeof(hdr), "Cat-%06d", x);
01079 cat = astman_get_header(m, hdr);
01080 snprintf(hdr, sizeof(hdr), "Var-%06d", x);
01081 var = astman_get_header(m, hdr);
01082 snprintf(hdr, sizeof(hdr), "Value-%06d", x);
01083 value = astman_get_header(m, hdr);
01084 if (!ast_strlen_zero(value) && *value == '>') {
01085 object = 1;
01086 value++;
01087 }
01088 snprintf(hdr, sizeof(hdr), "Match-%06d", x);
01089 match = astman_get_header(m, hdr);
01090 if (!strcasecmp(action, "newcat")) {
01091 if (!ast_strlen_zero(cat)) {
01092 category = ast_category_new(cat);
01093 if (category) {
01094 ast_category_append(cfg, category);
01095 }
01096 }
01097 } else if (!strcasecmp(action, "renamecat")) {
01098 if (!ast_strlen_zero(cat) && !ast_strlen_zero(value)) {
01099 category = ast_category_get(cfg, cat);
01100 if (category)
01101 ast_category_rename(category, value);
01102 }
01103 } else if (!strcasecmp(action, "delcat")) {
01104 if (!ast_strlen_zero(cat))
01105 ast_category_delete(cfg, (char *) cat);
01106 } else if (!strcasecmp(action, "update")) {
01107 if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) && (category = ast_category_get(cfg, cat)))
01108 ast_variable_update(category, var, value, match, object);
01109 } else if (!strcasecmp(action, "delete")) {
01110 if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) && (category = ast_category_get(cfg, cat)))
01111 ast_variable_delete(category, (char *) var, (char *) match);
01112 } else if (!strcasecmp(action, "append")) {
01113 if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) &&
01114 (category = ast_category_get(cfg, cat)) &&
01115 (v = ast_variable_new(var, value))){
01116 if (object || (match && !strcasecmp(match, "object")))
01117 v->object = 1;
01118 ast_variable_append(category, v);
01119 }
01120 }
01121 }
01122 }
01123
01124 static char mandescr_updateconfig[] =
01125 "Description: A 'UpdateConfig' action will dump the contents of a configuration\n"
01126 "file by category and contents.\n"
01127 "Variables (X's represent 6 digit number beginning with 000000):\n"
01128 " SrcFilename: Configuration filename to read(e.g. foo.conf)\n"
01129 " DstFilename: Configuration filename to write(e.g. foo.conf)\n"
01130 " Reload: Whether or not a reload should take place (or name of specific module)\n"
01131 " Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,Update,Delete,Append)\n"
01132 " Cat-XXXXXX: Category to operate on\n"
01133 " Var-XXXXXX: Variable to work on\n"
01134 " Value-XXXXXX: Value to work on\n"
01135 " Match-XXXXXX: Extra match required to match line\n";
01136
01137 static int action_updateconfig(struct mansession *s, const struct message *m)
01138 {
01139 struct ast_config *cfg;
01140 const char *sfn = astman_get_header(m, "SrcFilename");
01141 const char *dfn = astman_get_header(m, "DstFilename");
01142 int res;
01143 char idText[256] = "";
01144 const char *id = astman_get_header(m, "ActionID");
01145 const char *rld = astman_get_header(m, "Reload");
01146
01147 if (!ast_strlen_zero(id))
01148 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01149
01150 if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
01151 astman_send_error(s, m, "Filename not specified");
01152 return 0;
01153 }
01154 if (!(cfg = ast_config_load_with_comments(sfn))) {
01155 astman_send_error(s, m, "Config file not found");
01156 return 0;
01157 }
01158 handle_updates(s, m, cfg);
01159 res = config_text_file_save(dfn, cfg, "Manager");
01160 ast_config_destroy(cfg);
01161 if (res) {
01162 astman_send_error(s, m, "Save of config failed");
01163 return 0;
01164 }
01165 astman_append(s, "Response: Success\r\n%s\r\n", idText);
01166 if (!ast_strlen_zero(rld)) {
01167 if (ast_true(rld))
01168 rld = NULL;
01169 ast_module_reload(rld);
01170 }
01171 return 0;
01172 }
01173
01174
01175 static char mandescr_waitevent[] =
01176 "Description: A 'WaitEvent' action will ellicit a 'Success' response. Whenever\n"
01177 "a manager event is queued. Once WaitEvent has been called on an HTTP manager\n"
01178 "session, events will be generated and queued.\n"
01179 "Variables: \n"
01180 " Timeout: Maximum time to wait for events\n";
01181
01182 static int action_waitevent(struct mansession *s, const struct message *m)
01183 {
01184 const char *timeouts = astman_get_header(m, "Timeout");
01185 int timeout = -1, max;
01186 int x;
01187 int needexit = 0;
01188 time_t now;
01189 struct eventqent *eqe;
01190 const char *id = astman_get_header(m,"ActionID");
01191 char idText[256] = "";
01192
01193 if (!ast_strlen_zero(id))
01194 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01195
01196 if (!ast_strlen_zero(timeouts)) {
01197 sscanf(timeouts, "%i", &timeout);
01198 }
01199
01200 ast_mutex_lock(&s->__lock);
01201 if (s->waiting_thread != AST_PTHREADT_NULL) {
01202 pthread_kill(s->waiting_thread, SIGURG);
01203 }
01204 if (s->sessiontimeout) {
01205 time(&now);
01206 max = s->sessiontimeout - now - 10;
01207 if (max < 0)
01208 max = 0;
01209 if ((timeout < 0) || (timeout > max))
01210 timeout = max;
01211 if (!s->send_events)
01212 s->send_events = -1;
01213
01214 }
01215 ast_mutex_unlock(&s->__lock);
01216 s->waiting_thread = pthread_self();
01217 if (option_debug)
01218 ast_log(LOG_DEBUG, "Starting waiting for an event!\n");
01219 for (x=0; ((x < timeout) || (timeout < 0)); x++) {
01220 ast_mutex_lock(&s->__lock);
01221 if (s->eventq && s->eventq->next)
01222 needexit = 1;
01223 if (s->waiting_thread != pthread_self())
01224 needexit = 1;
01225 if (s->needdestroy)
01226 needexit = 1;
01227 ast_mutex_unlock(&s->__lock);
01228 if (needexit)
01229 break;
01230 if (s->fd > 0) {
01231 if (ast_wait_for_input(s->fd, 1000))
01232 break;
01233 } else {
01234 sleep(1);
01235 }
01236 }
01237 if (option_debug)
01238 ast_log(LOG_DEBUG, "Finished waiting for an event!\n");
01239 ast_mutex_lock(&s->__lock);
01240 if (s->waiting_thread == pthread_self()) {
01241 astman_send_response(s, m, "Success", "Waiting for Event...");
01242
01243 while(s->eventq->next) {
01244 eqe = s->eventq->next;
01245 if (((s->readperm & eqe->category) == eqe->category) &&
01246 ((s->send_events & eqe->category) == eqe->category)) {
01247 astman_append(s, "%s", eqe->eventdata);
01248 }
01249 unuse_eventqent(s->eventq);
01250 s->eventq = eqe;
01251 }
01252 astman_append(s,
01253 "Event: WaitEventComplete\r\n"
01254 "%s"
01255 "\r\n", idText);
01256 s->waiting_thread = AST_PTHREADT_NULL;
01257 } else {
01258 ast_log(LOG_DEBUG, "Abandoning event request!\n");
01259 }
01260 ast_mutex_unlock(&s->__lock);
01261 return 0;
01262 }
01263
01264 static char mandescr_listcommands[] =
01265 "Description: Returns the action name and synopsis for every\n"
01266 " action that is available to the user\n"
01267 "Variables: NONE\n";
01268
01269
01270 static int action_listcommands(struct mansession *s, const struct message *m)
01271 {
01272 struct manager_action *cur;
01273 char idText[256] = "";
01274 char temp[BUFSIZ];
01275 const char *id = astman_get_header(m,"ActionID");
01276
01277 if (!ast_strlen_zero(id))
01278 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01279 astman_append(s, "Response: Success\r\n%s", idText);
01280 for (cur = first_action; cur; cur = cur->next) {
01281 if ((s->writeperm & cur->authority) == cur->authority)
01282 astman_append(s, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)));
01283 }
01284 astman_append(s, "\r\n");
01285
01286 return 0;
01287 }
01288
01289 static char mandescr_events[] =
01290 "Description: Enable/Disable sending of events to this manager\n"
01291 " client.\n"
01292 "Variables:\n"
01293 " EventMask: 'on' if all events should be sent,\n"
01294 " 'off' if no events should be sent,\n"
01295 " 'system,call,log' to select which flags events should have to be sent.\n";
01296
01297 static int action_events(struct mansession *s, const struct message *m)
01298 {
01299 const char *mask = astman_get_header(m, "EventMask");
01300 int res;
01301
01302 res = set_eventmask(s, mask);
01303 if (res > 0)
01304 astman_send_response(s, m, "Events On", NULL);
01305 else if (res == 0)
01306 astman_send_response(s, m, "Events Off", NULL);
01307
01308 return 0;
01309 }
01310
01311 static char mandescr_logoff[] =
01312 "Description: Logoff this manager session\n"
01313 "Variables: NONE\n";
01314
01315 static int action_logoff(struct mansession *s, const struct message *m)
01316 {
01317 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
01318 return -1;
01319 }
01320
01321 static char mandescr_hangup[] =
01322 "Description: Hangup a channel\n"
01323 "Variables: \n"
01324 " Channel: The channel name to be hungup\n";
01325
01326 static int action_hangup(struct mansession *s, const struct message *m)
01327 {
01328 struct ast_channel *c = NULL;
01329 const char *name = astman_get_header(m, "Channel");
01330 if (ast_strlen_zero(name)) {
01331 astman_send_error(s, m, "No channel specified");
01332 return 0;
01333 }
01334 c = ast_get_channel_by_name_locked(name);
01335 if (!c) {
01336 astman_send_error(s, m, "No such channel");
01337 return 0;
01338 }
01339 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
01340 ast_channel_unlock(c);
01341 astman_send_ack(s, m, "Channel Hungup");
01342 return 0;
01343 }
01344
01345 static char mandescr_setvar[] =
01346 "Description: Set a global or local channel variable.\n"
01347 "Variables: (Names marked with * are required)\n"
01348 " Channel: Channel to set variable for\n"
01349 " *Variable: Variable name\n"
01350 " *Value: Value\n";
01351
01352 static int action_setvar(struct mansession *s, const struct message *m)
01353 {
01354 struct ast_channel *c = NULL;
01355 const char *name = astman_get_header(m, "Channel");
01356 const char *varname = astman_get_header(m, "Variable");
01357 const char *varval = astman_get_header(m, "Value");
01358
01359 if (ast_strlen_zero(varname)) {
01360 astman_send_error(s, m, "No variable specified");
01361 return 0;
01362 }
01363
01364 if (ast_strlen_zero(varval)) {
01365 astman_send_error(s, m, "No value specified");
01366 return 0;
01367 }
01368
01369 if (!ast_strlen_zero(name)) {
01370 c = ast_get_channel_by_name_locked(name);
01371 if (!c) {
01372 astman_send_error(s, m, "No such channel");
01373 return 0;
01374 }
01375 }
01376
01377 pbx_builtin_setvar_helper(c, varname, varval);
01378
01379 if (c)
01380 ast_channel_unlock(c);
01381
01382 astman_send_ack(s, m, "Variable Set");
01383
01384 return 0;
01385 }
01386
01387 static char mandescr_getvar[] =
01388 "Description: Get the value of a global or local channel variable.\n"
01389 "Variables: (Names marked with * are required)\n"
01390 " Channel: Channel to read variable from\n"
01391 " *Variable: Variable name\n"
01392 " ActionID: Optional Action id for message matching.\n";
01393
01394 static int action_getvar(struct mansession *s, const struct message *m)
01395 {
01396 struct ast_channel *c = NULL;
01397 const char *name = astman_get_header(m, "Channel");
01398 const char *varname = astman_get_header(m, "Variable");
01399 const char *id = astman_get_header(m,"ActionID");
01400 char *varval;
01401 char workspace[1024] = "";
01402
01403 if (ast_strlen_zero(varname)) {
01404 astman_send_error(s, m, "No variable specified");
01405 return 0;
01406 }
01407
01408 if (!ast_strlen_zero(name)) {
01409 c = ast_get_channel_by_name_locked(name);
01410 if (!c) {
01411 astman_send_error(s, m, "No such channel");
01412 return 0;
01413 }
01414 }
01415
01416 if (varname[strlen(varname) - 1] == ')') {
01417 char *copy = ast_strdupa(varname);
01418
01419 ast_func_read(c, copy, workspace, sizeof(workspace));
01420 varval = workspace;
01421 } else {
01422 pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
01423 }
01424
01425 if (c)
01426 ast_channel_unlock(c);
01427 astman_append(s, "Response: Success\r\n"
01428 "Variable: %s\r\nValue: %s\r\n", varname, varval);
01429 if (!ast_strlen_zero(id))
01430 astman_append(s, "ActionID: %s\r\n",id);
01431 astman_append(s, "\r\n");
01432
01433 return 0;
01434 }
01435
01436
01437
01438
01439 static int action_status(struct mansession *s, const struct message *m)
01440 {
01441 const char *id = astman_get_header(m,"ActionID");
01442 const char *name = astman_get_header(m,"Channel");
01443 char idText[256] = "";
01444 struct ast_channel *c;
01445 char bridge[256];
01446 struct timeval now = ast_tvnow();
01447 long elapsed_seconds = 0;
01448 int all = ast_strlen_zero(name);
01449
01450 if (!ast_strlen_zero(id))
01451 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01452 if (all)
01453 c = ast_channel_walk_locked(NULL);
01454 else {
01455 c = ast_get_channel_by_name_locked(name);
01456 if (!c) {
01457 astman_send_error(s, m, "No such channel");
01458 return 0;
01459 }
01460 }
01461 astman_send_ack(s, m, "Channel status will follow");
01462
01463 while (c) {
01464 if (c->_bridge)
01465 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
01466 else
01467 bridge[0] = '\0';
01468 if (c->pbx) {
01469 if (c->cdr) {
01470 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
01471 }
01472 astman_append(s,
01473 "Event: Status\r\n"
01474 "Privilege: Call\r\n"
01475 "Channel: %s\r\n"
01476 "CallerID: %s\r\n"
01477 "CallerIDNum: %s\r\n"
01478 "CallerIDName: %s\r\n"
01479 "Account: %s\r\n"
01480 "State: %s\r\n"
01481 "Context: %s\r\n"
01482 "Extension: %s\r\n"
01483 "Priority: %d\r\n"
01484 "Seconds: %ld\r\n"
01485 "%s"
01486 "Uniqueid: %s\r\n"
01487 "%s"
01488 "\r\n",
01489 c->name,
01490 S_OR(c->cid.cid_num, "<unknown>"),
01491 S_OR(c->cid.cid_num, "<unknown>"),
01492 S_OR(c->cid.cid_name, "<unknown>"),
01493 c->accountcode,
01494 ast_state2str(c->_state), c->context,
01495 c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
01496 } else {
01497 astman_append(s,
01498 "Event: Status\r\n"
01499 "Privilege: Call\r\n"
01500 "Channel: %s\r\n"
01501 "CallerID: %s\r\n"
01502 "CallerIDNum: %s\r\n"
01503 "CallerIDName: %s\r\n"
01504 "Account: %s\r\n"
01505 "State: %s\r\n"
01506 "%s"
01507 "Uniqueid: %s\r\n"
01508 "%s"
01509 "\r\n",
01510 c->name,
01511 S_OR(c->cid.cid_num, "<unknown>"),
01512 S_OR(c->cid.cid_num, "<unknown>"),
01513 S_OR(c->cid.cid_name, "<unknown>"),
01514 c->accountcode,
01515 ast_state2str(c->_state), bridge, c->uniqueid, idText);
01516 }
01517 ast_channel_unlock(c);
01518 if (!all)
01519 break;
01520 c = ast_channel_walk_locked(c);
01521 }
01522 astman_append(s,
01523 "Event: StatusComplete\r\n"
01524 "%s"
01525 "\r\n",idText);
01526 return 0;
01527 }
01528
01529 static char mandescr_redirect[] =
01530 "Description: Redirect (transfer) a call.\n"
01531 "Variables: (Names marked with * are required)\n"
01532 " *Channel: Channel to redirect\n"
01533 " ExtraChannel: Second call leg to transfer (optional)\n"
01534 " *Exten: Extension to transfer to\n"
01535 " *Context: Context to transfer to\n"
01536 " *Priority: Priority to transfer to\n"
01537 " ActionID: Optional Action id for message matching.\n";
01538
01539
01540 static int action_redirect(struct mansession *s, const struct message *m)
01541 {
01542 const char *name = astman_get_header(m, "Channel");
01543 const char *name2 = astman_get_header(m, "ExtraChannel");
01544 const char *exten = astman_get_header(m, "Exten");
01545 const char *context = astman_get_header(m, "Context");
01546 const char *priority = astman_get_header(m, "Priority");
01547 struct ast_channel *chan, *chan2 = NULL;
01548 int pi = 0;
01549 int res;
01550
01551 if (ast_strlen_zero(name)) {
01552 astman_send_error(s, m, "Channel not specified");
01553 return 0;
01554 }
01555 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
01556 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
01557 astman_send_error(s, m, "Invalid priority\n");
01558 return 0;
01559 }
01560 }
01561
01562 chan = ast_get_channel_by_name_locked(name);
01563 if (!chan) {
01564 char buf[BUFSIZ];
01565 snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
01566 astman_send_error(s, m, buf);
01567 return 0;
01568 }
01569 if (ast_check_hangup(chan)) {
01570 astman_send_error(s, m, "Redirect failed, channel not up.\n");
01571 ast_channel_unlock(chan);
01572 return 0;
01573 }
01574 if (!ast_strlen_zero(name2))
01575 chan2 = ast_get_channel_by_name_locked(name2);
01576 if (chan2 && ast_check_hangup(chan2)) {
01577 astman_send_error(s, m, "Redirect failed, extra channel not up.\n");
01578 ast_channel_unlock(chan);
01579 ast_channel_unlock(chan2);
01580 return 0;
01581 }
01582 res = ast_async_goto(chan, context, exten, pi);
01583 if (!res) {
01584 if (!ast_strlen_zero(name2)) {
01585 if (chan2)
01586 res = ast_async_goto(chan2, context, exten, pi);
01587 else
01588 res = -1;
01589 if (!res)
01590 astman_send_ack(s, m, "Dual Redirect successful");
01591 else
01592 astman_send_error(s, m, "Secondary redirect failed");
01593 } else
01594 astman_send_ack(s, m, "Redirect successful");
01595 } else
01596 astman_send_error(s, m, "Redirect failed");
01597 if (chan)
01598 ast_channel_unlock(chan);
01599 if (chan2)
01600 ast_channel_unlock(chan2);
01601 return 0;
01602 }
01603
01604 static char mandescr_command[] =
01605 "Description: Run a CLI command.\n"
01606 "Variables: (Names marked with * are required)\n"
01607 " *Command: Asterisk CLI command to run\n"
01608 " ActionID: Optional Action id for message matching.\n";
01609
01610
01611 static int action_command(struct mansession *s, const struct message *m)
01612 {
01613 const char *cmd = astman_get_header(m, "Command");
01614 const char *id = astman_get_header(m, "ActionID");
01615 astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
01616 if (!ast_strlen_zero(id))
01617 astman_append(s, "ActionID: %s\r\n", id);
01618
01619 ast_cli_command(s->fd, cmd);
01620 astman_append(s, "--END COMMAND--\r\n\r\n");
01621 return 0;
01622 }
01623
01624 static void *fast_originate(void *data)
01625 {
01626 struct fast_originate_helper *in = data;
01627 int res;
01628 int reason = 0;
01629 struct ast_channel *chan = NULL;
01630 char requested_channel[AST_CHANNEL_NAME];
01631
01632 if (!ast_strlen_zero(in->app)) {
01633 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1,
01634 S_OR(in->cid_num, NULL),
01635 S_OR(in->cid_name, NULL),
01636 in->vars, in->account, &chan);
01637 } else {
01638 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
01639 S_OR(in->cid_num, NULL),
01640 S_OR(in->cid_name, NULL),
01641 in->vars, in->account, &chan);
01642 }
01643
01644 if (!chan)
01645 snprintf(requested_channel, AST_CHANNEL_NAME, "%s/%s", in->tech, in->data);
01646
01647 manager_event(EVENT_FLAG_CALL, "OriginateResponse",
01648 "%s"
01649 "Response: %s\r\n"
01650 "Channel: %s\r\n"
01651 "Context: %s\r\n"
01652 "Exten: %s\r\n"
01653 "Reason: %d\r\n"
01654 "Uniqueid: %s\r\n"
01655 "CallerID: %s\r\n"
01656 "CallerIDNum: %s\r\n"
01657 "CallerIDName: %s\r\n",
01658 in->idtext, res ? "Failure" : "Success", chan ? chan->name : requested_channel, in->context, in->exten, reason,
01659 chan ? chan->uniqueid : "<null>",
01660 S_OR(in->cid_num, "<unknown>"),
01661 S_OR(in->cid_num, "<unknown>"),
01662 S_OR(in->cid_name, "<unknown>")
01663 );
01664
01665
01666 if (chan)
01667 ast_channel_unlock(chan);
01668 free(in);
01669 return NULL;
01670 }
01671
01672 static char mandescr_originate[] =
01673 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
01674 " Application/Data\n"
01675 "Variables: (Names marked with * are required)\n"
01676 " *Channel: Channel name to call\n"
01677 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
01678 " Context: Context to use (requires 'Exten' and 'Priority')\n"
01679 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
01680 " Application: Application to use\n"
01681 " Data: Data to use (requires 'Application')\n"
01682 " Timeout: How long to wait for call to be answered (in ms)\n"
01683 " CallerID: Caller ID to be set on the outgoing channel\n"
01684 " Variable: Channel variable to set, multiple Variable: headers are allowed\n"
01685 " Account: Account code\n"
01686 " Async: Set to 'true' for fast origination\n";
01687
01688 static int action_originate(struct mansession *s, const struct message *m)
01689 {
01690 const char *name = astman_get_header(m, "Channel");
01691 const char *exten = astman_get_header(m, "Exten");
01692 const char *context = astman_get_header(m, "Context");
01693 const char *priority = astman_get_header(m, "Priority");
01694 const char *timeout = astman_get_header(m, "Timeout");
01695 const char *callerid = astman_get_header(m, "CallerID");
01696 const char *account = astman_get_header(m, "Account");
01697 const char *app = astman_get_header(m, "Application");
01698 const char *appdata = astman_get_header(m, "Data");
01699 const char *async = astman_get_header(m, "Async");
01700 const char *id = astman_get_header(m, "ActionID");
01701 struct ast_variable *vars = astman_get_variables(m);
01702 char *tech, *data;
01703 char *l = NULL, *n = NULL;
01704 int pi = 0;
01705 int res;
01706 int to = 30000;
01707 int reason = 0;
01708 char tmp[256];
01709 char tmp2[256];
01710
01711 pthread_t th;
01712 pthread_attr_t attr;
01713 if (!name) {
01714 astman_send_error(s, m, "Channel not specified");
01715 return 0;
01716 }
01717 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
01718 if ((pi = ast_findlabel_extension(NULL, context, exten, priority, NULL)) < 1) {
01719 astman_send_error(s, m, "Invalid priority\n");
01720 return 0;
01721 }
01722 }
01723 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
01724 astman_send_error(s, m, "Invalid timeout\n");
01725 return 0;
01726 }
01727 ast_copy_string(tmp, name, sizeof(tmp));
01728 tech = tmp;
01729 data = strchr(tmp, '/');
01730 if (!data) {
01731 astman_send_error(s, m, "Invalid channel\n");
01732 return 0;
01733 }
01734 *data++ = '\0';
01735 ast_copy_string(tmp2, callerid, sizeof(tmp2));
01736 ast_callerid_parse(tmp2, &n, &l);
01737 if (n) {
01738 if (ast_strlen_zero(n))
01739 n = NULL;
01740 }
01741 if (l) {
01742 ast_shrink_phone_number(l);
01743 if (ast_strlen_zero(l))
01744 l = NULL;
01745 }
01746 if (ast_true(async)) {
01747 struct fast_originate_helper *fast = ast_calloc(1, sizeof(*fast));
01748 if (!fast) {
01749 res = -1;
01750 } else {
01751 if (!ast_strlen_zero(id))
01752 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
01753 ast_copy_string(fast->tech, tech, sizeof(fast->tech));
01754 ast_copy_string(fast->data, data, sizeof(fast->data));
01755 ast_copy_string(fast->app, app, sizeof(fast->app));
01756 ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
01757 if (l)
01758 ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
01759 if (n)
01760 ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
01761 fast->vars = vars;
01762 ast_copy_string(fast->context, context, sizeof(fast->context));
01763 ast_copy_string(fast->exten, exten, sizeof(fast->exten));
01764 ast_copy_string(fast->account, account, sizeof(fast->account));
01765 fast->timeout = to;
01766 fast->priority = pi;
01767 pthread_attr_init(&attr);
01768 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01769 if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
01770 res = -1;
01771 } else {
01772 res = 0;
01773 }
01774 pthread_attr_destroy(&attr);
01775 }
01776 } else if (!ast_strlen_zero(app)) {
01777 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
01778 } else {
01779 if (exten && context && pi)
01780 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
01781 else {
01782 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
01783 return 0;
01784 }
01785 }
01786 if (!res)
01787 astman_send_ack(s, m, "Originate successfully queued");
01788 else
01789 astman_send_error(s, m, "Originate failed");
01790 return 0;
01791 }
01792
01793
01794
01795 static char mandescr_mailboxstatus[] =
01796 "Description: Checks a voicemail account for status.\n"
01797 "Variables: (Names marked with * are required)\n"
01798 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
01799 " ActionID: Optional ActionID for message matching.\n"
01800 "Returns number of messages.\n"
01801 " Message: Mailbox Status\n"
01802 " Mailbox: <mailboxid>\n"
01803 " Waiting: <count>\n"
01804 "\n";
01805
01806 static int action_mailboxstatus(struct mansession *s, const struct message *m)
01807 {
01808 const char *mailbox = astman_get_header(m, "Mailbox");
01809 const char *id = astman_get_header(m,"ActionID");
01810 char idText[256] = "";
01811 int ret;
01812 if (ast_strlen_zero(mailbox)) {
01813 astman_send_error(s, m, "Mailbox not specified");
01814 return 0;
01815 }
01816 if (!ast_strlen_zero(id))
01817 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01818 ret = ast_app_has_voicemail(mailbox, NULL);
01819 astman_append(s, "Response: Success\r\n"
01820 "%s"
01821 "Message: Mailbox Status\r\n"
01822 "Mailbox: %s\r\n"
01823 "Waiting: %d\r\n\r\n", idText, mailbox, ret);
01824 return 0;
01825 }
01826
01827 static char mandescr_mailboxcount[] =
01828 "Description: Checks a voicemail account for new messages.\n"
01829 "Variables: (Names marked with * are required)\n"
01830 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
01831 " ActionID: Optional ActionID for message matching.\n"
01832 "Returns number of new and old messages.\n"
01833 " Message: Mailbox Message Count\n"
01834 " Mailbox: <mailboxid>\n"
01835 " NewMessages: <count>\n"
01836 " OldMessages: <count>\n"
01837 "\n";
01838 static int action_mailboxcount(struct mansession *s, const struct message *m)
01839 {
01840 const char *mailbox = astman_get_header(m, "Mailbox");
01841 const char *id = astman_get_header(m,"ActionID");
01842 char idText[256] = "";
01843 int newmsgs = 0, oldmsgs = 0;
01844 if (ast_strlen_zero(mailbox)) {
01845 astman_send_error(s, m, "Mailbox not specified");
01846 return 0;
01847 }
01848 ast_app_inboxcount(mailbox, &newmsgs, &oldmsgs);
01849 if (!ast_strlen_zero(id)) {
01850 snprintf(idText, sizeof(idText), "ActionID: %s\r\n",id);
01851 }
01852 astman_append(s, "Response: Success\r\n"
01853 "%s"
01854 "Message: Mailbox Message Count\r\n"
01855 "Mailbox: %s\r\n"
01856 "NewMessages: %d\r\n"
01857 "OldMessages: %d\r\n"
01858 "\r\n",
01859 idText,mailbox, newmsgs, oldmsgs);
01860 return 0;
01861 }
01862
01863 static char mandescr_extensionstate[] =
01864 "Description: Report the extension state for given extension.\n"
01865 " If the extension has a hint, will use devicestate to check\n"
01866 " the status of the device connected to the extension.\n"
01867 "Variables: (Names marked with * are required)\n"
01868 " *Exten: Extension to check state on\n"
01869 " *Context: Context for extension\n"
01870 " ActionId: Optional ID for this transaction\n"
01871 "Will return an \"Extension Status\" message.\n"
01872 "The response will include the hint for the extension and the status.\n";
01873
01874 static int action_extensionstate(struct mansession *s, const struct message *m)
01875 {
01876 const char *exten = astman_get_header(m, "Exten");
01877 const char *context = astman_get_header(m, "Context");
01878 const char *id = astman_get_header(m,"ActionID");
01879 char idText[256] = "";
01880 char hint[256] = "";
01881 int status;
01882 if (ast_strlen_zero(exten)) {
01883 astman_send_error(s, m, "Extension not specified");
01884 return 0;
01885 }
01886 if (ast_strlen_zero(context))
01887 context = "default";
01888 status = ast_extension_state(NULL, context, exten);
01889 ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
01890 if (!ast_strlen_zero(id)) {
01891 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
01892 }
01893 astman_append(s, "Response: Success\r\n"
01894 "%s"
01895 "Message: Extension Status\r\n"
01896 "Exten: %s\r\n"
01897 "Context: %s\r\n"
01898 "Hint: %s\r\n"
01899 "Status: %d\r\n\r\n",
01900 idText,exten, context, hint, status);
01901 return 0;
01902 }
01903
01904 static char mandescr_timeout[] =
01905 "Description: Hangup a channel after a certain time.\n"
01906 "Variables: (Names marked with * are required)\n"
01907 " *Channel: Channel name to hangup\n"
01908 " *Timeout: Maximum duration of the call (sec)\n"
01909 "Acknowledges set time with 'Timeout Set' message\n";
01910
01911 static int action_timeout(struct mansession *s, const struct message *m)
01912 {
01913 struct ast_channel *c = NULL;
01914 const char *name = astman_get_header(m, "Channel");
01915 int timeout = atoi(astman_get_header(m, "Timeout"));
01916 if (ast_strlen_zero(name)) {
01917 astman_send_error(s, m, "No channel specified");
01918 return 0;
01919 }
01920 if (!timeout) {
01921 astman_send_error(s, m, "No timeout specified");
01922 return 0;
01923 }
01924 c = ast_get_channel_by_name_locked(name);
01925 if (!c) {
01926 astman_send_error(s, m, "No such channel");
01927 return 0;
01928 }
01929 ast_channel_setwhentohangup(c, timeout);
01930 ast_channel_unlock(c);
01931 astman_send_ack(s, m, "Timeout Set");
01932 return 0;
01933 }
01934
01935 static int process_events(struct mansession *s)
01936 {
01937 struct eventqent *eqe;
01938 int ret = 0;
01939 ast_mutex_lock(&s->__lock);
01940 if (s->fd > -1) {
01941 if (!s->eventq)
01942 s->eventq = master_eventq;
01943 while(s->eventq->next) {
01944 eqe = s->eventq->next;
01945 if ((s->authenticated && (s->readperm & eqe->category) == eqe->category) &&
01946 ((s->send_events & eqe->category) == eqe->category)) {
01947 if (!ret && ast_carefulwrite(s->fd, eqe->eventdata, strlen(eqe->eventdata), s->writetimeout) < 0)
01948 ret = -1;
01949 }
01950 unuse_eventqent(s->eventq);
01951 s->eventq = eqe;
01952 }
01953 }
01954 ast_mutex_unlock(&s->__lock);
01955 return ret;
01956 }
01957
01958 static char mandescr_userevent[] =
01959 "Description: Send an event to manager sessions.\n"
01960 "Variables: (Names marked with * are required)\n"
01961 " *UserEvent: EventStringToSend\n"
01962 " Header1: Content1\n"
01963 " HeaderN: ContentN\n";
01964
01965 static int action_userevent(struct mansession *s, const struct message *m)
01966 {
01967 const char *event = astman_get_header(m, "UserEvent");
01968 char body[2048] = "";
01969 int x, bodylen = 0;
01970 for (x = 0; x < m->hdrcount; x++) {
01971 if (strncasecmp("UserEvent:", m->headers[x], strlen("UserEvent:"))) {
01972 ast_copy_string(body + bodylen, m->headers[x], sizeof(body) - bodylen - 3);
01973 bodylen += strlen(m->headers[x]);
01974 ast_copy_string(body + bodylen, "\r\n", 3);
01975 bodylen += 2;
01976 }
01977 }
01978
01979 manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", event, body);
01980 return 0;
01981 }
01982
01983 static int process_message(struct mansession *s, const struct message *m)
01984 {
01985 char action[80] = "";
01986 struct manager_action *tmp;
01987 const char *id = astman_get_header(m,"ActionID");
01988 char idText[256] = "";
01989 int ret = 0;
01990
01991 ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
01992 if (option_debug)
01993 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
01994
01995 if (ast_strlen_zero(action)) {
01996 astman_send_error(s, m, "Missing action in request");
01997 return 0;
01998 }
01999 if (!ast_strlen_zero(id)) {
02000 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02001 }
02002 if (!s->authenticated) {
02003 if (!strcasecmp(action, "Challenge")) {
02004 const char *authtype = astman_get_header(m, "AuthType");
02005
02006 if (!strcasecmp(authtype, "MD5")) {
02007 if (ast_strlen_zero(s->challenge))
02008 snprintf(s->challenge, sizeof(s->challenge), "%ld", ast_random());
02009 astman_append(s, "Response: Success\r\n"
02010 "%s"
02011 "Challenge: %s\r\n\r\n",
02012 idText, s->challenge);
02013 return 0;
02014 } else {
02015 astman_send_error(s, m, "Must specify AuthType");
02016 return 0;
02017 }
02018 } else if (!strcasecmp(action, "Login")) {
02019 if (authenticate(s, m)) {
02020 sleep(1);
02021 astman_send_error(s, m, "Authentication failed");
02022 return -1;
02023 } else {
02024 s->authenticated = 1;
02025 if (option_verbose > 1) {
02026 if (displayconnects) {
02027 ast_verbose(VERBOSE_PREFIX_2 "%sManager '%s' logged on from %s\n",
02028 (s->sessiontimeout ? "HTTP " : ""), s->username, ast_inet_ntoa(s->sin.sin_addr));
02029 }
02030 }
02031 ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n",
02032 (s->sessiontimeout ? "HTTP " : ""), s->username, ast_inet_ntoa(s->sin.sin_addr));
02033 astman_send_ack(s, m, "Authentication accepted");
02034 }
02035 } else if (!strcasecmp(action, "Logoff")) {
02036 astman_send_ack(s, m, "See ya");
02037 return -1;
02038 } else
02039 astman_send_error(s, m, "Authentication Required");
02040 } else {
02041 if (!strcasecmp(action, "Login"))
02042 astman_send_ack(s, m, "Already logged in");
02043 else {
02044 ast_rwlock_rdlock(&actionlock);
02045 for (tmp = first_action; tmp; tmp = tmp->next) {
02046 if (strcasecmp(action, tmp->action))
02047 continue;
02048 if ((s->writeperm & tmp->authority) == tmp->authority) {
02049 if (tmp->func(s, m))
02050 ret = -1;
02051 } else
02052 astman_send_error(s, m, "Permission denied");
02053 break;
02054 }
02055 ast_rwlock_unlock(&actionlock);
02056 if (!tmp)
02057 astman_send_error(s, m, "Invalid/unknown command");
02058 }
02059 }
02060 if (ret)
02061 return ret;
02062 return process_events(s);
02063 }
02064
02065 static int get_input(struct mansession *s, char *output)
02066 {
02067
02068 int res;
02069 int x;
02070 struct pollfd fds[1];
02071 for (x = 1; x < s->inlen; x++) {
02072 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
02073
02074 memcpy(output, s->inbuf, x + 1);
02075
02076 output[x+1] = '\0';
02077
02078 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
02079 s->inlen -= (x + 1);
02080 return 1;
02081 }
02082 }
02083 if (s->inlen >= sizeof(s->inbuf) - 1) {
02084 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(s->sin.sin_addr), s->inbuf);
02085 s->inlen = 0;
02086 }
02087 fds[0].fd = s->fd;
02088 fds[0].events = POLLIN;
02089 do {
02090 ast_mutex_lock(&s->__lock);
02091 s->waiting_thread = pthread_self();
02092 ast_mutex_unlock(&s->__lock);
02093
02094 res = poll(fds, 1, -1);
02095
02096 ast_mutex_lock(&s->__lock);
02097 s->waiting_thread = AST_PTHREADT_NULL;
02098 ast_mutex_unlock(&s->__lock);
02099 if (res < 0) {
02100 if (errno == EINTR) {
02101 return 0;
02102 }
02103 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
02104 return -1;
02105 } else if (res > 0) {
02106 ast_mutex_lock(&s->__lock);
02107 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
02108 ast_mutex_unlock(&s->__lock);
02109 if (res < 1)
02110 return -1;
02111 break;
02112 }
02113 } while(1);
02114 s->inlen += res;
02115 s->inbuf[s->inlen] = '\0';
02116 return 0;
02117 }
02118
02119 static int do_message(struct mansession *s)
02120 {
02121 struct message m = { 0 };
02122 char header_buf[sizeof(s->inbuf)] = { '\0' };
02123 int res;
02124
02125 for (;;) {
02126
02127 if (s->eventq->next) {
02128 if (process_events(s))
02129 return -1;
02130 }
02131 res = get_input(s, header_buf);
02132 if (res == 0) {
02133 continue;
02134 } else if (res > 0) {
02135
02136 if (strlen(header_buf) < 2)
02137 continue;
02138 header_buf[strlen(header_buf) - 2] = '\0';
02139 if (ast_strlen_zero(header_buf))
02140 return process_message(s, &m) ? -1 : 0;
02141 else if (m.hdrcount < (AST_MAX_MANHEADERS - 1))
02142 m.headers[m.hdrcount++] = ast_strdupa(header_buf);
02143 } else {
02144 return res;
02145 }
02146 }
02147 }
02148
02149 static void *session_do(void *data)
02150 {
02151 struct mansession *s = data;
02152 int res;
02153
02154 astman_append(s, "Asterisk Call Manager/1.0\r\n");
02155 for (;;) {
02156 if ((res = do_message(s)) < 0)
02157 break;
02158 }
02159 if (s->authenticated) {
02160 if (option_verbose > 1) {
02161 if (displayconnects)
02162 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
02163 }
02164 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
02165 } else {
02166 if (option_verbose > 1) {
02167 if (displayconnects)
02168 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
02169 }
02170 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
02171 }
02172 destroy_session(s);
02173 return NULL;
02174 }
02175
02176 static void *accept_thread(void *ignore)
02177 {
02178 int as;
02179 struct sockaddr_in sin;
02180 socklen_t sinlen;
02181 struct eventqent *eqe;
02182 struct mansession *s;
02183 struct protoent *p;
02184 int arg = 1;
02185 int flags;
02186 pthread_attr_t attr;
02187 time_t now;
02188 struct pollfd pfds[1];
02189
02190 pthread_attr_init(&attr);
02191 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02192
02193 for (;;) {
02194 time(&now);
02195 AST_LIST_LOCK(&sessions);
02196 AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, s, list) {
02197 if (s->sessiontimeout && (now > s->sessiontimeout) && !s->inuse) {
02198 AST_LIST_REMOVE_CURRENT(&sessions, list);
02199 if (s->authenticated && (option_verbose > 1) && displayconnects) {
02200 ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' timed out from %s\n",
02201 s->username, ast_inet_ntoa(s->sin.sin_addr));
02202 }
02203 free_session(s);
02204 break;
02205 }
02206 }
02207 AST_LIST_TRAVERSE_SAFE_END
02208
02209
02210 eqe = master_eventq;
02211 while (master_eventq->next && !master_eventq->usecount) {
02212 eqe = master_eventq;
02213 master_eventq = master_eventq->next;
02214 free(eqe);
02215 }
02216 AST_LIST_UNLOCK(&sessions);
02217 if (s)
02218 ast_atomic_fetchadd_int(&num_sessions, -1);
02219
02220 sinlen = sizeof(sin);
02221 pfds[0].fd = asock;
02222 pfds[0].events = POLLIN;
02223
02224
02225 if (poll(pfds, 1, 5000) < 1)
02226 continue;
02227 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
02228 if (as < 0) {
02229 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
02230 continue;
02231 }
02232 p = getprotobyname("tcp");
02233 if (p) {
02234 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
02235 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
02236 }
02237 }
02238 if (!(s = ast_calloc(1, sizeof(*s))))
02239 continue;
02240
02241 ast_atomic_fetchadd_int(&num_sessions, 1);
02242
02243 memcpy(&s->sin, &sin, sizeof(sin));
02244 s->writetimeout = 100;
02245 s->waiting_thread = AST_PTHREADT_NULL;
02246
02247 if (!block_sockets) {
02248
02249 flags = fcntl(as, F_GETFL);
02250 fcntl(as, F_SETFL, flags | O_NONBLOCK);
02251 } else {
02252 flags = fcntl(as, F_GETFL);
02253 fcntl(as, F_SETFL, flags & ~O_NONBLOCK);
02254 }
02255 ast_mutex_init(&s->__lock);
02256 s->fd = as;
02257 s->send_events = -1;
02258 AST_LIST_LOCK(&sessions);
02259 AST_LIST_INSERT_HEAD(&sessions, s, list);
02260
02261
02262 s->eventq = master_eventq;
02263 while(s->eventq->next)
02264 s->eventq = s->eventq->next;
02265 AST_LIST_UNLOCK(&sessions);
02266 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
02267 if (ast_pthread_create_background(&s->t, &attr, session_do, s))
02268 destroy_session(s);
02269 }
02270 pthread_attr_destroy(&attr);
02271 return NULL;
02272 }
02273
02274 static int append_event(const char *str, int category)
02275 {
02276 struct eventqent *tmp, *prev = NULL;
02277 tmp = ast_malloc(sizeof(*tmp) + strlen(str));
02278
02279 if (!tmp)
02280 return -1;
02281
02282 tmp->next = NULL;
02283 tmp->category = category;
02284 strcpy(tmp->eventdata, str);
02285
02286 if (master_eventq) {
02287 prev = master_eventq;
02288 while (prev->next)
02289 prev = prev->next;
02290 prev->next = tmp;
02291 } else {
02292 master_eventq = tmp;
02293 }
02294
02295 tmp->usecount = num_sessions;
02296
02297 return 0;
02298 }
02299
02300
02301 int manager_event(int category, const char *event, const char *fmt, ...)
02302 {
02303 struct mansession *s;
02304 char auth[80];
02305 va_list ap;
02306 struct timeval now;
02307 struct ast_dynamic_str *buf;
02308
02309
02310 if (!num_sessions)
02311 return 0;
02312
02313 if (!(buf = ast_dynamic_str_thread_get(&manager_event_buf, MANAGER_EVENT_BUF_INITSIZE)))
02314 return -1;
02315
02316 ast_dynamic_str_thread_set(&buf, 0, &manager_event_buf,
02317 "Event: %s\r\nPrivilege: %s\r\n",
02318 event, authority_to_str(category, auth, sizeof(auth)));
02319
02320 if (timestampevents) {
02321 now = ast_tvnow();
02322 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf,
02323 "Timestamp: %ld.%06lu\r\n",
02324 now.tv_sec, (unsigned long) now.tv_usec);
02325 }
02326
02327 va_start(ap, fmt);
02328 ast_dynamic_str_thread_append_va(&buf, 0, &manager_event_buf, fmt, ap);
02329 va_end(ap);
02330
02331 ast_dynamic_str_thread_append(&buf, 0, &manager_event_buf, "\r\n");
02332
02333
02334 AST_LIST_LOCK(&sessions);
02335 append_event(buf->str, category);
02336 AST_LIST_TRAVERSE(&sessions, s, list) {
02337 ast_mutex_lock(&s->__lock);
02338 if (s->waiting_thread != AST_PTHREADT_NULL)
02339 pthread_kill(s->waiting_thread, SIGURG);
02340 ast_mutex_unlock(&s->__lock);
02341 }
02342 AST_LIST_UNLOCK(&sessions);
02343
02344 return 0;
02345 }
02346
02347 int ast_manager_unregister(char *action)
02348 {
02349 struct manager_action *cur, *prev;
02350
02351 ast_rwlock_wrlock(&actionlock);
02352 cur = prev = first_action;
02353 while (cur) {
02354 if (!strcasecmp(action, cur->action)) {
02355 prev->next = cur->next;
02356 free(cur);
02357 if (option_verbose > 1)
02358 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
02359 ast_rwlock_unlock(&actionlock);
02360 return 0;
02361 }
02362 prev = cur;
02363 cur = cur->next;
02364 }
02365 ast_rwlock_unlock(&actionlock);
02366 return 0;
02367 }
02368
02369 static int manager_state_cb(char *context, char *exten, int state, void *data)
02370 {
02371
02372 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
02373 return 0;
02374 }
02375
02376 static int ast_manager_register_struct(struct manager_action *act)
02377 {
02378 struct manager_action *cur, *prev = NULL;
02379 int ret;
02380
02381 ast_rwlock_wrlock(&actionlock);
02382 cur = first_action;
02383 while (cur) {
02384 ret = strcasecmp(cur->action, act->action);
02385 if (ret == 0) {
02386 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
02387 ast_rwlock_unlock(&actionlock);
02388 return -1;
02389 } else if (ret > 0) {
02390
02391 if (prev) {
02392 act->next = prev->next;
02393 prev->next = act;
02394 } else {
02395 act->next = first_action;
02396 first_action = act;
02397 }
02398 break;
02399 }
02400 prev = cur;
02401 cur = cur->next;
02402 }
02403
02404 if (!cur) {
02405 if (prev)
02406 prev->next = act;
02407 else
02408 first_action = act;
02409 act->next = NULL;
02410 }
02411
02412 if (option_verbose > 1)
02413 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
02414 ast_rwlock_unlock(&actionlock);
02415 return 0;
02416 }
02417
02418
02419
02420 int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, const struct message *m), const char *synopsis, const char *description)
02421 {
02422 struct manager_action *cur;
02423
02424 cur = ast_malloc(sizeof(*cur));
02425 if (!cur)
02426 return -1;
02427
02428 cur->action = action;
02429 cur->authority = auth;
02430 cur->func = func;
02431 cur->synopsis = synopsis;
02432 cur->description = description;
02433 cur->next = NULL;
02434
02435 ast_manager_register_struct(cur);
02436
02437 return 0;
02438 }
02439
02440
02441
02442 static struct mansession *find_session(unsigned long ident)
02443 {
02444 struct mansession *s;
02445
02446 AST_LIST_LOCK(&sessions);
02447 AST_LIST_TRAVERSE(&sessions, s, list) {
02448 ast_mutex_lock(&s->__lock);
02449 if (s->sessiontimeout && (s->managerid == ident) && !s->needdestroy) {
02450 s->inuse++;
02451 break;
02452 }
02453 ast_mutex_unlock(&s->__lock);
02454 }
02455 AST_LIST_UNLOCK(&sessions);
02456
02457 return s;
02458 }
02459
02460 int astman_verify_session_readpermissions(unsigned long ident, int perm)
02461 {
02462 int result = 0;
02463 struct mansession *s;
02464
02465 AST_LIST_LOCK(&sessions);
02466 AST_LIST_TRAVERSE(&sessions, s, list) {
02467 ast_mutex_lock(&s->__lock);
02468 if ((s->managerid == ident) && (s->readperm & perm)) {
02469 result = 1;
02470 ast_mutex_unlock(&s->__lock);
02471 break;
02472 }
02473 ast_mutex_unlock(&s->__lock);
02474 }
02475 AST_LIST_UNLOCK(&sessions);
02476 return result;
02477 }
02478
02479 int astman_verify_session_writepermissions(unsigned long ident, int perm)
02480 {
02481 int result = 0;
02482 struct mansession *s;
02483
02484 AST_LIST_LOCK(&sessions);
02485 AST_LIST_TRAVERSE(&sessions, s, list) {
02486 ast_mutex_lock(&s->__lock);
02487 if ((s->managerid == ident) && (s->writeperm & perm)) {
02488 result = 1;
02489 ast_mutex_unlock(&s->__lock);
02490 break;
02491 }
02492 ast_mutex_unlock(&s->__lock);
02493 }
02494 AST_LIST_UNLOCK(&sessions);
02495 return result;
02496 }
02497
02498 enum {
02499 FORMAT_RAW,
02500 FORMAT_HTML,
02501 FORMAT_XML,
02502 };
02503 static char *contenttype[] = { "plain", "html", "xml" };
02504
02505 static char *generic_http_callback(int format, struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
02506 {
02507 struct mansession *s = NULL;
02508 unsigned long ident = 0;
02509 char workspace[512];
02510 char cookie[128];
02511 size_t len = sizeof(workspace);
02512 int blastaway = 0;
02513 char *c = workspace;
02514 char *retval = NULL;
02515 struct ast_variable *v;
02516
02517 for (v = params; v; v = v->next) {
02518 if (!strcasecmp(v->name, "mansession_id")) {
02519 sscanf(v->value, "%lx", &ident);
02520 break;
02521 }
02522 }
02523
02524 if (!(s = find_session(ident))) {
02525
02526 if (!(s = ast_calloc(1, sizeof(*s)))) {
02527 *status = 500;
02528 goto generic_callback_out;
02529 }
02530 memcpy(&s->sin, requestor, sizeof(s->sin));
02531 s->fd = -1;
02532 s->waiting_thread = AST_PTHREADT_NULL;
02533 s->send_events = 0;
02534 ast_mutex_init(&s->__lock);
02535 ast_mutex_lock(&s->__lock);
02536 s->inuse = 1;
02537 s->managerid = rand() | (unsigned long)s;
02538 AST_LIST_LOCK(&sessions);
02539 AST_LIST_INSERT_HEAD(&sessions, s, list);
02540
02541 s->eventq = master_eventq;
02542 while (s->eventq->next)
02543 s->eventq = s->eventq->next;
02544 AST_LIST_UNLOCK(&sessions);
02545 ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
02546 ast_atomic_fetchadd_int(&num_sessions, 1);
02547 }
02548
02549
02550 time(&s->sessiontimeout);
02551 if (!s->authenticated && (httptimeout > 5))
02552 s->sessiontimeout += 5;
02553 else
02554 s->sessiontimeout += httptimeout;
02555 ast_mutex_unlock(&s->__lock);
02556
02557 if (s) {
02558 struct message m = { 0 };
02559 char tmp[80];
02560 unsigned int x;
02561 size_t hdrlen;
02562
02563 for (x = 0, v = params; v && (x < AST_MAX_MANHEADERS); x++, v = v->next) {
02564 hdrlen = strlen(v->name) + strlen(v->value) + 3;
02565 m.headers[m.hdrcount] = alloca(hdrlen);
02566 snprintf((char *) m.headers[m.hdrcount], hdrlen, "%s: %s", v->name, v->value);
02567 m.hdrcount = x + 1;
02568 }
02569
02570 if (process_message(s, &m)) {
02571 if (s->authenticated) {
02572 if (option_verbose > 1) {
02573 if (displayconnects)
02574 ast_verbose(VERBOSE_PREFIX_2 "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
02575 }
02576 ast_log(LOG_EVENT, "HTTP Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(s->sin.sin_addr));
02577 } else {
02578 if (option_verbose > 1) {
02579 if (displayconnects)
02580 ast_verbose(VERBOSE_PREFIX_2 "HTTP Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(s->sin.sin_addr));
02581 }
02582 ast_log(LOG_EVENT, "HTTP Failed attempt from %s\n", ast_inet_ntoa(s->sin.sin_addr));
02583 }
02584 s->needdestroy = 1;
02585 }
02586 ast_build_string(&c, &len, "Content-type: text/%s\r\n", contenttype[format]);
02587 sprintf(tmp, "%08lx", s->managerid);
02588 ast_build_string(&c, &len, "%s\r\n", ast_http_setcookie("mansession_id", tmp, httptimeout, cookie, sizeof(cookie)));
02589 if (format == FORMAT_HTML)
02590 ast_build_string(&c, &len, "<title>Asterisk™ Manager Interface</title>");
02591 if (format == FORMAT_XML) {
02592 ast_build_string(&c, &len, "<ajax-response>\n");
02593 } else if (format == FORMAT_HTML) {
02594 ast_build_string(&c, &len, "<body bgcolor=\"#ffffff\"><table align=center bgcolor=\"#f1f1f1\" width=\"500\">\r\n");
02595 ast_build_string(&c, &len, "<tr><td colspan=\"2\" bgcolor=\"#f1f1ff\"><h1> Manager Tester</h1></td></tr>\r\n");
02596 }
02597 ast_mutex_lock(&s->__lock);
02598 if (s->outputstr) {
02599 char *tmp;
02600 if (format == FORMAT_XML)
02601 tmp = xml_translate(s->outputstr->str, params);
02602 else if (format == FORMAT_HTML)
02603 tmp = html_translate(s->outputstr->str);
02604 else
02605 tmp = s->outputstr->str;
02606 if (tmp) {
02607 retval = malloc(strlen(workspace) + strlen(tmp) + 128);
02608 if (retval) {
02609 strcpy(retval, workspace);
02610 strcpy(retval + strlen(retval), tmp);
02611 c = retval + strlen(retval);
02612 len = 120;
02613 }
02614 }
02615 if (tmp != s->outputstr->str)
02616 free(tmp);
02617 free(s->outputstr);
02618 s->outputstr = NULL;
02619 }
02620 ast_mutex_unlock(&s->__lock);
02621
02622
02623 if (format == FORMAT_XML) {
02624 ast_build_string(&c, &len, "</ajax-response>\n");
02625 } else if (format == FORMAT_HTML)
02626 ast_build_string(&c, &len, "</table></body>\r\n");
02627 } else {
02628 *status = 500;
02629 *title = strdup("Server Error");
02630 }
02631 ast_mutex_lock(&s->__lock);
02632 if (s->needdestroy) {
02633 if (s->inuse == 1) {
02634 ast_log(LOG_DEBUG, "Need destroy, doing it now!\n");
02635 blastaway = 1;
02636 } else {
02637 ast_log(LOG_DEBUG, "Need destroy, but can't do it yet!\n");
02638 if (s->waiting_thread != AST_PTHREADT_NULL)
02639 pthread_kill(s->waiting_thread, SIGURG);
02640 s->inuse--;
02641 }
02642 } else
02643 s->inuse--;
02644 ast_mutex_unlock(&s->__lock);
02645
02646 if (blastaway)
02647 destroy_session(s);
02648 generic_callback_out:
02649 if (*status != 200)
02650 return ast_http_error(500, "Server Error", NULL, "Internal Server Error (out of memory)\n");
02651 return retval;
02652 }
02653
02654 static char *manager_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
02655 {
02656 return generic_http_callback(FORMAT_HTML, requestor, uri, params, status, title, contentlength);
02657 }
02658
02659 static char *mxml_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
02660 {
02661 return generic_http_callback(FORMAT_XML, requestor, uri, params, status, title, contentlength);
02662 }
02663
02664 static char *rawman_http_callback(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength)
02665 {
02666 return generic_http_callback(FORMAT_RAW, requestor, uri, params, status, title, contentlength);
02667 }
02668
02669 struct ast_http_uri rawmanuri = {
02670 .description = "Raw HTTP Manager Event Interface",
02671 .uri = "rawman",
02672 .has_subtree = 0,
02673 .callback = rawman_http_callback,
02674 };
02675
02676 struct ast_http_uri manageruri = {
02677 .description = "HTML Manager Event Interface",
02678 .uri = "manager",
02679 .has_subtree = 0,
02680 .callback = manager_http_callback,
02681 };
02682
02683 struct ast_http_uri managerxmluri = {
02684 .description = "XML Manager Event Interface",
02685 .uri = "mxml",
02686 .has_subtree = 0,
02687 .callback = mxml_http_callback,
02688 };
02689
02690 static int registered = 0;
02691 static int webregged = 0;
02692
02693 int init_manager(void)
02694 {
02695 struct ast_config *cfg = NULL;
02696 const char *val;
02697 char *cat = NULL;
02698 int oldportno = portno;
02699 static struct sockaddr_in ba;
02700 int x = 1;
02701 int flags;
02702 int webenabled = 0;
02703 int newhttptimeout = 60;
02704 struct ast_manager_user *user = NULL;
02705
02706 if (!registered) {
02707
02708 ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
02709 ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
02710 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
02711 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
02712 ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
02713 ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
02714 ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
02715 ast_manager_register2("GetConfig", EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
02716 ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
02717 ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
02718 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
02719 ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
02720 ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
02721 ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
02722 ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
02723 ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
02724 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
02725 ast_manager_register2("UserEvent", EVENT_FLAG_USER, action_userevent, "Send an arbitrary event", mandescr_userevent);
02726 ast_manager_register2("WaitEvent", 0, action_waitevent, "Wait for an event to occur", mandescr_waitevent);
02727
02728 ast_cli_register_multiple(cli_manager, sizeof(cli_manager) / sizeof(struct ast_cli_entry));
02729 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
02730 registered = 1;
02731
02732 append_event("Event: Placeholder\r\n\r\n", 0);
02733 }
02734 portno = DEFAULT_MANAGER_PORT;
02735 displayconnects = 1;
02736 cfg = ast_config_load("manager.conf");
02737 if (!cfg) {
02738 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
02739 return 0;
02740 }
02741 val = ast_variable_retrieve(cfg, "general", "enabled");
02742 if (val)
02743 enabled = ast_true(val);
02744
02745 val = ast_variable_retrieve(cfg, "general", "block-sockets");
02746 if (val)
02747 block_sockets = ast_true(val);
02748
02749 val = ast_variable_retrieve(cfg, "general", "webenabled");
02750 if (val)
02751 webenabled = ast_true(val);
02752
02753 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
02754 if (sscanf(val, "%d", &portno) != 1) {
02755 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
02756 portno = DEFAULT_MANAGER_PORT;
02757 }
02758 }
02759
02760 if ((val = ast_variable_retrieve(cfg, "general", "displayconnects")))
02761 displayconnects = ast_true(val);
02762
02763 if ((val = ast_variable_retrieve(cfg, "general", "timestampevents")))
02764 timestampevents = ast_true(val);
02765
02766 if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
02767 newhttptimeout = atoi(val);
02768
02769 memset(&ba, 0, sizeof(ba));
02770 ba.sin_family = AF_INET;
02771 ba.sin_port = htons(portno);
02772
02773 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
02774 if (!inet_aton(val, &ba.sin_addr)) {
02775 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
02776 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
02777 }
02778 }
02779
02780
02781 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
02782 #if 0
02783
02784 close(asock);
02785 asock = -1;
02786 #else
02787 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
02788 #endif
02789 }
02790
02791 AST_LIST_LOCK(&users);
02792
02793 while ((cat = ast_category_browse(cfg, cat))) {
02794 struct ast_variable *var = NULL;
02795
02796 if (!strcasecmp(cat, "general"))
02797 continue;
02798
02799
02800 if (!(user = ast_get_manager_by_name_locked(cat))) {
02801 if (!(user = ast_calloc(1, sizeof(*user))))
02802 break;
02803
02804 ast_copy_string(user->username, cat, sizeof(user->username));
02805
02806 AST_LIST_INSERT_TAIL(&users, user, list);
02807 }
02808
02809
02810 user->keep = 1;
02811
02812 var = ast_variable_browse(cfg, cat);
02813 while (var) {
02814 if (!strcasecmp(var->name, "secret")) {
02815 if (user->secret)
02816 free(user->secret);
02817 user->secret = ast_strdup(var->value);
02818 } else if (!strcasecmp(var->name, "deny") ) {
02819 if (user->deny)
02820 free(user->deny);
02821 user->deny = ast_strdup(var->value);
02822 } else if (!strcasecmp(var->name, "permit") ) {
02823 if (user->permit)
02824 free(user->permit);
02825 user->permit = ast_strdup(var->value);
02826 } else if (!strcasecmp(var->name, "read") ) {
02827 if (user->read)
02828 free(user->read);
02829 user->read = ast_strdup(var->value);
02830 } else if (!strcasecmp(var->name, "write") ) {
02831 if (user->write)
02832 free(user->write);
02833 user->write = ast_strdup(var->value);
02834 } else if (!strcasecmp(var->name, "displayconnects") )
02835 user->displayconnects = ast_true(var->value);
02836 else
02837 ast_log(LOG_DEBUG, "%s is an unknown option.\n", var->name);
02838 var = var->next;
02839 }
02840 }
02841
02842
02843 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, list) {
02844 if (user->keep) {
02845 user->keep = 0;
02846 continue;
02847 }
02848
02849 AST_LIST_REMOVE_CURRENT(&users, list);
02850
02851 if (user->secret)
02852 free(user->secret);
02853 if (user->deny)
02854 free(user->deny);
02855 if (user->permit)
02856 free(user->permit);
02857 if (user->read)
02858 free(user->read);
02859 if (user->write)
02860 free(user->write);
02861 free(user);
02862 }
02863 AST_LIST_TRAVERSE_SAFE_END
02864
02865 AST_LIST_UNLOCK(&users);
02866
02867 ast_config_destroy(cfg);
02868
02869 if (webenabled && enabled) {
02870 if (!webregged) {
02871 ast_http_uri_link(&rawmanuri);
02872 ast_http_uri_link(&manageruri);
02873 ast_http_uri_link(&managerxmluri);
02874 webregged = 1;
02875 }
02876 } else {
02877 if (webregged) {
02878 ast_http_uri_unlink(&rawmanuri);
02879 ast_http_uri_unlink(&manageruri);
02880 ast_http_uri_unlink(&managerxmluri);
02881 webregged = 0;
02882 }
02883 }
02884
02885 if (newhttptimeout > 0)
02886 httptimeout = newhttptimeout;
02887
02888
02889 if (!enabled)
02890 return 0;
02891
02892 if (asock < 0) {
02893 asock = socket(AF_INET, SOCK_STREAM, 0);
02894 if (asock < 0) {
02895 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
02896 return -1;
02897 }
02898 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
02899 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
02900 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
02901 close(asock);
02902 asock = -1;
02903 return -1;
02904 }
02905 if (listen(asock, 2)) {
02906 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
02907 close(asock);
02908 asock = -1;
02909 return -1;
02910 }
02911 flags = fcntl(asock, F_GETFL);
02912 fcntl(asock, F_SETFL, flags | O_NONBLOCK);
02913 if (option_verbose)
02914 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
02915 ast_pthread_create_background(&t, NULL, accept_thread, NULL);
02916 }
02917 return 0;
02918 }
02919
02920 int reload_manager(void)
02921 {
02922 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
02923 return init_manager();
02924 }