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