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) && s->challenge) {
00439 int x;
00440 int len=0;
00441 char md5key[256] = "";
00442 struct MD5Context md5;
00443 unsigned char digest[16];
00444 MD5Init(&md5);
00445 MD5Update(&md5, s->challenge, strlen(s->challenge));
00446 MD5Update(&md5, password, strlen(password));
00447 MD5Final(digest, &md5);
00448 for (x=0;x<16;x++)
00449 len += sprintf(md5key + len, "%2.2x", digest[x]);
00450 if (!strcmp(md5key, key))
00451 break;
00452 else {
00453 ast_destroy(cfg);
00454 return -1;
00455 }
00456 }
00457 } else if (password && !strcasecmp(password, pass)) {
00458 break;
00459 } else {
00460 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
00461 ast_destroy(cfg);
00462 return -1;
00463 }
00464 }
00465 }
00466 cat = ast_category_browse(cfg, cat);
00467 }
00468 if (cat) {
00469 strncpy(s->username, cat, sizeof(s->username) - 1);
00470 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
00471 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
00472 ast_destroy(cfg);
00473 if (events)
00474 set_eventmask(s, events);
00475 return 0;
00476 }
00477 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);
00478 ast_destroy(cfg);
00479 return -1;
00480 }
00481
00482 static char mandescr_ping[] =
00483 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the "
00484 " manager connection open.\n"
00485 "Variables: NONE\n";
00486
00487 static int action_ping(struct mansession *s, struct message *m)
00488 {
00489 astman_send_response(s, m, "Pong", NULL);
00490 return 0;
00491 }
00492
00493 static char mandescr_listcommands[] =
00494 "Description: Returns the action name and synopsis for every\n"
00495 " action that is available to the user\n"
00496 "Variables: NONE\n";
00497
00498 static int action_listcommands(struct mansession *s, struct message *m)
00499 {
00500 struct manager_action *cur = first_action;
00501 char idText[256] = "";
00502 char *id = astman_get_header(m,"ActionID");
00503
00504 if (id && !ast_strlen_zero(id))
00505 snprintf(idText,256,"ActionID: %s\r\n",id);
00506 ast_cli(s->fd, "Response: Success\r\n%s", idText);
00507 ast_mutex_lock(&s->lock);
00508 ast_mutex_lock(&actionlock);
00509 while (cur) {
00510 if ((s->writeperm & cur->authority) == cur->authority)
00511 ast_cli(s->fd, "%s: %s\r\n", cur->action, cur->synopsis);
00512 cur = cur->next;
00513 }
00514 ast_mutex_unlock(&actionlock);
00515 ast_cli(s->fd, "\r\n");
00516 ast_mutex_unlock(&s->lock);
00517
00518 return 0;
00519 }
00520
00521 static char mandescr_events[] =
00522 "Description: Enable/Disable sending of events to this manager\n"
00523 " client.\n"
00524 "Variables:\n"
00525 " EventMask: 'on' if all events should be sent,\n"
00526 " 'off' if no events should be sent,\n"
00527 " 'system,call,log' to select which flags events should have to be sent.\n";
00528
00529 static int action_events(struct mansession *s, struct message *m)
00530 {
00531 char *mask = astman_get_header(m, "EventMask");
00532 int res;
00533
00534 res = set_eventmask(s, mask);
00535 if (res > 0)
00536 astman_send_response(s, m, "Events On", NULL);
00537 else if (res == 0)
00538 astman_send_response(s, m, "Events Off", NULL);
00539
00540 return 0;
00541 }
00542
00543 static char mandescr_logoff[] =
00544 "Description: Logoff this manager session\n"
00545 "Variables: NONE\n";
00546
00547 static int action_logoff(struct mansession *s, struct message *m)
00548 {
00549 astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
00550 return -1;
00551 }
00552
00553 static char mandescr_hangup[] =
00554 "Description: Hangup a channel\n"
00555 "Variables: \n"
00556 " Channel: The channel name to be hungup\n";
00557
00558 static int action_hangup(struct mansession *s, struct message *m)
00559 {
00560 struct ast_channel *c = NULL;
00561 char *name = astman_get_header(m, "Channel");
00562 char *uniqueid = astman_get_header(m, "Uniqueid");
00563 if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
00564 astman_send_error(s, m, "No channel or uniqueid specified");
00565 return 0;
00566 }
00567 if (!ast_strlen_zero(uniqueid)) {
00568 c = ast_get_channel_by_uniqueid_locked(uniqueid);
00569 } else {
00570 if (!ast_strlen_zero(name))
00571 c = ast_get_channel_by_name_locked(name);
00572 }
00573 if (!c) {
00574 astman_send_error(s, m, "No such channel");
00575 return 0;
00576 }
00577 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
00578 ast_mutex_unlock(&c->lock);
00579 astman_send_ack(s, m, "Channel Hungup");
00580 return 0;
00581 }
00582
00583 static char mandescr_setvar[] =
00584 "Description: Set a local channel variable.\n"
00585 "Variables: (Names marked with * are required)\n"
00586 " *Channel: Channel to set variable for\n"
00587 " *Variable: Variable name\n"
00588 " *Value: Value\n";
00589
00590 static int action_setvar(struct mansession *s, struct message *m)
00591 {
00592 struct ast_channel *c = NULL;
00593 char *name = astman_get_header(m, "Channel");
00594 char *varname = astman_get_header(m, "Variable");
00595 char *varval = astman_get_header(m, "Value");
00596
00597 if (!strlen(name)) {
00598 astman_send_error(s, m, "No channel specified");
00599 return 0;
00600 }
00601 if (!strlen(varname)) {
00602 astman_send_error(s, m, "No variable specified");
00603 return 0;
00604 }
00605
00606 c = ast_channel_walk_locked(NULL);
00607 while(c) {
00608 if (!strcasecmp(c->name, name)) {
00609 break;
00610 }
00611 ast_mutex_unlock(&c->lock);
00612 c = ast_channel_walk_locked(c);
00613 }
00614 if (!c) {
00615 astman_send_error(s, m, "No such channel");
00616 return 0;
00617 }
00618
00619 pbx_builtin_setvar_helper(c,varname,varval);
00620
00621 ast_mutex_unlock(&c->lock);
00622 astman_send_ack(s, m, "Variable Set");
00623 return 0;
00624 }
00625
00626 static char mandescr_getvar[] =
00627 "Description: Get the value of a local channel variable.\n"
00628 "Variables: (Names marked with * are required)\n"
00629 " *Channel: Channel to read variable from\n"
00630 " *Variable: Variable name\n"
00631 " ActionID: Optional Action id for message matching.\n";
00632
00633 static int action_getvar(struct mansession *s, struct message *m)
00634 {
00635 struct ast_channel *c = NULL;
00636 char *name = astman_get_header(m, "Channel");
00637 char *varname = astman_get_header(m, "Variable");
00638 char *id = astman_get_header(m,"ActionID");
00639 char *varval;
00640
00641 if (!strlen(name)) {
00642 astman_send_error(s, m, "No channel specified");
00643 return 0;
00644 }
00645 if (!strlen(varname)) {
00646 astman_send_error(s, m, "No variable specified");
00647 return 0;
00648 }
00649
00650 c = ast_channel_walk_locked(NULL);
00651 while(c) {
00652 if (!strcasecmp(c->name, name)) {
00653 break;
00654 }
00655 ast_mutex_unlock(&c->lock);
00656 c = ast_channel_walk_locked(c);
00657 }
00658 if (!c) {
00659 astman_send_error(s, m, "No such channel");
00660 return 0;
00661 }
00662
00663 varval=pbx_builtin_getvar_helper(c,varname);
00664
00665 ast_mutex_unlock(&c->lock);
00666 ast_mutex_lock(&s->lock);
00667 ast_cli(s->fd, "Response: Success\r\n"
00668 "%s: %s\r\n" ,varname,varval);
00669 if (id && !ast_strlen_zero(id))
00670 ast_cli(s->fd, "ActionID: %s\r\n",id);
00671 ast_cli(s->fd, "\r\n");
00672 ast_mutex_unlock(&s->lock);
00673
00674 return 0;
00675 }
00676
00677 static char mandescr_dbget[] =
00678 "Description: Get a value from astdb\n"
00679 "Variables: \n"
00680 " Family: ...\n"
00681 " Key: ...\n";
00682
00683 static int action_dbget(struct mansession *s, struct message *m)
00684 {
00685 char *family = astman_get_header(m, "Family");
00686 char *key = astman_get_header(m, "Key");
00687 char *id = astman_get_header(m,"ActionID");
00688 char dbresult[256];
00689
00690 if (!strlen(family)) {
00691 astman_send_error(s, m, "No family specified");
00692 return 0;
00693 }
00694 if (!strlen(key)) {
00695 astman_send_error(s, m, "No key specified");
00696 return 0;
00697 }
00698
00699 ast_mutex_lock(&s->lock);
00700 if (ast_db_get(family, key, dbresult, sizeof(dbresult) - 1)) {
00701 ast_cli(s->fd, "Response: Failed\r\n");
00702 } else {
00703 ast_cli(s->fd, "Response: Success\r\n"
00704 "Value: %s\r\n" ,dbresult);
00705 }
00706 if (id && !ast_strlen_zero(id))
00707 ast_cli(s->fd, "ActionID: %s\r\n",id);
00708 ast_cli(s->fd, "\r\n");
00709 ast_mutex_unlock(&s->lock);
00710
00711 return 0;
00712 }
00713
00714 static char mandescr_dbput[] =
00715 "Description: Put a value into astdb\n"
00716 "Variables: \n"
00717 " Family: ...\n"
00718 " Key: ...\n"
00719 " Value: ...\n";
00720
00721 static int action_dbput(struct mansession *s, struct message *m)
00722 {
00723 char *family = astman_get_header(m, "Family");
00724 char *key = astman_get_header(m, "Key");
00725 char *value = astman_get_header(m, "Value");
00726 char *id = astman_get_header(m,"ActionID");
00727
00728 if (!strlen(family)) {
00729 astman_send_error(s, m, "No family specified");
00730 return 0;
00731 }
00732 if (!strlen(key)) {
00733 astman_send_error(s, m, "No key specified");
00734 return 0;
00735 }
00736 if (!strlen(value)) {
00737 astman_send_error(s, m, "No value specified");
00738 return 0;
00739 }
00740
00741 ast_mutex_lock(&s->lock);
00742 if (ast_db_put(family, key, value)) {
00743 ast_cli(s->fd, "Response: Failed\r\n");
00744 } else {
00745 ast_cli(s->fd, "Response: Success\r\n");
00746 }
00747 if (id && !ast_strlen_zero(id))
00748 ast_cli(s->fd, "ActionID: %s\r\n",id);
00749 ast_cli(s->fd, "\r\n");
00750 ast_mutex_unlock(&s->lock);
00751
00752 return 0;
00753 }
00754
00755
00756 static char mandescr_dbdel[] =
00757 "Description: remove value from astdb\n"
00758 "Variables: \n"
00759 " Family: ...\n"
00760 " Key: ...\n";
00761
00762 static int action_dbdel(struct mansession *s, struct message *m)
00763 {
00764 char *family = astman_get_header(m, "Family");
00765 char *key = astman_get_header(m, "Key");
00766 char *id = astman_get_header(m,"ActionID");
00767
00768 if (!strlen(family)) {
00769 astman_send_error(s, m, "No family specified");
00770 return 0;
00771 }
00772 if (!strlen(key)) {
00773 astman_send_error(s, m, "No key specified");
00774 return 0;
00775 }
00776
00777 ast_mutex_lock(&s->lock);
00778 if (ast_db_del(family, key)) {
00779 ast_cli(s->fd, "Response: Failed\r\n");
00780 } else {
00781 ast_cli(s->fd, "Response: Success\r\n");
00782 }
00783 if (id && !ast_strlen_zero(id))
00784 ast_cli(s->fd, "ActionID: %s\r\n",id);
00785 ast_cli(s->fd, "\r\n");
00786 ast_mutex_unlock(&s->lock);
00787
00788 return 0;
00789 }
00790
00791
00792 static int action_status(struct mansession *s, struct message *m)
00793 {
00794 char *id = astman_get_header(m,"ActionID");
00795 char *name = astman_get_header(m,"Channel");
00796 char idText[256] = "";
00797 struct ast_channel *c;
00798 char bridge[256];
00799 struct timeval now;
00800 long elapsed_seconds=0;
00801
00802 gettimeofday(&now, NULL);
00803 astman_send_ack(s, m, "Channel status will follow");
00804 c = ast_channel_walk_locked(NULL);
00805 if (id && !ast_strlen_zero(id))
00806 snprintf(idText,256,"ActionID: %s\r\n",id);
00807 if (name && !ast_strlen_zero(name)) {
00808 while (c) {
00809 if (!strcasecmp(c->name, name)) {
00810 break;
00811 }
00812 ast_mutex_unlock(&c->lock);
00813 c = ast_channel_walk_locked(c);
00814 }
00815 if (!c) {
00816 astman_send_error(s, m, "No such channel");
00817 return 0;
00818 }
00819 }
00820 while(c) {
00821 if (c->bridge)
00822 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
00823 else
00824 bridge[0] = '\0';
00825 ast_mutex_lock(&s->lock);
00826 if (c->pbx) {
00827 if (c->cdr) {
00828 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
00829 }
00830 ast_cli(s->fd,
00831 "Event: Status\r\n"
00832 "Channel: %s\r\n"
00833 "CallerID: %s\r\n"
00834 "Account: %s\r\n"
00835 "State: %s\r\n"
00836 "Context: %s\r\n"
00837 "Extension: %s\r\n"
00838 "Priority: %d\r\n"
00839 "Seconds: %ld\r\n"
00840 "%s"
00841 "Uniqueid: %s\r\n"
00842 "%s"
00843 "\r\n",
00844 c->name, c->callerid ? c->callerid : "<unknown>",
00845 c->accountcode,
00846 ast_state2str(c->_state), c->context,
00847 c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
00848 } else {
00849 ast_cli(s->fd,
00850 "Event: Status\r\n"
00851 "Channel: %s\r\n"
00852 "CallerID: %s\r\n"
00853 "Account: %s\r\n"
00854 "State: %s\r\n"
00855 "%s"
00856 "Uniqueid: %s\r\n"
00857 "%s"
00858 "\r\n",
00859 c->name, c->callerid ? c->callerid : "<unknown>",
00860 c->accountcode,
00861 ast_state2str(c->_state), bridge, c->uniqueid, idText);
00862 }
00863 ast_mutex_unlock(&s->lock);
00864 ast_mutex_unlock(&c->lock);
00865 if (name && !ast_strlen_zero(name)) {
00866 break;
00867 }
00868 c = ast_channel_walk_locked(c);
00869 }
00870 ast_mutex_lock(&s->lock);
00871 ast_cli(s->fd,
00872 "Event: StatusComplete\r\n"
00873 "%s"
00874 "\r\n",idText);
00875 ast_mutex_unlock(&s->lock);
00876 return 0;
00877 }
00878
00879 static int action_redirect(struct mansession *s, struct message *m)
00880 {
00881 char *name = astman_get_header(m, "Channel");
00882 char *name2 = astman_get_header(m, "ExtraChannel");
00883 char *uniqueid = astman_get_header(m, "Uniqueid");
00884 char *uniqueid2 = astman_get_header(m, "ExtraUniqueid");
00885 char *exten = astman_get_header(m, "Exten");
00886 char *context = astman_get_header(m, "Context");
00887 char *priority = astman_get_header(m, "Priority");
00888 char *exten2 = astman_get_header(m, "ExtraExten");
00889 char *context2 = astman_get_header(m, "ExtraContext");
00890 char *priority2 = astman_get_header(m, "ExtraPriority");
00891 struct ast_channel *chan, *chan2 = NULL;
00892 int pi = 0;
00893 int pi2 = 0;
00894 int res;
00895 if ((!name || ast_strlen_zero(name)) && (!uniqueid || ast_strlen_zero(uniqueid))) {
00896 astman_send_error(s, m, "Channel or Uniqueid not specified");
00897 return 0;
00898 }
00899 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
00900 astman_send_error(s, m, "Invalid priority\n");
00901 return 0;
00902 }
00903 if (uniqueid && (!ast_strlen_zero(uniqueid))) {
00904 chan = ast_get_channel_by_uniqueid_locked(uniqueid);
00905 } else {
00906 chan = ast_get_channel_by_name_locked(name);
00907 }
00908 if (!chan) {
00909 astman_send_error(s, m, "Channel not existant");
00910 return 0;
00911 }
00912 if (!ast_strlen_zero(uniqueid2)) {
00913 chan2 = ast_get_channel_by_uniqueid_locked(uniqueid2);
00914 if (!ast_strlen_zero(priority2) && (sscanf(priority, "%d", &pi2) != 1)) {
00915 astman_send_error(s, m, "Invalid priority2\n");
00916 return 0;
00917 }
00918 } else {
00919 if (!ast_strlen_zero(name2))
00920 chan2 = ast_get_channel_by_name_locked(name2);
00921 }
00922 res = ast_async_goto(chan, context, exten, pi);
00923 if (!res) {
00924 if ((!ast_strlen_zero(name2)) || (!ast_strlen_zero(uniqueid2))){
00925 if (chan2)
00926 res = ast_async_goto(chan2, context2, exten2, pi2);
00927 else
00928 res = -1;
00929 if (!res)
00930 astman_send_ack(s, m, "Dual Redirect successful");
00931 else
00932 astman_send_error(s, m, "Secondary redirect failed");
00933 } else
00934 astman_send_ack(s, m, "Redirect successful");
00935 } else
00936 astman_send_error(s, m, "Redirect failed");
00937 if (chan)
00938 ast_mutex_unlock(&chan->lock);
00939 if (chan2)
00940 ast_mutex_unlock(&chan2->lock);
00941 return 0;
00942 }
00943
00944 static char mandescr_command[] =
00945 "Description: Run a CLI command.\n"
00946 "Variables: (Names marked with * are required)\n"
00947 " *Command: Asterisk CLI command to run\n"
00948 " ActionID: Optional Action id for message matching.\n";
00949 static int action_command(struct mansession *s, struct message *m)
00950 {
00951 char *cmd = astman_get_header(m, "Command");
00952 char *id = astman_get_header(m, "ActionID");
00953 ast_mutex_lock(&s->lock);
00954 s->blocking = 1;
00955 ast_mutex_unlock(&s->lock);
00956 ast_cli(s->fd, "Response: Follows\r\n");
00957 if (id && !ast_strlen_zero(id))
00958 ast_cli(s->fd, "ActionID: %s\r\n", id);
00959
00960 ast_cli_command(s->fd, cmd);
00961 ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
00962 ast_mutex_lock(&s->lock);
00963 s->blocking = 0;
00964 ast_mutex_unlock(&s->lock);
00965 return 0;
00966 }
00967
00968 static void *fast_originate(void *data)
00969 {
00970 struct fast_originate_helper *in = data;
00971 int res;
00972 int reason = 0;
00973 if (!ast_strlen_zero(in->app)) {
00974 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);
00975 } else {
00976 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);
00977 }
00978 if (!res)
00979 manager_event(EVENT_FLAG_CALL,
00980 "OriginateSuccess",
00981 "%s"
00982 "Uniqueid: %s\r\n"
00983 "Channel: %s/%s\r\n"
00984 "Context: %s\r\n"
00985 "Exten: %s\r\n",
00986 in->idtext, in->uniqueid, in->tech, in->data, in->context, in->exten);
00987 else
00988 manager_event(EVENT_FLAG_CALL,
00989 "OriginateFailure",
00990 "%s"
00991 "Uniqueid: %s\r\n"
00992 "Channel: %s/%s\r\n"
00993 "Context: %s\r\n"
00994 "Exten: %s\r\n",
00995 in->idtext, in->uniqueid, in->tech, in->data, in->context, in->exten);
00996
00997 free(in);
00998 return NULL;
00999 }
01000
01001 static char mandescr_originate[] =
01002 "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
01003 " Application/Data\n"
01004 "Variables: (Names marked with * are required)\n"
01005 " *Channel: Channel name to call\n"
01006 " Exten: Extension to use (requires 'Context' and 'Priority')\n"
01007 " Context: Context to use (requires 'Exten' and 'Priority')\n"
01008 " Priority: Priority to use (requires 'Exten' and 'Context')\n"
01009 " Application: Application to use\n"
01010 " Data: Data to use (requires 'Application')\n"
01011 " Timeout: How long to wait for call to be answered (in ms)\n"
01012 " CallerID: Caller ID to be set on the outgoing channel\n"
01013 " CallingPres: Caller ID presentation to be set on the outgoing channel\n"
01014 " Variable: Channel variable to set (VAR1=value1|VAR2=value2)\n"
01015 " Account: Account code\n"
01016 " Async: Set to 'true' for fast origination\n";
01017
01018 static int action_originate(struct mansession *s, struct message *m)
01019 {
01020 char *name = astman_get_header(m, "Channel");
01021 char *exten = astman_get_header(m, "Exten");
01022 char *context = astman_get_header(m, "Context");
01023 char *priority = astman_get_header(m, "Priority");
01024 char *timeout = astman_get_header(m, "Timeout");
01025 char *callerid = astman_get_header(m, "CallerID");
01026 char *callingpres = astman_get_header(m, "CallingPres");
01027 char *variable = astman_get_header(m, "Variable");
01028 char *account = astman_get_header(m, "Account");
01029 char *app = astman_get_header(m, "Application");
01030 char *appdata = astman_get_header(m, "Data");
01031 char *async = astman_get_header(m, "Async");
01032 char *id = astman_get_header(m, "ActionID");
01033 char *tech, *data;
01034 char *uniqueid;
01035 int pi = 0;
01036 int cpresi = 0;
01037 int res;
01038 int to = 30000;
01039 int reason = 0;
01040 char tmp[256];
01041 char idText[256] = "";
01042 pthread_t th;
01043 pthread_attr_t attr;
01044 if (!name) {
01045 astman_send_error(s, m, "Channel not specified");
01046 return 0;
01047 }
01048 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) {
01049 astman_send_error(s, m, "Invalid priority\n");
01050 return 0;
01051 }
01052 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
01053 astman_send_error(s, m, "Invalid timeout\n");
01054 return 0;
01055 }
01056 if (!ast_strlen_zero(callingpres) && (sscanf(callingpres, "%d", &cpresi) != 1)) {
01057 astman_send_error(s, m, "Invalid CallingPres\n");
01058 return 0;
01059 }
01060 strncpy(tmp, name, sizeof(tmp) - 1);
01061 tech = tmp;
01062 data = strchr(tmp, '/');
01063 if (!data) {
01064 astman_send_error(s, m, "Invalid channel\n");
01065 return 0;
01066 }
01067 *data = '\0';
01068 data++;
01069 uniqueid = ast_alloc_uniqueid();
01070 if (ast_true(async)) {
01071 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
01072 if (!fast) {
01073 res = -1;
01074 } else {
01075 memset(fast, 0, sizeof(struct fast_originate_helper));
01076 if (id && !ast_strlen_zero(id))
01077 snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
01078 strncpy(fast->tech, tech, sizeof(fast->tech) - 1);
01079 strncpy(fast->data, data, sizeof(fast->data) - 1);
01080 strncpy(fast->app, app, sizeof(fast->app) - 1);
01081 strncpy(fast->appdata, appdata, sizeof(fast->appdata) - 1);
01082 strncpy(fast->callerid, callerid, sizeof(fast->callerid) - 1);
01083 strncpy(fast->variable, variable, sizeof(fast->variable) - 1);
01084 strncpy(fast->account, account, sizeof(fast->account) - 1);
01085 strncpy(fast->context, context, sizeof(fast->context) - 1);
01086 strncpy(fast->exten, exten, sizeof(fast->exten) - 1);
01087 strncpy(fast->uniqueid, uniqueid, sizeof(fast->uniqueid) - 1);
01088 fast->timeout = to;
01089 fast->priority = pi;
01090 fast->callingpres = cpresi;
01091 pthread_attr_init(&attr);
01092 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01093 if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
01094 res = -1;
01095 } else {
01096 res = 0;
01097 }
01098 }
01099 } else if (!ast_strlen_zero(app)) {
01100 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account, uniqueid);
01101 } else {
01102 if (exten && context && pi)
01103 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);
01104 else {
01105 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
01106 return 0;
01107 }
01108 }
01109 if (!res) {
01110 if (id && !ast_strlen_zero(id)) {
01111 snprintf(idText,256,"ActionID: %s\r\n",id);
01112 }
01113 ast_mutex_lock(&s->lock);
01114 ast_cli(s->fd, "Response: Success\r\n"
01115 "%s"
01116 "Message: Originate successfully queued\r\n"
01117 "Uniqueid: %s\r\n"
01118 "\r\n",
01119 idText, uniqueid);
01120 ast_mutex_unlock(&s->lock);
01121 } else {
01122 astman_send_error(s, m, "Originate failed");
01123 }
01124 return 0;
01125 }
01126
01127 static char mandescr_mailboxstatus[] =
01128 "Description: Checks a voicemail account for status.\n"
01129 "Variables: (Names marked with * are required)\n"
01130 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
01131 " ActionID: Optional ActionID for message matching.\n"
01132 "Returns number of messages.\n"
01133 " Message: Mailbox Status\n"
01134 " Mailbox: <mailboxid>\n"
01135 " Waiting: <count>\n"
01136 "\n";
01137 static int action_mailboxstatus(struct mansession *s, struct message *m)
01138 {
01139 char *mailbox = astman_get_header(m, "Mailbox");
01140 char *id = astman_get_header(m,"ActionID");
01141 char idText[256] = "";
01142 int ret;
01143 if (!mailbox || ast_strlen_zero(mailbox)) {
01144 astman_send_error(s, m, "Mailbox not specified");
01145 return 0;
01146 }
01147 if (id && !ast_strlen_zero(id))
01148 snprintf(idText,256,"ActionID: %s\r\n",id);
01149 ret = ast_app_has_voicemail(mailbox);
01150 ast_mutex_lock(&s->lock);
01151 ast_cli(s->fd, "Response: Success\r\n"
01152 "%s"
01153 "Message: Mailbox Status\r\n"
01154 "Mailbox: %s\r\n"
01155 "Waiting: %d\r\n\r\n", idText, mailbox, ret);
01156 ast_mutex_unlock(&s->lock);
01157 return 0;
01158 }
01159
01160 static char mandescr_mailboxcount[] =
01161 "Description: Checks a voicemail account for new messages.\n"
01162 "Variables: (Names marked with * are required)\n"
01163 " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
01164 " ActionID: Optional ActionID for message matching.\n"
01165 "Returns number of new and old messages.\n"
01166 " Message: Mailbox Message Count\n"
01167 " Mailbox: <mailboxid>\n"
01168 " NewMessages: <count>\n"
01169 " OldMessages: <count>\n"
01170 "\n";
01171 static int action_mailboxcount(struct mansession *s, struct message *m)
01172 {
01173 char *mailbox = astman_get_header(m, "Mailbox");
01174 char *id = astman_get_header(m,"ActionID");
01175 char idText[256] = "";
01176 int newmsgs = 0, oldmsgs = 0;
01177 if (!mailbox || ast_strlen_zero(mailbox)) {
01178 astman_send_error(s, m, "Mailbox not specified");
01179 return 0;
01180 }
01181 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
01182 if (id && !ast_strlen_zero(id)) {
01183 snprintf(idText,256,"ActionID: %s\r\n",id);
01184 }
01185 ast_mutex_lock(&s->lock);
01186 ast_cli(s->fd, "Response: Success\r\n"
01187 "%s"
01188 "Message: Mailbox Message Count\r\n"
01189 "Mailbox: %s\r\n"
01190 "NewMessages: %d\r\n"
01191 "OldMessages: %d\r\n"
01192 "\r\n",
01193 idText,mailbox, newmsgs, oldmsgs);
01194 ast_mutex_unlock(&s->lock);
01195 return 0;
01196 }
01197
01198 static char mandescr_extensionstate[] =
01199 "Description: Report the extension state for given extension.\n"
01200 " If the extension has a hint, will use devicestate to check\n"
01201 " the status of the device connected to the extension.\n"
01202 "Variables: (Names marked with * are required)\n"
01203 " *Exten: Extension to check state on\n"
01204 " *Context: Context for extension\n"
01205 " ActionId: Optional ID for this transaction\n"
01206 "Will return an \"Extension Status\" message.\n"
01207 "The response will include the hint for the extension and the status.\n";
01208
01209 static int action_extensionstate(struct mansession *s, struct message *m)
01210 {
01211 char *exten = astman_get_header(m, "Exten");
01212 char *context = astman_get_header(m, "Context");
01213 char *id = astman_get_header(m,"ActionID");
01214 char idText[256] = "";
01215 char hint[256] = "";
01216 int status;
01217 if (!exten || ast_strlen_zero(exten)) {
01218 astman_send_error(s, m, "Extension not specified");
01219 return 0;
01220 }
01221 if (!context || ast_strlen_zero(context))
01222 context = "default";
01223 status = ast_extension_state(NULL, context, exten);
01224 ast_get_hint(hint, sizeof(hint) - 1, NULL, context, exten);
01225 if (id && !ast_strlen_zero(id)) {
01226 snprintf(idText,256,"ActionID: %s\r\n",id);
01227 }
01228 ast_mutex_lock(&s->lock);
01229 ast_cli(s->fd, "Response: Success\r\n"
01230 "%s"
01231 "Message: Extension Status\r\n"
01232 "Exten: %s\r\n"
01233 "Context: %s\r\n"
01234 "Hint: %s\r\n"
01235 "Status: %d\r\n\r\n",
01236 idText,exten, context, hint, status);
01237 ast_mutex_unlock(&s->lock);
01238 return 0;
01239 }
01240
01241 static char mandescr_timeout[] =
01242 "Description: Hangup a channel after a certain time.\n"
01243 "Variables: (Names marked with * are required)\n"
01244 " *Channel: Channel name to hangup\n"
01245 " *Timeout: Maximum duration of the call (sec)\n"
01246 "Acknowledges set time with 'Timeout Set' message\n";
01247
01248 static int action_timeout(struct mansession *s, struct message *m)
01249 {
01250 struct ast_channel *c = NULL;
01251 char *name = astman_get_header(m, "Channel");
01252 int timeout = atoi(astman_get_header(m, "Timeout"));
01253 if (ast_strlen_zero(name)) {
01254 astman_send_error(s, m, "No channel specified");
01255 return 0;
01256 }
01257 if (!timeout) {
01258 astman_send_error(s, m, "No timeout specified");
01259 return 0;
01260 }
01261 c = ast_channel_walk_locked(NULL);
01262 while(c) {
01263 if (!strcasecmp(c->name, name)) {
01264 break;
01265 }
01266 ast_mutex_unlock(&c->lock);
01267 c = ast_channel_walk_locked(c);
01268 }
01269 if (!c) {
01270 astman_send_error(s, m, "No such channel");
01271 return 0;
01272 }
01273 ast_channel_setwhentohangup(c, timeout);
01274 ast_mutex_unlock(&c->lock);
01275 astman_send_ack(s, m, "Timeout Set");
01276 return 0;
01277 }
01278
01279 static int process_message(struct mansession *s, struct message *m)
01280 {
01281 char action[80] = "";
01282 struct manager_action *tmp = first_action;
01283 char *id = astman_get_header(m,"ActionID");
01284 char idText[256] = "";
01285 char iabuf[INET_ADDRSTRLEN];
01286
01287 strncpy(action, astman_get_header(m, "Action"), sizeof(action) - 1);
01288 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
01289
01290 if (ast_strlen_zero(action)) {
01291 astman_send_error(s, m, "Missing action in request");
01292 return 0;
01293 }
01294 if (id && !ast_strlen_zero(id)) {
01295 snprintf(idText,256,"ActionID: %s\r\n",id);
01296 }
01297 if (!s->authenticated) {
01298 if (!strcasecmp(action, "Challenge")) {
01299 char *authtype;
01300 authtype = astman_get_header(m, "AuthType");
01301 if (!strcasecmp(authtype, "MD5")) {
01302 if (!s->challenge || ast_strlen_zero(s->challenge)) {
01303 ast_mutex_lock(&s->lock);
01304 snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
01305 ast_mutex_unlock(&s->lock);
01306 }
01307 ast_mutex_lock(&s->lock);
01308 ast_cli(s->fd, "Response: Success\r\n"
01309 "%s"
01310 "Challenge: %s\r\n\r\n",
01311 idText,s->challenge);
01312 ast_mutex_unlock(&s->lock);
01313 return 0;
01314 } else {
01315 astman_send_error(s, m, "Must specify AuthType");
01316 return 0;
01317 }
01318 } else if (!strcasecmp(action, "Login")) {
01319 if (authenticate(s, m)) {
01320 sleep(1);
01321 astman_send_error(s, m, "Authentication failed");
01322 return -1;
01323 } else {
01324 s->authenticated = 1;
01325 if (option_verbose > 1)
01326 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01327 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01328 astman_send_ack(s, m, "Authentication accepted");
01329 }
01330 } else if (!strcasecmp(action, "Logoff")) {
01331 astman_send_ack(s, m, "See ya");
01332 return -1;
01333 } else
01334 astman_send_error(s, m, "Authentication Required");
01335 } else {
01336 while( tmp ) {
01337 if (!strcasecmp(action, tmp->action)) {
01338 if ((s->writeperm & tmp->authority) == tmp->authority) {
01339 if (tmp->func(s, m))
01340 return -1;
01341 } else {
01342 astman_send_error(s, m, "Permission denied");
01343 }
01344 return 0;
01345 }
01346 tmp = tmp->next;
01347 }
01348 astman_send_error(s, m, "Invalid/unknown command");
01349 }
01350 return 0;
01351 }
01352
01353 static int get_input(struct mansession *s, char *output)
01354 {
01355
01356 int res;
01357 int x;
01358 struct pollfd fds[1];
01359 char iabuf[INET_ADDRSTRLEN];
01360 for (x=1;x<s->inlen;x++) {
01361 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
01362
01363 memcpy(output, s->inbuf, x + 1);
01364
01365 output[x+1] = '\0';
01366
01367 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
01368 s->inlen -= (x + 1);
01369 return 1;
01370 }
01371 }
01372 if (s->inlen >= sizeof(s->inbuf) - 1) {
01373 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);
01374 s->inlen = 0;
01375 }
01376 fds[0].fd = s->fd;
01377 fds[0].events = POLLIN;
01378 res = poll(fds, 1, -1);
01379 if (res < 0) {
01380 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
01381 } else if (res > 0) {
01382 ast_mutex_lock(&s->lock);
01383 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
01384 ast_mutex_unlock(&s->lock);
01385 if (res < 1)
01386 return -1;
01387 }
01388 s->inlen += res;
01389 s->inbuf[s->inlen] = '\0';
01390 return 0;
01391 }
01392
01393 static void *session_do(void *data)
01394 {
01395 struct mansession *s = data;
01396 struct message m;
01397 char iabuf[INET_ADDRSTRLEN];
01398 int res;
01399
01400 ast_mutex_lock(&s->lock);
01401 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
01402 ast_mutex_unlock(&s->lock);
01403 memset(&m, 0, sizeof(&m));
01404 for (;;) {
01405 res = get_input(s, m.headers[m.hdrcount]);
01406 if (res > 0) {
01407
01408 if (strlen(m.headers[m.hdrcount]) < 2)
01409 continue;
01410 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
01411 if (ast_strlen_zero(m.headers[m.hdrcount])) {
01412 if (process_message(s, &m))
01413 break;
01414 memset(&m, 0, sizeof(&m));
01415 } else if (m.hdrcount < MAX_HEADERS - 1)
01416 m.hdrcount++;
01417 } else if (res < 0)
01418 break;
01419 }
01420 if (s->authenticated) {
01421 if (option_verbose > 1)
01422 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01423 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01424 } else {
01425 if (option_verbose > 1)
01426 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01427 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
01428 }
01429 destroy_session(s);
01430 return NULL;
01431 }
01432
01433 static void *accept_thread(void *ignore)
01434 {
01435 int as;
01436 struct sockaddr_in sin;
01437 int sinlen;
01438 struct mansession *s;
01439 struct protoent *p;
01440 int arg = 1;
01441 int flags;
01442 pthread_attr_t attr;
01443
01444 pthread_attr_init(&attr);
01445 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01446
01447 for (;;) {
01448 sinlen = sizeof(sin);
01449 as = accept(asock, (struct sockaddr *)&sin, &sinlen);
01450 if (as < 0) {
01451 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
01452 continue;
01453 }
01454 p = getprotobyname("tcp");
01455 if( p ) {
01456 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
01457 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
01458 }
01459 }
01460 s = malloc(sizeof(struct mansession));
01461 if (!s) {
01462 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
01463 continue;
01464 }
01465 memset(s, 0, sizeof(struct mansession));
01466 memcpy(&s->sin, &sin, sizeof(sin));
01467
01468 if(! block_sockets) {
01469
01470 flags = fcntl(as, F_GETFL);
01471 fcntl(as, F_SETFL, flags | O_NONBLOCK);
01472 }
01473 ast_mutex_init(&s->lock);
01474 s->fd = as;
01475 s->send_events = -1;
01476 ast_mutex_lock(&sessionlock);
01477 s->next = sessions;
01478 sessions = s;
01479 ast_mutex_unlock(&sessionlock);
01480 if (ast_pthread_create(&t, &attr, session_do, s))
01481 destroy_session(s);
01482 }
01483 pthread_attr_destroy(&attr);
01484 return NULL;
01485 }
01486
01487 int manager_event(int category, char *event, char *fmt, ...)
01488 {
01489 struct mansession *s;
01490 char tmp[4096];
01491 va_list ap;
01492
01493 ast_mutex_lock(&sessionlock);
01494 s = sessions;
01495 while(s) {
01496 if (((s->readperm & category) == category) && ((s->send_events & category) == category) ) {
01497 ast_mutex_lock(&s->lock);
01498 if (!s->blocking) {
01499 ast_cli(s->fd, "Event: %s\r\n", event);
01500 va_start(ap, fmt);
01501 vsnprintf(tmp, sizeof(tmp), fmt, ap);
01502 va_end(ap);
01503 ast_carefulwrite(s->fd,tmp,strlen(tmp),100);
01504 ast_cli(s->fd, "\r\n");
01505 }
01506 ast_mutex_unlock(&s->lock);
01507 }
01508 s = s->next;
01509 }
01510 ast_mutex_unlock(&sessionlock);
01511 return 0;
01512 }
01513
01514 int ast_manager_unregister( char *action ) {
01515 struct manager_action *cur = first_action, *prev = first_action;
01516
01517 ast_mutex_lock(&actionlock);
01518 while( cur ) {
01519 if (!strcasecmp(action, cur->action)) {
01520 prev->next = cur->next;
01521 free(cur);
01522 if (option_verbose > 1)
01523 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
01524 ast_mutex_unlock(&actionlock);
01525 return 0;
01526 }
01527 prev = cur;
01528 cur = cur->next;
01529 }
01530 ast_mutex_unlock(&actionlock);
01531 return 0;
01532 }
01533
01534 static int manager_state_cb(char *context, char *exten, int state, void *data)
01535 {
01536
01537 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
01538 return 0;
01539 }
01540
01541 static int ast_manager_register_struct(struct manager_action *act)
01542 {
01543 struct manager_action *cur = first_action, *prev = NULL;
01544 int ret;
01545
01546 ast_mutex_lock(&actionlock);
01547 while(cur) {
01548 ret = strcasecmp(cur->action, act->action);
01549 if (ret == 0) {
01550 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
01551 ast_mutex_unlock(&actionlock);
01552 return -1;
01553 } else if (ret > 0) {
01554
01555 if (prev) {
01556 act->next = prev->next;
01557 prev->next = act;
01558 } else {
01559 act->next = first_action;
01560 first_action = act;
01561 }
01562 break;
01563 }
01564 prev = cur;
01565 cur = cur->next;
01566 }
01567
01568 if (!cur) {
01569 if (prev)
01570 prev->next = act;
01571 else
01572 first_action = act;
01573 act->next = NULL;
01574 }
01575
01576 if (option_verbose > 1)
01577 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
01578 ast_mutex_unlock(&actionlock);
01579 return 0;
01580 }
01581
01582 int ast_manager_register2(char *action, int auth, int (*func)(struct mansession *s, struct message *m), char *synopsis, char *description)
01583 {
01584 struct manager_action *cur;
01585
01586 cur = malloc(sizeof(struct manager_action));
01587 if (!cur) {
01588 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
01589 ast_mutex_unlock(&actionlock);
01590 return -1;
01591 }
01592 cur->action = action;
01593 cur->authority = auth;
01594 cur->func = func;
01595 cur->synopsis = synopsis;
01596 cur->description = description;
01597 cur->next = NULL;
01598
01599 ast_manager_register_struct(cur);
01600
01601 return 0;
01602 }
01603
01604 static int registered = 0;
01605
01606 int init_manager(void)
01607 {
01608 struct ast_config *cfg;
01609 char *val;
01610 int oldportno = portno;
01611 static struct sockaddr_in ba;
01612 int x = 1;
01613 if (!registered) {
01614
01615 ast_manager_register2("Ping", 0, action_ping, "Ping", mandescr_ping);
01616 ast_manager_register2("Events", 0, action_events, "Contol Event Flow", mandescr_events);
01617 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
01618 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
01619 ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
01620 ast_manager_register2( "Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
01621 ast_manager_register2( "Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
01622 ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
01623 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
01624 ast_manager_register2( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command", mandescr_command );
01625 ast_manager_register2( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
01626 ast_manager_register2( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
01627 ast_manager_register2( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
01628 ast_manager_register2( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
01629 ast_manager_register2( "DBget", EVENT_FLAG_CALL, action_dbget, "Retrieve a value from astdb", mandescr_dbget );
01630 ast_manager_register2( "DBput", EVENT_FLAG_CALL, action_dbput, "Store a value in astdb", mandescr_dbput );
01631 ast_manager_register2( "DBdel", EVENT_FLAG_CALL, action_dbdel, "Delete a key from astdb", mandescr_dbdel );
01632 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
01633
01634 ast_cli_register(&show_mancmd_cli);
01635 ast_cli_register(&show_mancmds_cli);
01636 ast_cli_register(&show_manconn_cli);
01637 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
01638 registered = 1;
01639 }
01640 portno = DEFAULT_MANAGER_PORT;
01641 cfg = ast_load("manager.conf");
01642 if (!cfg) {
01643 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
01644 return 0;
01645 }
01646 memset(&ba, 0, sizeof(ba));
01647 val = ast_variable_retrieve(cfg, "general", "enabled");
01648 if (val)
01649 enabled = ast_true(val);
01650
01651 val = ast_variable_retrieve(cfg, "general", "block-sockets");
01652 if(val)
01653 block_sockets = ast_true(val);
01654
01655 if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
01656 if (sscanf(val, "%d", &portno) != 1) {
01657 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
01658 portno = DEFAULT_MANAGER_PORT;
01659 }
01660 } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
01661 if (sscanf(val, "%d", &portno) != 1) {
01662 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
01663 portno = DEFAULT_MANAGER_PORT;
01664 }
01665 ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val);
01666 }
01667
01668 ba.sin_family = AF_INET;
01669 ba.sin_port = htons(portno);
01670 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
01671
01672 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
01673 if (!inet_aton(val, &ba.sin_addr)) {
01674 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
01675 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
01676 }
01677 }
01678
01679 if ((asock > -1) && ((portno != oldportno) || !enabled)) {
01680 #if 0
01681
01682 close(asock);
01683 asock = -1;
01684 #else
01685 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
01686 #endif
01687 }
01688 ast_destroy(cfg);
01689
01690
01691 if (!enabled) {
01692 return 0;
01693 }
01694 if (asock < 0) {
01695 asock = socket(AF_INET, SOCK_STREAM, 0);
01696 if (asock < 0) {
01697 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01698 return -1;
01699 }
01700 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
01701 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
01702 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
01703 close(asock);
01704 asock = -1;
01705 return -1;
01706 }
01707 if (listen(asock, 2)) {
01708 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
01709 close(asock);
01710 asock = -1;
01711 return -1;
01712 }
01713 if (option_verbose)
01714 ast_verbose("Asterisk Management interface listening on port %d\n", portno);
01715 ast_pthread_create(&t, NULL, accept_thread, NULL);
01716 }
01717 return 0;
01718 }
01719
01720 int reload_manager(void)
01721 {
01722 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
01723 return init_manager();
01724 }