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