00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <sys/time.h>
00018 #include <sys/types.h>
00019 #include <netdb.h>
00020 #include <sys/socket.h>
00021 #include <netinet/in.h>
00022 #include <netinet/tcp.h>
00023 #include <arpa/inet.h>
00024 #include <signal.h>
00025 #include <errno.h>
00026 #include <unistd.h>
00027 #include <sys/poll.h>
00028 #include <asterisk/channel.h>
00029 #include <asterisk/file.h>
00030 #include <asterisk/manager.h>
00031 #include <asterisk/config.h>
00032 #include <asterisk/lock.h>
00033 #include <asterisk/logger.h>
00034 #include <asterisk/options.h>
00035 #include <asterisk/cli.h>
00036 #include <asterisk/app.h>
00037 #include <asterisk/pbx.h>
00038 #include <asterisk/md5.h>
00039 #include <asterisk/acl.h>
00040 #include <asterisk/utils.h>
00041
00042 struct fast_originate_helper
00043 {
00044 char tech[256];
00045 char data[256];
00046 int timeout;
00047 char app[256];
00048 char appdata[256];
00049 char callerid[256];
00050 char variable[256];
00051 char account[256];
00052 char context[256];
00053 char exten[256];
00054 char idtext[256];
00055 int priority;
00056 };
00057
00058 static int enabled = 0;
00059 static int portno = DEFAULT_MANAGER_PORT;
00060 static int asock = -1;
00061 static pthread_t t;
00062 AST_MUTEX_DEFINE_STATIC(sessionlock);
00063 static int block_sockets = 0;
00064
00065 static struct permalias {
00066 int num;
00067 char *label;
00068 } perms[] = {
00069 { EVENT_FLAG_SYSTEM, "system" },
00070 { EVENT_FLAG_CALL, "call" },
00071 { EVENT_FLAG_LOG, "log" },
00072 { EVENT_FLAG_VERBOSE, "verbose" },
00073 { EVENT_FLAG_COMMAND, "command" },
00074 { EVENT_FLAG_AGENT, "agent" },
00075 { EVENT_FLAG_USER, "user" },
00076 { -1, "all" },
00077 };
00078
00079 static struct mansession *sessions = NULL;
00080 static struct manager_action *first_action = NULL;
00081 AST_MUTEX_DEFINE_STATIC(actionlock);
00082
00083 int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
00084 {
00085
00086
00087 int res=0;
00088 struct pollfd fds[1];
00089 while(len) {
00090 res = write(fd, s, len);
00091 if ((res < 0) && (errno != EAGAIN)) {
00092 return -1;
00093 }
00094 if (res < 0) res = 0;
00095 len -= res;
00096 s += res;
00097 fds[0].fd = fd;
00098 fds[0].events = POLLOUT;
00099
00100 res = poll(fds, 1, timeoutms);
00101 if (res < 1)
00102 return -1;
00103 }
00104 return res;
00105 }
00106
00107 static char *authority_to_str(int authority, char *res, int reslen)
00108 {
00109 int running_total = 0, i;
00110 memset(res, 0, reslen);
00111 for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
00112 if (authority & perms[i].num) {
00113 if (*res) {
00114 strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
00115 running_total++;
00116 }
00117 strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
00118 running_total += strlen(perms[i].label);
00119 }
00120 }
00121 return res;
00122 }
00123
00124 static char *complete_show_mancmd(char *line, char *word, int pos, int state)
00125 {
00126 struct manager_action *cur = first_action;
00127 int which = 0;
00128
00129 ast_mutex_lock(&actionlock);
00130 while (cur) {
00131 if (!strncasecmp(word, cur->action, strlen(word))) {
00132 if (++which > state) {
00133 char *ret = strdup(cur->action);
00134 ast_mutex_unlock(&actionlock);
00135 return ret;
00136 }
00137 }
00138 cur = cur->next;
00139 }
00140 ast_mutex_unlock(&actionlock);
00141 return NULL;
00142 }
00143
00144 static int handle_showmancmd(int fd, int argc, char *argv[])
00145 {
00146 struct manager_action *cur = first_action;
00147 char authority[80];
00148 int num;
00149
00150 if (argc != 4)
00151 return RESULT_SHOWUSAGE;
00152 ast_mutex_lock(&actionlock);
00153 while (cur) {
00154 for (num = 3; num < argc; num++) {
00155 if (!strcasecmp(cur->action, argv[num])) {
00156 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 : "");
00157 }
00158 }
00159 cur = cur->next;
00160 }
00161
00162 ast_mutex_unlock(&actionlock);
00163 return RESULT_SUCCESS;
00164 }
00165
00166 static int handle_showmancmds(int fd, int argc, char *argv[])
00167 {
00168 struct manager_action *cur = first_action;
00169 char authority[80];
00170 char *format = " %-15.15s %-10.10s %-45.45s\n";
00171
00172 ast_mutex_lock(&actionlock);
00173 ast_cli(fd, format, "Action", "Privilege", "Synopsis");
00174 while (cur) {
00175 ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
00176 cur = cur->next;
00177 }
00178
00179 ast_mutex_unlock(&actionlock);
00180 return RESULT_SUCCESS;
00181 }
00182
00183 static int handle_showmanconn(int fd, int argc, char *argv[])
00184 {
00185 struct mansession *s;
00186 char iabuf[INET_ADDRSTRLEN];
00187 char *format = " %-15.15s %-15.15s\n";
00188 ast_mutex_lock(&sessionlock);
00189 s = sessions;
00190 ast_cli(fd, format, "Username", "IP Address");
00191 while (s) {
00192 ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
00193 s = s->next;
00194 }
00195
00196 ast_mutex_unlock(&sessionlock);
00197 return RESULT_SUCCESS;
00198 }
00199
00200 static char showmancmd_help[] =
00201 "Usage: show manager command <actionname>\n"
00202 " Shows the detailed description for a specific manager command.\n";
00203
00204 static char showmancmds_help[] =
00205 "Usage: show manager commands\n"
00206 " Prints a listing of all the available manager commands.\n";
00207
00208 static char showmanconn_help[] =
00209 "Usage: show manager connected\n"
00210 " Prints a listing of the users that are connected to the\n"
00211 "manager interface.\n";
00212
00213 static struct ast_cli_entry show_mancmd_cli =
00214 { { "show", "manager", "command", NULL },
00215 handle_showmancmd, "Show manager command", showmancmd_help, complete_show_mancmd };
00216
00217 static struct ast_cli_entry show_mancmds_cli =
00218 { { "show", "manager", "commands", NULL },
00219 handle_showmancmds, "Show manager commands", showmancmds_help };
00220
00221 static struct ast_cli_entry show_manconn_cli =
00222 { { "show", "manager", "connected", NULL },
00223 handle_showmanconn, "Show connected manager users", showmanconn_help };
00224
00225 static void destroy_session(struct mansession *s)
00226 {
00227 struct mansession *cur, *prev = NULL;
00228 ast_mutex_lock(&sessionlock);
00229 cur = sessions;
00230 while(cur) {
00231 if (cur == s)
00232 break;
00233 prev = cur;
00234 cur = cur->next;
00235 }
00236 if (cur) {
00237 if (prev)
00238 prev->next = cur->next;
00239 else
00240 sessions = cur->next;
00241 if (s->fd > -1)
00242 close(s->fd);
00243 ast_mutex_destroy(&s->lock);
00244 free(s);
00245 } else
00246 ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
00247 ast_mutex_unlock(&sessionlock);
00248
00249 }
00250
00251 char *astman_get_header(struct message *m, char *var)
00252 {
00253 char cmp[80];
00254 int x;
00255 snprintf(cmp, sizeof(cmp), "%s: ", var);
00256 for (x=0;x<m->hdrcount;x++)
00257 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
00258 return m->headers[x] + strlen(cmp);
00259 return "";
00260 }
00261
00262 void astman_send_error(struct mansession *s, struct message *m, char *error)
00263 {
00264 char *id = astman_get_header(m,"ActionID");
00265 ast_mutex_lock(&s->lock);
00266 ast_cli(s->fd, "Response: Error\r\n");
00267 if (id && !ast_strlen_zero(id))
00268 ast_cli(s->fd, "ActionID: %s\r\n",id);
00269 ast_cli(s->fd, "Message: %s\r\n\r\n", error);
00270 ast_mutex_unlock(&s->lock);
00271 }
00272
00273 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
00274 {
00275 char *id = astman_get_header(m,"ActionID");
00276 ast_mutex_lock(&s->lock);
00277 ast_cli(s->fd, "Response: %s\r\n", resp);
00278 if (id && !ast_strlen_zero(id))
00279 ast_cli(s->fd, "ActionID: %s\r\n",id);
00280 if (msg)
00281 ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
00282 else
00283 ast_cli(s->fd, "\r\n");
00284 ast_mutex_unlock(&s->lock);
00285 }
00286
00287 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
00288 {
00289 astman_send_response(s, m, "Success", msg);
00290 }
00291
00292
00293
00294
00295
00296
00297 static int ast_instring(char *bigstr, char *smallstr, char delim)
00298 {
00299 char *val = bigstr, *next;
00300
00301 do {
00302 if ((next = strchr(val, delim))) {
00303 if (!strncmp(val, smallstr, (next - val)))
00304 return 1;
00305 else
00306 continue;
00307 } else
00308 return !strcmp(smallstr, val);
00309
00310 } while (*(val = (next + 1)));
00311
00312 return 0;
00313 }
00314
00315 static int get_perm(char *instr)
00316 {
00317 int x = 0, ret = 0;
00318
00319 if (!instr)
00320 return 0;
00321
00322 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
00323 if (ast_instring(instr, perms[x].label, ','))
00324 ret |= perms[x].num;
00325
00326 return ret;
00327 }
00328
00329 static int ast_is_number(char *string)
00330 {
00331 int ret = 1, x = 0;
00332
00333 if (!string)
00334 return 0;
00335
00336 for (x=0; x < strlen(string); x++) {
00337 if (!(string[x] >= 48 && string[x] <= 57)) {
00338 ret = 0;
00339 break;
00340 }
00341 }
00342
00343 return ret ? atoi(string) : 0;
00344 }
00345
00346 static int ast_strings_to_mask(char *string)
00347 {
00348 int x = 0, ret = -1;
00349
00350 x = ast_is_number(string);
00351
00352 if (x)
00353 ret = x;
00354 else if (!string || ast_strlen_zero(string))
00355 ret = -1;
00356 else if (!strcasecmp(string, "off") || ast_false(string))
00357 ret = 0;
00358 else if (!strcasecmp(string, "on") || ast_true(string))
00359 ret = -1;
00360 else {
00361 ret = 0;
00362 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
00363 if (ast_instring(string, perms[x].label, ','))
00364 ret |= perms[x].num;
00365 }
00366 }
00367
00368 return ret;
00369 }
00370
00371
00372
00373
00374
00375
00376 static int set_eventmask(struct mansession *s, char *eventmask)
00377 {
00378 int maskint = ast_strings_to_mask(eventmask);
00379
00380 ast_mutex_lock(&s->lock);
00381 s->send_events = maskint;
00382 ast_mutex_unlock(&s->lock);
00383
00384 return s->send_events;
00385 }
00386
00387 static int authenticate(struct mansession *s, struct message *m)
00388 {
00389 struct ast_config *cfg;
00390 char iabuf[INET_ADDRSTRLEN];
00391 char *cat;
00392 char *user = astman_get_header(m, "Username");
00393 char *pass = astman_get_header(m, "Secret");
00394 char *authtype = astman_get_header(m, "AuthType");
00395 char *key = astman_get_header(m, "Key");
00396 char *events = astman_get_header(m, "Events");
00397
00398 cfg = ast_load("manager.conf");
00399 if (!cfg)
00400 return -1;
00401 cat = ast_category_browse(cfg, NULL);
00402 while(cat) {
00403 if (strcasecmp(cat, "general")) {
00404
00405 if (!strcasecmp(cat, user)) {
00406 struct ast_variable *v;
00407 struct ast_ha *ha = NULL;
00408 char *password = NULL;
00409 v = ast_variable_browse(cfg, cat);
00410 while (v) {
00411 if (!strcasecmp(v->name, "secret")) {
00412 password = v->value;
00413 } else if (!strcasecmp(v->name, "permit") ||
00414 !strcasecmp(v->name, "deny")) {
00415 ha = ast_append_ha(v->name, v->value, ha);
00416 }
00417 v = v->next;
00418 }
00419 if (ha && !ast_apply_ha(ha, &(s->sin))) {
00420 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
00421 ast_free_ha(ha);
00422 ast_destroy(cfg);
00423 return -1;
00424 } else if (ha)
00425 ast_free_ha(ha);
00426 if (!strcasecmp(authtype, "MD5")) {
00427 if (key && !ast_strlen_zero(key) && s->challenge) {
00428 int x;
00429 int len=0;
00430 char md5key[256] = "";
00431 struct MD5Context md5;
00432 unsigned char digest[16];
00433 MD5Init(&md5);
00434 MD5Update(&md5, s->challenge, strlen(s->challenge));
00435 MD5Update(&md5, password, strlen(password));
00436 MD5Final(digest, &md5);
00437 for (x=0;x<16;x++)
00438 len += sprintf(md5key + len, "%2.2x", digest[x]);
00439 if (!strcmp(md5key, key))
00440 break;
00441 else {
00442 ast_destroy(cfg);
00443 return -1;
00444 }
00445 }
00446 } else if (password && !strcasecmp(password, pass)) {
00447 break;
00448 } else {
00449 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
00450 ast_destroy(cfg);
00451 return -1;
00452 }
00453 }
00454 }
00455 cat = ast_category_browse(cfg, cat);
00456 }
00457 if (cat) {
00458 strncpy(s->username, cat, sizeof(s->username) - 1);
00459 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
00460 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
00461 ast_destroy(cfg);
00462 if (events)
00463 set_eventmask(s, events);
00464 return 0;
00465 }
00466 ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
00467 ast_destroy(cfg);
00468 return -1;
00469 }
00470
00471 static char mandescr_ping[] =
00472 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the "
00473 " manager connection open.\n"
00474 "Variables: NONE\n";
00475
00476 static int action_ping(struct mansession *s, struct message *m)
00477 {
00478 astman_send_response(s, m, "Pong", NULL);
00479 return 0;
00480 }
00481
00482 static char mandescr_listcommands[] =
00483 "Description: Returns the action name and synopsis for every\n"
00484 " action that is available to the user\n"
00485 "Variables: NONE\n";
00486
00487 static int action_listcommands(struct mansession *s, struct message *m)
00488 {
00489 struct manager_action *cur = first_action;
00490 char idText[256] = "";
00491 char *id = astman_get_header(m,"ActionID");
00492
00493 if (id && !ast_strlen_zero(id))
00494 snprintf(idText,256,"ActionID: %s\r\n",id);
00495 ast_cli(s->fd, "Response: Success\r\n%s", idText);
00496 ast_mutex_lock(&s->lock);
00497 ast_mutex_lock(&actionlock);
00498 while (cur) {
00499 if ((s->writeperm & cur->authority) == cur->authority)
00500 ast_cli(s->fd, "%s: %s\r\n", cur->action, cur->synopsis);
00501 cur = cur->next;
00502 }
00503 ast_mutex_unlock(&actionlock);
00504 ast_cli(s->fd, "\r\n");
00505 ast_mutex_unlock(&s->lock);
00506
00507 return 0;
00508 }
00509
00510 static char mandescr_events[] =
00511 "Description: Enable/Disable sending of events to this manager\n"
00512 " client.\n"
00513 "Variables:\n"
00514 " EventMask: 'on' if all events should be sent,\n"
00515 " 'off' if no events should be sent,\n"
00516 " 'system,call,log' to select which flags events should have to be sent.\n";
00517
00518 static int action_events(struct mansession *s, struct message *m)
00519 {
00520 char *mask = astman_get_header(m, "EventMask");
00521 int res;
00522
00523 res = set_eventmask(s, mask);
00524 if (res > 0)
00525 astman_send_response(s, m, "Events On", NULL);
00526 else if (res == 0)
00527 astman_send_response(s, m, "Events Off", NULL);
00528
00529 return 0;
00530 }
00531
00532 static char mandescr_logoff[] =
00533 "Description: Logoff this manager session\n"
00534 "Variables: NONE\n";
00535
00536 static int action_logoff(struct mansession *s, struct message *m)
00537 {
00538 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
00539 return -1;
00540 }
00541
00542 static char mandescr_hangup[] =
00543 "Description: Hangup a channel\n"
00544 "Variables: \n"
00545 " Channel: The channel name to be hungup\n";
00546
00547 static int action_hangup(struct mansession *s, struct message *m)
00548 {
00549 struct ast_channel *c = NULL;
00550 char *name = astman_get_header(m, "Channel");
00551 if (ast_strlen_zero(name)) {
00552 astman_send_error(s, m, "No channel specified");
00553 return 0;
00554 }
00555 c = ast_channel_walk_locked(NULL);
00556 while(c) {
00557 if (!strcasecmp(c->name, name)) {
00558 break;
00559 }
00560 ast_mutex_unlock(&c->lock);
00561 c = ast_channel_walk_locked(c);
00562 }
00563 if (!c) {
00564 astman_send_error(s, m, "No such channel");
00565 return 0;
00566 }
00567 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
00568 ast_mutex_unlock(&c->lock);
00569 astman_send_ack(s, m, "Channel Hungup");
00570 return 0;
00571 }
00572
00573 static int action_setvar(struct mansession *s, struct message *m)
00574 {
00575 struct ast_channel *c = NULL;
00576 char *name = astman_get_header(m, "Channel");
00577 char *varname = astman_get_header(m, "Variable");
00578 char *varval = astman_get_header(m, "Value");
00579
00580 if (!strlen(name)) {
00581 astman_send_error(s, m, "No channel specified");
00582 return 0;
00583 }
00584 if (!strlen(varname)) {
00585 astman_send_error(s, m, "No variable specified");
00586 return 0;
00587 }
00588
00589 c = ast_channel_walk_locked(NULL);
00590 while(c) {
00591 if (!strcasecmp(c->name, name)) {
00592 break;
00593 }
00594 ast_mutex_unlock(&c->lock);
00595 c = ast_channel_walk_locked(c);
00596 }
00597 if (!c) {
00598 astman_send_error(s, m, "No such channel");
00599 return 0;
00600 }
00601
00602 pbx_builtin_setvar_helper(c,varname,varval);
00603
00604 ast_mutex_unlock(&c->lock);
00605 astman_send_ack(s, m, "Variable Set");
00606 return 0;
00607 }
00608
00609 static int action_getvar(struct mansession *s, struct message *m)
00610 {
00611 struct ast_channel *c = NULL;
00612 char *name = astman_get_header(m, "Channel");
00613 char *varname = astman_get_header(m, "Variable");
00614 char *id = astman_get_header(m,"ActionID");
00615 char *varval;
00616
00617 if (!strlen(name)) {
00618 astman_send_error(s, m, "No channel specified");
00619 return 0;
00620 }
00621 if (!strlen(varname)) {
00622 astman_send_error(s, m, "No variable specified");
00623 return 0;
00624 }
00625
00626 c = ast_channel_walk_locked(NULL);
00627 while(c) {
00628 if (!strcasecmp(c->name, name)) {
00629 break;
00630 }
00631 ast_mutex_unlock(&c->lock);
00632 c = ast_channel_walk_locked(c);
00633 }
00634 if (!c) {
00635 astman_send_error(s, m, "No such channel");
00636 return 0;
00637 }
00638
00639 varval=pbx_builtin_getvar_helper(c,varname);
00640
00641 ast_mutex_unlock(&c->lock);
00642 ast_mutex_lock(&s->lock);
00643 ast_cli(s->fd, "Response: Success\r\n"
00644 "%s: %s\r\n" ,varname,varval);
00645 if (id && !ast_strlen_zero(id))
00646 ast_cli(s->fd, "ActionID: %s\r\n",id);
00647 ast_cli(s->fd, "\r\n");
00648 ast_mutex_unlock(&s->lock);
00649
00650 return 0;
00651 }
00652
00653
00654 static int action_status(struct mansession *s, struct message *m)
00655 {
00656 char *id = astman_get_header(m,"ActionID");
00657 char *name = astman_get_header(m,"Channel");
00658 char idText[256] = "";
00659 struct ast_channel *c;
00660 char bridge[256];
00661 struct timeval now;
00662 long elapsed_seconds=0;
00663
00664 gettimeofday(&now, NULL);
00665 astman_send_ack(s, m, "Channel status will follow");
00666 c = ast_channel_walk_locked(NULL);
00667 if (id && !ast_strlen_zero(id))
00668 snprintf(idText,256,"ActionID: %s\r\n",id);
00669 if (name && !ast_strlen_zero(name)) {
00670 while (c) {
00671 if (!strcasecmp(c->name, name)) {
00672 break;
00673 }
00674 ast_mutex_unlock(&c->lock);
00675 c = ast_channel_walk_locked(c);
00676 }
00677 if (!c) {
00678 astman_send_error(s, m, "No such channel");
00679 return 0;
00680 }
00681 }
00682 while(c) {
00683 if (c->bridge)
00684 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
00685 else
00686 bridge[0] = '\0';
00687 ast_mutex_lock(&s->lock);
00688 if (c->pbx) {
00689 if (c->cdr) {
00690 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
00691 }
00692 ast_cli(s->fd,
00693 "Event: Status\r\n"
00694 "Channel: %s\r\n"
00695 "CallerID: %s\r\n"
00696 "Account: %s\r\n"
00697 "State: %s\r\n"
00698 "Context: %s\r\n"
00699 "Extension: %s\r\n"
00700 "Priority: %d\r\n"
00701 "Seconds: %ld\r\n"
00702 "%s"
00703 "Uniqueid: %s\r\n"
00704 "%s"
00705 "\r\n",
00706 c->name, c->callerid ? c->callerid : "<unknown>",
00707 c->accountcode,
00708 ast_state2str(c->_state), c->context,
00709 c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
00710 } else {
00711 ast_cli(s->fd,
00712 "Event: Status\r\n"
00713 "Channel: %s\r\n"
00714 "CallerID: %s\r\n"
00715 "Account: %s\r\n"
00716 "State: %s\r\n"
00717 "%s"
00718 "Uniqueid: %s\r\n"
00719 "%s"
00720 "\r\n",
00721 c->name, c->callerid ? c->callerid : "<unknown>",
00722 c->accountcode,
00723 ast_state2str(c->_state), bridge, c->uniqueid, idText);
00724 }
00725 ast_mutex_unlock(&s->lock);
00726 ast_mutex_unlock(&c->lock);
00727 if (name && !ast_strlen_zero(name)) {
00728 break;
00729 }
00730 c = ast_channel_walk_locked(c);
00731 }
00732 ast_mutex_lock(&s->lock);
00733 ast_cli(s->fd,
00734 "Event: StatusComplete\r\n"
00735 "%s"
00736 "\r\n",idText);
00737 ast_mutex_unlock(&s->lock);
00738 return 0;
00739 }
00740
00741 static int action_redirect(struct mansession *s, struct message *m)
00742 {
00743 char *name = astman_get_header(m, "Channel");
00744 char *name2 = astman_get_header(m, "ExtraChannel");
00745 char *exten = astman_get_header(m, "Exten");
00746 char *context = astman_get_header(m, "Context");
00747 char *priority = astman_get_header(m, "Priority");
00748 struct ast_channel *chan, *chan2 = NULL;
00749 int pi = 0;
00750 int res;
00751 if (!name || ast_strlen_zero(name)) {
00752 astman_send_error(s, m, "Channel not specified");
00753 return 0;
00754 }
00755 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
00756 astman_send_error(s, m, "Invalid priority\n");
00757 return 0;
00758 }
00759 chan = ast_get_channel_by_name_locked(name);
00760 if (!chan) {
00761 astman_send_error(s, m, "Channel not existant");
00762 return 0;
00763 }
00764 if (!ast_strlen_zero(name2))
00765 chan2 = ast_get_channel_by_name_locked(name2);
00766 res = ast_async_goto(chan, context, exten, pi);
00767 if (!res) {
00768 if (!ast_strlen_zero(name2)) {
00769 if (chan2)
00770 res = ast_async_goto(chan2, context, exten, pi);
00771 else
00772 res = -1;
00773 if (!res)
00774 astman_send_ack(s, m, "Dual Redirect successful");
00775 else
00776 astman_send_error(s, m, "Secondary redirect failed");
00777 } else
00778 astman_send_ack(s, m, "Redirect successful");
00779 } else
00780 astman_send_error(s, m, "Redirect failed");
00781 if (chan)
00782 ast_mutex_unlock(&chan->lock);
00783 if (chan2)
00784 ast_mutex_unlock(&chan2->lock);
00785 return 0;
00786 }
00787
00788 static int action_command(struct mansession *s, struct message *m)
00789 {
00790 char *cmd = astman_get_header(m, "Command");
00791 char *id = astman_get_header(m, "ActionID");
00792 ast_mutex_lock(&s->lock);
00793 s->blocking = 1;
00794 ast_mutex_unlock(&s->lock);
00795 ast_cli(s->fd, "Response: Follows\r\n");
00796 if (id && !ast_strlen_zero(id))
00797 ast_cli(s->fd, "ActionID: %s\r\n", id);
00798
00799 ast_cli_command(s->fd, cmd);
00800 ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
00801 ast_mutex_lock(&s->lock);
00802 s->blocking = 0;
00803 ast_mutex_unlock(&s->lock);
00804 return 0;
00805 }
00806
00807 static void *fast_originate(void *data)
00808 {
00809 struct fast_originate_helper *in = data;
00810 int res;
00811 int reason = 0;
00812 if (!ast_strlen_zero(in->app)) {
00813 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, !ast_strlen_zero(in->callerid) ? in->callerid : NULL, in->variable, in->account);
00814 } else {
00815 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, !ast_strlen_zero(in->callerid) ? in->callerid : NULL, in->variable, in->account);
00816 }
00817 if (!res)
00818 manager_event(EVENT_FLAG_CALL,
00819 "OriginateSuccess",
00820 "%s"
00821 "Channel: %s/%s\r\n"
00822 "Context: %s\r\n"
00823 "Exten: %s\r\n",
00824 in->idtext, in->tech, in->data, in->context, in->exten);
00825 else
00826 manager_event(EVENT_FLAG_CALL,
00827 "OriginateFailure",
00828 "%s"
00829 "Channel: %s/%s\r\n"
00830 "Context: %s\r\n"
00831 "Exten: %s\r\n",
00832 in->idtext, in->tech, in->data, in->context, in->exten);
00833
00834 free(in);
00835 return NULL;
00836 }
00837
00838 static char mandescr_originate[] =
00839 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
00840 " Application/Data\n"
00841 "Variables: (Names marked with * are required)\n"
00842 " *Channel: Channel name to call\n"
00843 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
00844 " Context: Context to use (requires 'Exten' and 'Priority')\n"
00845 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
00846 " Application: Application to use\n"
00847 " Data: Data to use (requires 'Application')\n"
00848 " Timeout: How long to wait for call to be answered (in ms)\n"
00849 " CallerID: Caller ID to be set on the outgoing channel\n"
00850 " Variable: Channel variable to set (VAR1=value1|VAR2=value2)\n"
00851 " Account: Account code\n"
00852 " Async: Set to 'true' for fast origination\n";
00853
00854 static int action_originate(struct mansession *s, struct message *m)
00855 {
00856 char *name = astman_get_header(m, "Channel");
00857 char *exten = astman_get_header(m, "Exten");
00858 char *context = astman_get_header(m, "Context");
00859 char *priority = astman_get_header(m, "Priority");
00860 char *timeout = astman_get_header(m, "Timeout");
00861 char *callerid = astman_get_header(m, "CallerID");
00862 char *variable = astman_get_header(m, "Variable");
00863 char *account = astman_get_header(m, "Account");
00864 char *app = astman_get_header(m, "Application");
00865 char *appdata = astman_get_header(m, "Data");
00866 char *async = astman_get_header(m, "Async");
00867 char *id = astman_get_header(m, "ActionID");
00868 char *tech, *data;
00869 int pi = 0;
00870 int res;
00871 int to = 30000;
00872 int reason = 0;
00873 char tmp[256];
00874 pthread_t th;
00875 pthread_attr_t attr;
00876 if (!name) {
00877 astman_send_error(s, m, "Channel not specified");
00878 return 0;
00879 }
00880 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
00881 astman_send_error(s, m, "Invalid priority\n");
00882 return 0;
00883 }
00884 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
00885 astman_send_error(s, m, "Invalid timeout\n");
00886 return 0;
00887 }
00888 strncpy(tmp, name, sizeof(tmp) - 1);
00889 tech = tmp;
00890 data = strchr(tmp, '/');
00891 if (!data) {
00892 astman_send_error(s, m, "Invalid channel\n");
00893 return 0;
00894 }
00895 *data = '\0';
00896 data++;
00897 if (ast_true(async)) {
00898 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
00899 if (!fast) {
00900 res = -1;
00901 } else {
00902 memset(fast, 0, sizeof(struct fast_originate_helper));
00903 if (id && !ast_strlen_zero(id))
00904 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
00905 strncpy(fast->tech, tech, sizeof(fast->tech) - 1);
00906 strncpy(fast->data, data, sizeof(fast->data) - 1);
00907 strncpy(fast->app, app, sizeof(fast->app) - 1);
00908 strncpy(fast->appdata, appdata, sizeof(fast->appdata) - 1);
00909 strncpy(fast->callerid, callerid, sizeof(fast->callerid) - 1);
00910 strncpy(fast->variable, variable, sizeof(fast->variable) - 1);
00911 strncpy(fast->account, account, sizeof(fast->account) - 1);
00912 strncpy(fast->context, context, sizeof(fast->context) - 1);
00913 strncpy(fast->exten, exten, sizeof(fast->exten) - 1);
00914 fast->timeout = to;
00915 fast->priority = pi;
00916 pthread_attr_init(&attr);
00917 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00918 if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
00919 res = -1;
00920 } else {
00921 res = 0;
00922 }
00923 }
00924 } else if (!ast_strlen_zero(app)) {
00925 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
00926 } else {
00927 if (exten && context && pi)
00928 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account);
00929 else {
00930 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
00931 return 0;
00932 }
00933 }
00934 if (!res)
00935 astman_send_ack(s, m, "Originate successfully queued");
00936 else
00937 astman_send_error(s, m, "Originate failed");
00938 return 0;
00939 }
00940
00941 static int action_mailboxstatus(struct mansession *s, struct message *m)
00942 {
00943 char *mailbox = astman_get_header(m, "Mailbox");
00944 char *id = astman_get_header(m,"ActionID");
00945 char idText[256] = "";
00946 int ret;
00947 if (!mailbox || ast_strlen_zero(mailbox)) {
00948 astman_send_error(s, m, "Mailbox not specified");
00949 return 0;
00950 }
00951 if (id && !ast_strlen_zero(id))
00952 snprintf(idText,256,"ActionID: %s\r\n",id);
00953 ret = ast_app_has_voicemail(mailbox);
00954 ast_mutex_lock(&s->lock);
00955 ast_cli(s->fd, "Response: Success\r\n"
00956 "%s"
00957 "Message: Mailbox Status\r\n"
00958 "Mailbox: %s\r\n"
00959 "Waiting: %d\r\n\r\n", idText, mailbox, ret);
00960 ast_mutex_unlock(&s->lock);
00961 return 0;
00962 }
00963
00964 static int action_mailboxcount(struct mansession *s, struct message *m)
00965 {
00966 char *mailbox = astman_get_header(m, "Mailbox");
00967 char *id = astman_get_header(m,"ActionID");
00968 char idText[256] = "";
00969 int newmsgs = 0, oldmsgs = 0;
00970 if (!mailbox || ast_strlen_zero(mailbox)) {
00971 astman_send_error(s, m, "Mailbox not specified");
00972 return 0;
00973 }
00974 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
00975 if (id && !ast_strlen_zero(id)) {
00976 snprintf(idText,256,"ActionID: %s\r\n",id);
00977 }
00978 ast_mutex_lock(&s->lock);
00979 ast_cli(s->fd, "Response: Success\r\n"
00980 "%s"
00981 "Message: Mailbox Message Count\r\n"
00982 "Mailbox: %s\r\n"
00983 "NewMessages: %d\r\n"
00984 "OldMessages: %d\r\n"
00985 "\r\n",
00986 idText,mailbox, newmsgs, oldmsgs);
00987 ast_mutex_unlock(&s->lock);
00988 return 0;
00989 }
00990
00991 static int action_extensionstate(struct mansession *s, struct message *m)
00992 {
00993 char *exten = astman_get_header(m, "Exten");
00994 char *context = astman_get_header(m, "Context");
00995 char *id = astman_get_header(m,"ActionID");
00996 char idText[256] = "";
00997 char hint[256] = "";
00998 int status;
00999 if (!exten || ast_strlen_zero(exten)) {
01000 astman_send_error(s, m, "Extension not specified");
01001 return 0;
01002 }
01003 if (!context || ast_strlen_zero(context))
01004 context = "default";
01005 status = ast_extension_state(NULL, context, exten);
01006 ast_get_hint(hint, sizeof(hint) - 1, NULL, context, exten);
01007 if (id && !ast_strlen_zero(id)) {
01008 snprintf(idText,256,"ActionID: %s\r\n",id);
01009 }
01010 ast_mutex_lock(&s->lock);
01011 ast_cli(s->fd, "Response: Success\r\n"
01012 "%s"
01013 "Message: Extension Status\r\n"
01014 "Exten: %s\r\n"
01015 "Context: %s\r\n"
01016 "Hint: %s\r\n"
01017 "Status: %d\r\n\r\n",
01018 idText,exten, context, hint, status);
01019 ast_mutex_unlock(&s->lock);
01020 return 0;
01021 }
01022
01023 static int action_timeout(struct mansession *s, struct message *m)
01024 {
01025 struct ast_channel *c = NULL;
01026 char *name = astman_get_header(m, "Channel");
01027 int timeout = atoi(astman_get_header(m, "Timeout"));
01028 if (ast_strlen_zero(name)) {
01029 astman_send_error(s, m, "No channel specified");
01030 return 0;
01031 }
01032 if (!timeout) {
01033 astman_send_error(s, m, "No timeout specified");
01034 return 0;
01035 }
01036 c = ast_channel_walk_locked(NULL);
01037 while(c) {
01038 if (!strcasecmp(c->name, name)) {
01039 break;
01040 }
01041 ast_mutex_unlock(&c->lock);
01042 c = ast_channel_walk_locked(c);
01043 }
01044 if (!c) {
01045 astman_send_error(s, m, "No such channel");
01046 return 0;
01047 }
01048 ast_channel_setwhentohangup(c, timeout);
01049 ast_mutex_unlock(&c->lock);
01050 astman_send_ack(s, m, "Timeout Set");
01051 return 0;
01052 }
01053
01054 static int process_message(struct mansession *s, struct message *m)
01055 {
01056 char action[80] = "";
01057 struct manager_action *tmp = first_action;
01058 char *id = astman_get_header(m,"ActionID");
01059 char idText[256] = "";
01060 char iabuf[INET_ADDRSTRLEN];
01061
01062 strncpy(action, astman_get_header(m, "Action"), sizeof(action) - 1);
01063 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
01064
01065 if (ast_strlen_zero(action)) {
01066 astman_send_error(s, m, "Missing action in request");
01067 return 0;
01068 }
01069 if (id && !ast_strlen_zero(id)) {
01070 snprintf(idText,256,"ActionID: %s\r\n",id);
01071 }
01072 if (!s->authenticated) {
01073 if (!strcasecmp(action, "Challenge")) {
01074 char *authtype;
01075 authtype = astman_get_header(m, "AuthType");
01076 if (!strcasecmp(authtype, "MD5")) {
01077 if (!s->challenge || ast_strlen_zero(s->challenge)) {
01078 ast_mutex_lock(&s->lock);
01079 snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
01080 ast_mutex_unlock(&s->lock);
01081 }
01082 ast_mutex_lock(&s->lock);
01083 ast_cli(s->fd, "Response: Success\r\n"
01084 "%s"
01085 "Challenge: %s\r\n\r\n",
01086 idText,s->challenge);
01087 ast_mutex_unlock(&s->lock);
01088 return 0;
01089 } else {
01090 astman_send_error(s, m, "Must specify AuthType");
01091 return 0;
01092 }
01093 } else if (!strcasecmp(action, "Login")) {
01094 if (authenticate(s, m)) {
01095 sleep(1);
01096 astman_send_error(s, m, "Authentication failed");
01097 return -1;
01098 } else {
01099 s->authenticated = 1;
01100 if (option_verbose > 1)
01101 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01102 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01103 astman_send_ack(s, m, "Authentication accepted");
01104 }
01105 } else if (!strcasecmp(action, "Logoff")) {
01106 astman_send_ack(s, m, "See ya");
01107 return -1;
01108 } else
01109 astman_send_error(s, m, "Authentication Required");
01110 } else {
01111 while( tmp ) {
01112 if (!strcasecmp(action, tmp->action)) {
01113 if ((s->writeperm & tmp->authority) == tmp->authority) {
01114 if (tmp->func(s, m))
01115 return -1;
01116 } else {
01117 astman_send_error(s, m, "Permission denied");
01118 }
01119 return 0;
01120 }
01121 tmp = tmp->next;
01122 }
01123 astman_send_error(s, m, "Invalid/unknown command");
01124 }
01125 return 0;
01126 }
01127
01128 static int get_input(struct mansession *s, char *output)
01129 {
01130
01131 int res;
01132 int x;
01133 struct pollfd fds[1];
01134 char iabuf[INET_ADDRSTRLEN];
01135 for (x=1;x<s->inlen;x++) {
01136 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
01137
01138 memcpy(output, s->inbuf, x + 1);
01139
01140 output[x+1] = '\0';
01141
01142 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
01143 s->inlen -= (x + 1);
01144 return 1;
01145 }
01146 }
01147 if (s->inlen >= sizeof(s->inbuf) - 1) {
01148 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf);
01149 s->inlen = 0;
01150 }
01151 fds[0].fd = s->fd;
01152 fds[0].events = POLLIN;
01153 res = poll(fds, 1, -1);
01154 if (res < 0) {
01155 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
01156 } else if (res > 0) {
01157 ast_mutex_lock(&s->lock);
01158 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
01159 ast_mutex_unlock(&s->lock);
01160 if (res < 1)
01161 return -1;
01162 }
01163 s->inlen += res;
01164 s->inbuf[s->inlen] = '\0';
01165 return 0;
01166 }
01167
01168 static void *session_do(void *data)
01169 {
01170 struct mansession *s = data;
01171 struct message m;
01172 char iabuf[INET_ADDRSTRLEN];
01173 int res;
01174
01175 ast_mutex_lock(&s->lock);
01176 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
01177 ast_mutex_unlock(&s->lock);
01178 memset(&m, 0, sizeof(&m));
01179 for (;;) {
01180 res = get_input(s, m.headers[m.hdrcount]);
01181 if (res > 0) {
01182
01183 if (strlen(m.headers[m.hdrcount]) < 2)
01184 continue;
01185 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
01186 if (ast_strlen_zero(m.headers[m.hdrcount])) {
01187 if (process_message(s, &m))
01188 break;
01189 memset(&m, 0, sizeof(&m));
01190 } else if (m.hdrcount < MAX_HEADERS - 1)
01191 m.hdrcount++;
01192 } else if (res < 0)
01193 break;
01194 }
01195 if (s->authenticated) {
01196 if (option_verbose > 1)
01197 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01198 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01199 } else {
01200 if (option_verbose > 1)
01201 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01202 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01203 }
01204 destroy_session(s);
01205 return NULL;
01206 }
01207
01208 static void *accept_thread(void *ignore)
01209 {
01210 int as;
01211 struct sockaddr_in sin;
01212 int sinlen;
01213 struct mansession *s;
01214 struct protoent *p;
01215 int arg = 1;
01216 int flags;
01217 pthread_attr_t attr;
01218
01219 pthread_attr_init(&attr);
01220 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01221
01222 for (;;) {
01223 sinlen = sizeof(sin);
01224 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
01225 if (as < 0) {
01226 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
01227 continue;
01228 }
01229 p = getprotobyname("tcp");
01230 if( p ) {
01231 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
01232 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
01233 }
01234 }
01235 s = malloc(sizeof(struct mansession));
01236 if (!s) {
01237 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
01238 continue;
01239 }
01240 memset(s, 0, sizeof(struct mansession));
01241 memcpy(&s->sin, &sin, sizeof(sin));
01242
01243 if(! block_sockets) {
01244
01245 flags = fcntl(as, F_GETFL);
01246 fcntl(as, F_SETFL, flags | O_NONBLOCK);
01247 }
01248 ast_mutex_init(&s->lock);
01249 s->fd = as;
01250 s->send_events = -1;
01251 ast_mutex_lock(&sessionlock);
01252 s->next = sessions;
01253 sessions = s;
01254 ast_mutex_unlock(&sessionlock);
01255 if (ast_pthread_create(&t, &attr, session_do, s))
01256 destroy_session(s);
01257 }
01258 pthread_attr_destroy(&attr);
01259 return NULL;
01260 }
01261
01262 int manager_event(int category, char *event, char *fmt, ...)
01263 {
01264 struct mansession *s;
01265 char tmp[4096];
01266 va_list ap;
01267
01268 ast_mutex_lock(&sessionlock);
01269 s = sessions;
01270 while(s) {
01271 if (((s->readperm & category) == category) && ((s->send_events & category) == category) ) {
01272 ast_mutex_lock(&s->lock);
01273 if (!s->blocking) {
01274 ast_cli(s->fd, "Event: %s\r\n", event);
01275 va_start(ap, fmt);
01276 vsnprintf(tmp, sizeof(tmp), fmt, ap);
01277 va_end(ap);
01278 ast_carefulwrite(s->fd,tmp,strlen(tmp),100);
01279 ast_cli(s->fd, "\r\n");
01280 }
01281 ast_mutex_unlock(&s->lock);
01282 }
01283 s = s->next;
01284 }
01285 ast_mutex_unlock(&sessionlock);
01286 return 0;
01287 }
01288
01289 int ast_manager_unregister( char *action ) {
01290 struct manager_action *cur = first_action, *prev = first_action;
01291
01292 ast_mutex_lock(&actionlock);
01293 while( cur ) {
01294 if (!strcasecmp(action, cur->action)) {
01295 prev->next = cur->next;
01296 free(cur);
01297 if (option_verbose > 1)
01298 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
01299 ast_mutex_unlock(&actionlock);
01300 return 0;
01301 }
01302 prev = cur;
01303 cur = cur->next;
01304 }
01305 ast_mutex_unlock(&actionlock);
01306 return 0;
01307 }
01308
01309 static int manager_state_cb(char *context, char *exten, int state, void *data)
01310 {
01311
01312 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
01313 return 0;
01314 }
01315
01316 static int ast_manager_register_struct(struct manager_action *act)
01317 {
01318 struct manager_action *cur = first_action, *prev = NULL;
01319 int ret;
01320
01321 ast_mutex_lock(&actionlock);
01322 while(cur) {
01323 ret = strcasecmp(cur->action, act->action);
01324 if (ret == 0) {
01325 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
01326 ast_mutex_unlock(&actionlock);
01327 return -1;
01328 } else if (ret > 0) {
01329
01330 if (prev) {
01331 act->next = prev->next;
01332 prev->next = act;
01333 } else {
01334 act->next = first_action;
01335 first_action = act;
01336 }
01337 break;
01338 }
01339 prev = cur;
01340 cur = cur->next;
01341 }
01342
01343 if (!cur) {
01344 if (prev)
01345 prev->next = act;
01346 else
01347 first_action = act;
01348 act->next = NULL;
01349 }
01350
01351 if (option_verbose > 1)
01352 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
01353 ast_mutex_unlock(&actionlock);
01354 return 0;
01355 }
01356
01357 int ast_manager_register2(char *action, int auth, int (*func)(struct mansession *s, struct message *m), char *synopsis, char *description)
01358 {
01359 struct manager_action *cur;
01360
01361 cur = malloc(sizeof(struct manager_action));
01362 if (!cur) {
01363 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
01364 ast_mutex_unlock(&actionlock);
01365 return -1;
01366 }
01367 cur->action = action;
01368 cur->authority = auth;
01369 cur->func = func;
01370 cur->synopsis = synopsis;
01371 cur->description = description;
01372 cur->next = NULL;
01373
01374 ast_manager_register_struct(cur);
01375
01376 return 0;
01377 }
01378
01379 static int registered = 0;
01380
01381 int init_manager(void)
01382 {
01383 struct ast_config *cfg;
01384 char *val;
01385 int oldportno = portno;
01386 static struct sockaddr_in ba;
01387 int x = 1;
01388 if (!registered) {
01389
01390 ast_manager_register2("Ping", 0, action_ping, "Ping", mandescr_ping);
01391 ast_manager_register2("Events", 0, action_events, "Contol Event Flow", mandescr_events);
01392 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
01393 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
01394 ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
01395 ast_manager_register( "Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable" );
01396 ast_manager_register( "Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable" );
01397 ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
01398 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
01399 ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" );
01400 ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
01401 ast_manager_register( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status" );
01402 ast_manager_register( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout" );
01403 ast_manager_register( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count" );
01404 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
01405
01406 ast_cli_register(&show_mancmd_cli);
01407 ast_cli_register(&show_mancmds_cli);
01408 ast_cli_register(&show_manconn_cli);
01409 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
01410 registered = 1;
01411 }
01412 portno = DEFAULT_MANAGER_PORT;
01413 cfg = ast_load("manager.conf");
01414 if (!cfg) {
01415 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
01416 return 0;
01417 }
01418 memset(&ba, 0, sizeof(ba));
01419 val = ast_variable_retrieve(cfg, "general", "enabled");
01420 if (val)
01421 enabled = ast_true(val);
01422
01423 val = ast_variable_retrieve(cfg, "general", "block-sockets");
01424 if(val)
01425 block_sockets = ast_true(val);
01426
01427 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
01428 if (sscanf(val, "%d", &portno) != 1) {
01429 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
01430 portno = DEFAULT_MANAGER_PORT;
01431 }
01432 } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
01433 if (sscanf(val, "%d", &portno) != 1) {
01434 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
01435 portno = DEFAULT_MANAGER_PORT;
01436 }
01437 ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val);
01438 }
01439
01440 ba.sin_family = AF_INET;
01441 ba.sin_port = htons(portno);
01442 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
01443
01444 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
01445 if (!inet_aton(val, &ba.sin_addr)) {
01446 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
01447 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
01448 }
01449 }
01450
01451 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
01452 #if 0
01453
01454 close(asock);
01455 asock = -1;
01456 #else
01457 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
01458 #endif
01459 }
01460 ast_destroy(cfg);
01461
01462
01463 if (!enabled) {
01464 return 0;
01465 }
01466 if (asock < 0) {
01467 asock = socket(AF_INET, SOCK_STREAM, 0);
01468 if (asock < 0) {
01469 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01470 return -1;
01471 }
01472 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
01473 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
01474 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
01475 close(asock);
01476 asock = -1;
01477 return -1;
01478 }
01479 if (listen(asock, 2)) {
01480 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
01481 close(asock);
01482 asock = -1;
01483 return -1;
01484 }
01485 if (option_verbose)
01486 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
01487 ast_pthread_create(&t, NULL, accept_thread, NULL);
01488 }
01489 return 0;
01490 }
01491
01492 int reload_manager(void)
01493 {
01494 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
01495 return init_manager();
01496 }