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