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