Newer
Older
ast_module_reload(rld);
}
} else {
ast_config_destroy(cfg);
switch(result) {
case UNKNOWN_ACTION:
astman_send_error(s, m, "Unknown action command");
break;
case UNKNOWN_CATEGORY:
astman_send_error(s, m, "Given category does not exist");
break;
case UNSPECIFIED_CATEGORY:
astman_send_error(s, m, "Category not specified");
break;
case UNSPECIFIED_ARGUMENT:
astman_send_error(s, m, "Problem with category, value, or line (if required)");
break;
case FAILURE_ALLOCATION:
astman_send_error(s, m, "Memory allocation failure, this should not happen");
break;
case FAILURE_NEWCAT:
astman_send_error(s, m, "Create category did not complete successfully");
break;
case FAILURE_DELCAT:
astman_send_error(s, m, "Delete category did not complete successfully");
break;
case FAILURE_EMPTYCAT:
astman_send_error(s, m, "Empty category did not complete successfully");
break;
case FAILURE_UPDATE:
astman_send_error(s, m, "Update did not complete successfully");
break;
case FAILURE_DELETE:
astman_send_error(s, m, "Delete did not complete successfully");
break;
case FAILURE_APPEND:
astman_send_error(s, m, "Append did not complete successfully");
break;
case FAILURE_TEMPLATE:
astman_send_error(s, m, "Template category not found");
break;
return 0;
}
static int action_createconfig(struct mansession *s, const struct message *m)
{
int fd;
const char *fn = astman_get_header(m, "Filename");
struct ast_str *filepath = ast_str_alloca(PATH_MAX);
ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
ast_str_append(&filepath, 0, "%s", fn);
if ((fd = open(ast_str_buffer(filepath), O_CREAT | O_EXCL, AST_FILE_MODE)) != -1) {
close(fd);
astman_send_ack(s, m, "New configuration file created successfully");
} else {
astman_send_error(s, m, strerror(errno));
}
return 0;
}
static int action_waitevent(struct mansession *s, const struct message *m)
Mark Spencer
committed
{
const char *timeouts = astman_get_header(m, "Timeout");
Mark Spencer
committed
int x;
int needexit = 0;
Tilghman Lesher
committed
const char *id = astman_get_header(m, "ActionID");
char idText[256];
Mark Spencer
committed
if (!ast_strlen_zero(id)) {
Mark Spencer
committed
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
} else {
Tilghman Lesher
committed
idText[0] = '\0';
Mark Spencer
committed
if (!ast_strlen_zero(timeouts)) {
if (timeout < -1) {
/* XXX maybe put an upper bound, or prevent the use of 0 ? */
Mark Spencer
committed
}
if (s->session->waiting_thread != AST_PTHREADT_NULL) {
pthread_kill(s->session->waiting_thread, SIGURG);
if (s->session->managerid) { /* AMI-over-HTTP session */
/*
* Make sure the timeout is within the expire time of the session,
* as the client will likely abort the request if it does not see
* data coming after some amount of time.
*/
time_t now = time(NULL);
int max = s->session->sessiontimeout - now - 10;
if (max < 0) { /* We are already late. Strange but possible. */
Mark Spencer
committed
max = 0;
}
if (timeout < 0 || timeout > max) {
Mark Spencer
committed
timeout = max;
}
if (!s->session->send_events) { /* make sure we record events */
s->session->send_events = -1;
Mark Spencer
committed
}
/* XXX should this go inside the lock ? */
s->session->waiting_thread = pthread_self(); /* let new events wake up this thread */
ast_debug(1, "Starting waiting for an event!\n");
for (x = 0; x < timeout || timeout < 0; x++) {
Tilghman Lesher
committed
if (AST_RWLIST_NEXT(s->session->last_ev, eq_next)) {
Mark Spencer
committed
needexit = 1;
/* We can have multiple HTTP session point to the same mansession entry.
* The way we deal with it is not very nice: newcomers kick out the previous
* HTTP session. XXX this needs to be improved.
*/
if (s->session->waiting_thread != pthread_self()) {
Mark Spencer
committed
needexit = 1;
}
if (s->session->needdestroy) {
Mark Spencer
committed
needexit = 1;
if (needexit) {
Mark Spencer
committed
break;
if (s->session->managerid == 0) { /* AMI session */
if (ast_wait_for_input(s->session->fd, 1000)) {
Mark Spencer
committed
break;
} else { /* HTTP session */
Mark Spencer
committed
sleep(1);
}
}
ast_debug(1, "Finished waiting for an event!\n");
if (s->session->waiting_thread == pthread_self()) {
Tilghman Lesher
committed
struct eventqent *eqe = s->session->last_ev;
astman_send_response(s, m, "Success", "Waiting for Event completed.");
Tilghman Lesher
committed
while ((eqe = advance_event(eqe))) {
if (((s->session->readperm & eqe->category) == eqe->category)
&& ((s->session->send_events & eqe->category) == eqe->category)
&& match_filter(s, eqe->eventdata)) {
astman_append(s, "%s", eqe->eventdata);
}
Tilghman Lesher
committed
s->session->last_ev = eqe;
Mark Spencer
committed
}
astman_append(s,
"Event: WaitEventComplete\r\n"
"%s"
s->session->waiting_thread = AST_PTHREADT_NULL;
Mark Spencer
committed
} else {
ast_debug(1, "Abandoning event request!\n");
Mark Spencer
committed
}
Mark Spencer
committed
return 0;
}
static int action_listcommands(struct mansession *s, const struct message *m)
struct manager_action *cur;
struct ast_str *temp = ast_str_alloca(MAX_AUTH_PERM_STRING);
astman_start_ack(s, m);
AST_RWLIST_RDLOCK(&actions);
AST_RWLIST_TRAVERSE(&actions, cur, list) {
if ((s->session->writeperm & cur->authority) || cur->authority == 0) {
astman_append(s, "%s: %s (Priv: %s)\r\n",
cur->action, cur->synopsis, authority_to_str(cur->authority, &temp));
AST_RWLIST_UNLOCK(&actions);
astman_append(s, "\r\n");
static int action_events(struct mansession *s, const struct message *m)
const char *mask = astman_get_header(m, "EventMask");
const char *id = astman_get_header(m, "ActionID");
char id_text[256];
if (!ast_strlen_zero(id)) {
snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
} else {
id_text[0] = '\0';
}
res = set_eventmask(s, mask);
if (broken_events_action) {
/* if this option is set we should not return a response on
* error, or when all events are set */
if (res > 0) {
for (x = 0; x < ARRAY_LEN(perms); x++) {
if (!strcasecmp(perms[x].label, "all") && res == perms[x].num) {
return 0;
}
}
astman_append(s, "Response: Success\r\n%s"
"Events: On\r\n\r\n", id_text);
astman_append(s, "Response: Success\r\n%s"
"Events: Off\r\n\r\n", id_text);
if (res > 0)
astman_append(s, "Response: Success\r\n%s"
"Events: On\r\n\r\n", id_text);
else if (res == 0)
astman_append(s, "Response: Success\r\n%s"
"Events: Off\r\n\r\n", id_text);
else
astman_send_error(s, m, "Invalid event mask");
static int action_logoff(struct mansession *s, const struct message *m)
astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
static int action_login(struct mansession *s, const struct message *m)
/* still authenticated - don't process again */
if (s->session->authenticated) {
astman_send_ack(s, m, "Already authenticated");
return 0;
}
if (authenticate(s, m)) {
sleep(1);
astman_send_error(s, m, "Authentication failed");
return -1;
}
s->session->authenticated = 1;
ast_atomic_fetchadd_int(&unauth_sessions, -1);
if (manager_displayconnects(s->session)) {
ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_sockaddr_stringify_addr(&s->session->addr));
astman_send_ack(s, m, "Authentication accepted");
if ((s->session->send_events & EVENT_FLAG_SYSTEM)
&& (s->session->readperm & EVENT_FLAG_SYSTEM)
&& ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
struct ast_str *auth = ast_str_alloca(MAX_AUTH_PERM_STRING);
const char *cat_str = authority_to_str(EVENT_FLAG_SYSTEM, &auth);
astman_append(s, "Event: FullyBooted\r\n"
"Privilege: %s\r\n"
"Status: Fully Booted\r\n\r\n", cat_str);
return 0;
}
static int action_challenge(struct mansession *s, const struct message *m)
const char *authtype = astman_get_header(m, "AuthType");
if (!strcasecmp(authtype, "MD5")) {
if (ast_strlen_zero(s->session->challenge)) {
snprintf(s->session->challenge, sizeof(s->session->challenge), "%ld", ast_random());
Eliel C. Sardanons
committed
mansession_lock(s);
astman_start_ack(s, m);
astman_append(s, "Challenge: %s\r\n\r\n", s->session->challenge);
Eliel C. Sardanons
committed
mansession_unlock(s);
} else {
astman_send_error(s, m, "Must specify AuthType");
}
return 0;
}
static int action_hangup(struct mansession *s, const struct message *m)
int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
const char *id = astman_get_header(m, "ActionID");
const char *name_or_regex = astman_get_header(m, "Channel");
const char *cause = astman_get_header(m, "Cause");
char idText[256];
regex_t regexbuf;
struct ast_channel_iterator *iter = NULL;
struct ast_str *regex_string;
int channels_matched = 0;
if (ast_strlen_zero(name_or_regex)) {
astman_send_error(s, m, "No channel specified");
if (!ast_strlen_zero(id)) {
snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
} else {
idText[0] = '\0';
if (!ast_strlen_zero(cause)) {
char *endptr;
causecode = strtol(cause, &endptr, 10);
if (causecode < 0 || causecode > 127 || *endptr != '\0') {
ast_log(LOG_NOTICE, "Invalid 'Cause: %s' in manager action Hangup\n", cause);
/* keep going, better to hangup without cause than to not hang up at all */
causecode = 0; /* do not set channel's hangupcause */
}
}
/************************************************/
/* Regular explicit match channel byname hangup */
if (name_or_regex[0] != '/') {
if (!(c = ast_channel_get_by_name(name_or_regex))) {
ast_log(LOG_NOTICE, "Request to hangup non-existent channel: %s\n",
name_or_regex);
astman_send_error(s, m, "No such channel");
return 0;
}
ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
(s->session->managerid ? "HTTP " : ""),
s->session->username,
ast_sockaddr_stringify_addr(&s->session->addr),
ast_channel_name(c));
ast_channel_softhangup_withcause_locked(c, causecode);
c = ast_channel_unref(c);
astman_send_ack(s, m, "Channel Hungup");
return 0;
}
/***********************************************/
/* find and hangup any channels matching regex */
regex_string = ast_str_create(strlen(name_or_regex));
if (!regex_string) {
astman_send_error(s, m, "Memory Allocation Failure");
return 0;
}
/* Make "/regex/" into "regex" */
if (ast_regex_string_to_regex_pattern(name_or_regex, ®ex_string) != 0) {
astman_send_error(s, m, "Regex format invalid, Channel param should be /regex/");
ast_free(regex_string);
/* if regex compilation fails, hangup fails */
if (regcomp(®exbuf, ast_str_buffer(regex_string), REG_EXTENDED | REG_NOSUB)) {
astman_send_error_va(s, m, "Regex compile failed on: %s", name_or_regex);
ast_free(regex_string);
return 0;
}
astman_send_listack(s, m, "Channels hung up will follow", "start");
iter = ast_channel_iterator_all_new();
if (iter) {
for (; (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
if (regexec(®exbuf, ast_channel_name(c), 0, NULL, 0)) {
continue;
}
ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
(s->session->managerid ? "HTTP " : ""),
s->session->username,
ast_sockaddr_stringify_addr(&s->session->addr),
ast_channel_name(c));
ast_channel_softhangup_withcause_locked(c, causecode);
channels_matched++;
astman_append(s,
"Event: ChannelHungup\r\n"
"Channel: %s\r\n"
"%s"
"\r\n", ast_channel_name(c), idText);
}
ast_channel_iterator_destroy(iter);
regfree(®exbuf);
ast_free(regex_string);
astman_send_list_complete_start(s, m, "ChannelsHungupListComplete", channels_matched);
astman_send_list_complete_end(s);
static int action_setvar(struct mansession *s, const struct message *m)
{
struct ast_channel *c = NULL;
const char *name = astman_get_header(m, "Channel");
const char *varname = astman_get_header(m, "Variable");
const char *varval = astman_get_header(m, "Value");
astman_send_error(s, m, "No variable specified");
return 0;
}
if (!(c = ast_channel_get_by_name(name))) {
astman_send_error(s, m, "No such channel");
return 0;
}
}
Olle Johansson
committed
res = pbx_builtin_setvar_helper(c, varname, S_OR(varval, ""));
if (c) {
c = ast_channel_unref(c);
astman_send_ack(s, m, "Variable Set");
} else {
astman_send_error(s, m, "Variable not set");
}
return 0;
}
static int action_getvar(struct mansession *s, const struct message *m)
{
struct ast_channel *c = NULL;
const char *name = astman_get_header(m, "Channel");
const char *varname = astman_get_header(m, "Variable");
char *varval;
if (ast_strlen_zero(varname)) {
astman_send_error(s, m, "No variable specified");
return 0;
}
Jonathan Rose
committed
/* We don't want users with insufficient permissions using certain functions. */
if (!(function_capable_string_allowed_with_auths(varname, s->session->writeperm))) {
astman_send_error(s, m, "GetVar Access Forbidden: Variable");
return 0;
}
if (!ast_strlen_zero(name)) {
if (!(c = ast_channel_get_by_name(name))) {
astman_send_error(s, m, "No such channel");
return 0;
}
}
Tilghman Lesher
committed
if (varname[strlen(varname) - 1] == ')') {
if (!c) {
c = ast_dummy_channel_alloc();
if (c) {
ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
} else
ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
} else {
ast_func_read(c, (char *) varname, workspace, sizeof(workspace));
}
Tilghman Lesher
committed
} else {
pbx_retrieve_variable(c, varname, &varval, workspace, sizeof(workspace), NULL);
}
if (c) {
c = ast_channel_unref(c);
astman_start_ack(s, m);
astman_append(s, "Variable: %s\r\nValue: %s\r\n\r\n", varname, S_OR(varval, ""));
return 0;
}
/*! \brief Manager "status" command to show channels */
/* Needs documentation... */
static int action_status(struct mansession *s, const struct message *m)
Tilghman Lesher
committed
const char *name = astman_get_header(m, "Channel");
const char *chan_variables = astman_get_header(m, "Variables");
const char *id = astman_get_header(m, "ActionID");
char *variables = ast_strdupa(S_OR(chan_variables, ""));
struct ast_str *variable_str = ast_str_create(1024);
struct ast_str *write_transpath = ast_str_alloca(256);
struct ast_str *read_transpath = ast_str_alloca(256);
struct ast_channel *chan;
Alexander Traud
committed
struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
int all = ast_strlen_zero(name); /* set if we want all channels */
char id_text[256];
struct ast_channel_iterator *it_chans = NULL;
Tilghman Lesher
committed
AST_DECLARE_APP_ARGS(vars,
AST_APP_ARG(name)[100];
);
if (!variable_str) {
astman_send_error(s, m, "Memory Allocation Failure");
return 1;
Jonathan Rose
committed
if (!(function_capable_string_allowed_with_auths(variables, s->session->writeperm))) {
ast_free(variable_str);
Jonathan Rose
committed
astman_send_error(s, m, "Status Access Forbidden: Variables");
return 0;
}
if (all) {
if (!(it_chans = ast_channel_iterator_all_new())) {
ast_free(variable_str);
astman_send_error(s, m, "Memory Allocation Failure");
return 1;
}
chan = ast_channel_iterator_next(it_chans);
} else {
chan = ast_channel_get_by_name(name);
if (!chan) {
Mark Spencer
committed
astman_send_error(s, m, "No such channel");
ast_free(variable_str);
Mark Spencer
committed
return 0;
}
}
astman_send_listack(s, m, "Channel status will follow", "start");
if (!ast_strlen_zero(id)) {
snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
} else {
id_text[0] = '\0';
}
if (!ast_strlen_zero(chan_variables)) {
Tilghman Lesher
committed
AST_STANDARD_APP_ARGS(vars, variables);
}
Kevin P. Fleming
committed
/* if we look by name, we break after the first iteration */
for (; chan; all ? chan = ast_channel_iterator_next(it_chans) : 0) {
struct timeval now;
long elapsed_seconds;
struct ast_bridge *bridge;
ast_channel_lock(chan);
now = ast_tvnow();
elapsed_seconds = ast_tvdiff_sec(now, ast_channel_creationtime(chan));
if (!ast_strlen_zero(chan_variables)) {
Tilghman Lesher
committed
int i;
ast_str_reset(variable_str);
Tilghman Lesher
committed
for (i = 0; i < vars.argc; i++) {
char valbuf[512], *ret = NULL;
if (vars.name[i][strlen(vars.name[i]) - 1] == ')') {
if (ast_func_read(chan, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
Tilghman Lesher
committed
valbuf[0] = '\0';
}
ret = valbuf;
} else {
pbx_retrieve_variable(chan, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
Tilghman Lesher
committed
}
ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
Tilghman Lesher
committed
}
}
bridge = ast_channel_get_bridge(chan);
astman_append(s,
"Event: Status\r\n"
"Privilege: Call\r\n"
"Channel: %s\r\n"
"ChannelState: %u\r\n"
"ChannelStateDesc: %s\r\n"
"CallerIDNum: %s\r\n"
"CallerIDName: %s\r\n"
"ConnectedLineNum: %s\r\n"
"ConnectedLineName: %s\r\n"
"Accountcode: %s\r\n"
"Context: %s\r\n"
"Exten: %s\r\n"
"Priority: %d\r\n"
"Uniqueid: %s\r\n"
"Type: %s\r\n"
"DNID: %s\r\n"
"EffectiveConnectedLineNum: %s\r\n"
"EffectiveConnectedLineName: %s\r\n"
"TimeToHangup: %ld\r\n"
"BridgeID: %s\r\n"
"Linkedid: %s\r\n"
"Application: %s\r\n"
"Data: %s\r\n"
"Nativeformats: %s\r\n"
"Readformat: %s\r\n"
"Readtrans: %s\r\n"
"Writeformat: %s\r\n"
"Writetrans: %s\r\n"
"Callgroup: %llu\r\n"
"Pickupgroup: %llu\r\n"
"Seconds: %ld\r\n"
"%s"
"%s"
"\r\n",
ast_channel_name(chan),
ast_channel_state(chan),
ast_state2str(ast_channel_state(chan)),
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>"),
S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "<unknown>"),
S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "<unknown>"),
ast_channel_accountcode(chan),
ast_channel_context(chan),
ast_channel_exten(chan),
ast_channel_priority(chan),
ast_channel_uniqueid(chan),
ast_channel_tech(chan)->type,
S_OR(ast_channel_dialed(chan)->number.str, ""),
S_COR(ast_channel_connected_effective_id(chan).number.valid, ast_channel_connected_effective_id(chan).number.str, "<unknown>"),
S_COR(ast_channel_connected_effective_id(chan).name.valid, ast_channel_connected_effective_id(chan).name.str, "<unknown>"),
(long)ast_channel_whentohangup(chan)->tv_sec,
bridge ? bridge->uniqueid : "",
ast_channel_linkedid(chan),
ast_channel_appl(chan),
ast_channel_data(chan),
ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf),
ast_format_get_name(ast_channel_readformat(chan)),
ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath),
ast_format_get_name(ast_channel_writeformat(chan)),
ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath),
ast_channel_callgroup(chan),
ast_channel_pickupgroup(chan),
(long)elapsed_seconds,
ast_str_buffer(variable_str),
id_text);
ao2_cleanup(bridge);
ast_channel_unlock(chan);
chan = ast_channel_unref(chan);
}
if (it_chans) {
ast_channel_iterator_destroy(it_chans);
Kevin P. Fleming
committed
}
astman_send_list_complete_start(s, m, "StatusComplete", channels);
astman_append(s, "Items: %d\r\n", channels);
astman_send_list_complete_end(s);
ast_free(variable_str);
static int action_sendtext(struct mansession *s, const struct message *m)
{
struct ast_channel *c = NULL;
const char *name = astman_get_header(m, "Channel");
const char *textmsg = astman_get_header(m, "Message");
int res = 0;
Russell Bryant
committed
if (ast_strlen_zero(name)) {
astman_send_error(s, m, "No channel specified");
return 0;
}
Russell Bryant
committed
if (ast_strlen_zero(textmsg)) {
astman_send_error(s, m, "No Message specified");
return 0;
}
if (!(c = ast_channel_get_by_name(name))) {
astman_send_error(s, m, "No such channel");
return 0;
}
res = ast_sendtext(c, textmsg);
c = ast_channel_unref(c);
astman_send_ack(s, m, "Success");
} else {
astman_send_error(s, m, "Failure");
}
/*! \brief action_redirect: The redirect manager command */
static int action_redirect(struct mansession *s, const struct message *m)
Richard Mudgett
committed
char buf[256];
const char *name = astman_get_header(m, "Channel");
const char *name2 = astman_get_header(m, "ExtraChannel");
const char *exten = astman_get_header(m, "Exten");
const char *exten2 = astman_get_header(m, "ExtraExten");
const char *context = astman_get_header(m, "Context");
const char *context2 = astman_get_header(m, "ExtraContext");
const char *priority = astman_get_header(m, "Priority");
const char *priority2 = astman_get_header(m, "ExtraPriority");
Richard Mudgett
committed
struct ast_channel *chan;
struct ast_channel *chan2;
int pi = 0;
int pi2 = 0;
Mark Michelson
committed
int chan1_wait = 0;
int chan2_wait = 0;
if (ast_strlen_zero(name)) {
astman_send_error(s, m, "Channel not specified");
Richard Mudgett
committed
if (ast_strlen_zero(context)) {
astman_send_error(s, m, "Context not specified");
return 0;
}
if (ast_strlen_zero(exten)) {
astman_send_error(s, m, "Exten not specified");
return 0;
}
if (ast_strlen_zero(priority)) {
astman_send_error(s, m, "Priority not specified");
return 0;
}
if (sscanf(priority, "%30d", &pi) != 1) {
pi = ast_findlabel_extension(NULL, context, exten, priority, NULL);
}
if (pi < 1) {
astman_send_error(s, m, "Priority is invalid");
return 0;
Richard Mudgett
committed
if (!ast_strlen_zero(name2) && !ast_strlen_zero(context2)) {
/* We have an ExtraChannel and an ExtraContext */
if (ast_strlen_zero(exten2)) {
astman_send_error(s, m, "ExtraExten not specified");
return 0;
}
if (ast_strlen_zero(priority2)) {
astman_send_error(s, m, "ExtraPriority not specified");
return 0;
}
if (sscanf(priority2, "%30d", &pi2) != 1) {
pi2 = ast_findlabel_extension(NULL, context2, exten2, priority2, NULL);
}
if (pi2 < 1) {
astman_send_error(s, m, "ExtraPriority is invalid");
return 0;
}
}
Richard Mudgett
committed
chan = ast_channel_get_by_name(name);
if (!chan) {
snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
astman_send_error(s, m, buf);
if (ast_check_hangup_locked(chan)) {
astman_send_error(s, m, "Redirect failed, channel not up.");
chan = ast_channel_unref(chan);
Richard Mudgett
committed
if (ast_strlen_zero(name2)) {
/* Single channel redirect in progress. */
res = ast_async_goto(chan, context, exten, pi);
if (!res) {
astman_send_ack(s, m, "Redirect successful");
} else {
astman_send_error(s, m, "Redirect failed");
}
chan = ast_channel_unref(chan);
return 0;
}
Richard Mudgett
committed
chan2 = ast_channel_get_by_name(name2);
if (!chan2) {
snprintf(buf, sizeof(buf), "ExtraChannel does not exist: %s", name2);
astman_send_error(s, m, buf);
chan = ast_channel_unref(chan);
Richard Mudgett
committed
return 0;
}
if (ast_check_hangup_locked(chan2)) {
astman_send_error(s, m, "Redirect failed, extra channel not up.");
chan2 = ast_channel_unref(chan2);
Richard Mudgett
committed
chan = ast_channel_unref(chan);
Richard Mudgett
committed
/* Dual channel redirect in progress. */
Mark Michelson
committed
ast_channel_lock(chan);
if (ast_channel_is_bridged(chan)) {
Richard Mudgett
committed
ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
Mark Michelson
committed
chan1_wait = 1;
Mark Michelson
committed
ast_channel_unlock(chan);
ast_channel_lock(chan2);
if (ast_channel_is_bridged(chan2)) {
Richard Mudgett
committed
ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
Mark Michelson
committed
chan2_wait = 1;
Richard Mudgett
committed
}
Mark Michelson
committed
ast_channel_unlock(chan2);
res = ast_async_goto(chan, context, exten, pi);
Richard Mudgett
committed
if (!ast_strlen_zero(context2)) {
res = ast_async_goto(chan2, context2, exten2, pi2);
} else {
Richard Mudgett
committed
res = ast_async_goto(chan2, context, exten, pi);
}
if (!res) {
astman_send_ack(s, m, "Dual Redirect successful");
} else {
astman_send_error(s, m, "Secondary redirect failed");
}
} else {
astman_send_error(s, m, "Redirect failed");
Richard Mudgett
committed
/* Release the bridge wait. */
Mark Michelson
committed
if (chan1_wait) {
ast_channel_clear_flag(chan, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
Richard Mudgett
committed
}
Mark Michelson
committed
if (chan2_wait) {
ast_channel_clear_flag(chan2, AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT);
Richard Mudgett
committed
chan2 = ast_channel_unref(chan2);
chan = ast_channel_unref(chan);
Richard Mudgett
committed
static int action_blind_transfer(struct mansession *s, const struct message *m)
{
const char *name = astman_get_header(m, "Channel");
const char *exten = astman_get_header(m, "Exten");
const char *context = astman_get_header(m, "Context");
Richard Mudgett
committed
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
if (ast_strlen_zero(name)) {
astman_send_error(s, m, "No channel specified");
return 0;
}
if (ast_strlen_zero(exten)) {
astman_send_error(s, m, "No extension specified");
return 0;
}
chan = ast_channel_get_by_name(name);
if (!chan) {
astman_send_error(s, m, "Channel specified does not exist");
return 0;
}
if (ast_strlen_zero(context)) {
context = ast_channel_context(chan);
}
switch (ast_bridge_transfer_blind(1, chan, exten, context, NULL, NULL)) {
Richard Mudgett
committed
case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
astman_send_error(s, m, "Transfer not permitted");
break;
case AST_BRIDGE_TRANSFER_INVALID:
astman_send_error(s, m, "Transfer invalid");
break;
case AST_BRIDGE_TRANSFER_FAIL:
astman_send_error(s, m, "Transfer failed");
break;
case AST_BRIDGE_TRANSFER_SUCCESS:
astman_send_ack(s, m, "Transfer succeeded");
break;
}
Richard Mudgett
committed
return 0;
}
static int action_atxfer(struct mansession *s, const struct message *m)
{
const char *name = astman_get_header(m, "Channel");
const char *exten = astman_get_header(m, "Exten");
const char *context = astman_get_header(m, "Context");
struct ast_channel *chan = NULL;
char feature_code[AST_FEATURE_MAX_LEN];
const char *digit;
if (ast_strlen_zero(name)) {
astman_send_error(s, m, "No channel specified");
return 0;
}
if (ast_strlen_zero(exten)) {
astman_send_error(s, m, "No extension specified");
return 0;
}
if (!(chan = ast_channel_get_by_name(name))) {
astman_send_error(s, m, "Channel specified does not exist");
return 0;
}
ast_channel_lock(chan);
if (ast_get_builtin_feature(chan, "atxfer", feature_code, sizeof(feature_code)) ||
ast_strlen_zero(feature_code)) {
ast_channel_unlock(chan);
astman_send_error(s, m, "No attended transfer feature code found");
ast_channel_unref(chan);
return 0;
}
if (!ast_strlen_zero(context)) {
pbx_builtin_setvar_helper(chan, "TRANSFER_CONTEXT", context);
}
for (digit = feature_code; *digit; ++digit) {
struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
ast_queue_frame(chan, &f);
}
for (digit = exten; *digit; ++digit) {
struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
ast_queue_frame(chan, &f);
}
chan = ast_channel_unref(chan);
astman_send_ack(s, m, "Atxfer successfully queued");
return 0;
}
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
static int action_cancel_atxfer(struct mansession *s, const struct message *m)
{
const char *name = astman_get_header(m, "Channel");
struct ast_channel *chan = NULL;
char *feature_code;
const char *digit;
if (ast_strlen_zero(name)) {
astman_send_error(s, m, "No channel specified");
return 0;
}
if (!(chan = ast_channel_get_by_name(name))) {
astman_send_error(s, m, "Channel specified does not exist");
return 0;
}
ast_channel_lock(chan);
feature_code = ast_get_chan_features_atxferabort(chan);
ast_channel_unlock(chan);
if (!feature_code) {
astman_send_error(s, m, "No disconnect feature code found");
ast_channel_unref(chan);
return 0;
}
for (digit = feature_code; *digit; ++digit) {
struct ast_frame f = { AST_FRAME_DTMF, .subclass.integer = *digit };
ast_queue_frame(chan, &f);
}
ast_free(feature_code);
chan = ast_channel_unref(chan);
astman_send_ack(s, m, "CancelAtxfer successfully queued");
return 0;
}
static int check_blacklist(const char *cmd)
{
char *cmd_copy, *cur_cmd;
char *cmd_words[AST_MAX_CMD_LEN] = { NULL, };