freeswitch/src/mod/applications/mod_commands/mod_commands.c

3830 lines
104 KiB
C
Raw Normal View History

/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
* Michael Jerris <mike@jerris.com>
* Johny Kadarisman <jkr888@gmail.com>
* Paul Tinsley <jackhammer@gmail.com>
* Marcel Barbulescu <marcelbarbulescu@gmail.com>
* Bret McDanel <trixter AT 0xdecafbad.com>
* Cesar Cepeda <cesar@auronix.com>
* Massimo Cetra <devel@navynet.it>
* Rupa Schomaker <rupa@rupa.com>
*
*
* mod_commands.c -- Misc. Command Module
*
*/
#include <switch.h>
#include <switch_stun.h>
#include <switch_version.h>
SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_commands_shutdown);
SWITCH_MODULE_DEFINITION(mod_commands, mod_commands_load, mod_commands_shutdown, NULL);
SWITCH_STANDARD_API(hostname_api_function)
{
char hostname[256]="";
gethostname(hostname, sizeof(hostname));
stream->write_function(stream, "%s",hostname);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(host_lookup_function)
{
char host[256] = "";
if (zstr(cmd)) {
stream->write_function(stream, "%s", "parameter missing\n");
} else {
if (switch_resolve_host(cmd, host, sizeof(host)) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "%s", host);
} else {
stream->write_function(stream, "%s", "!err!");
}
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(nat_map_function)
{
int argc;
char *mydata = NULL, *argv[5];
switch_nat_ip_proto_t proto = SWITCH_NAT_UDP;
switch_port_t external_port = 0;
char *tmp = NULL;
switch_bool_t sticky = SWITCH_FALSE;
if (!cmd) {
goto error;
}
mydata = strdup(cmd);
switch_assert(mydata);
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 1) {
goto error;
}
if (argv[0] && switch_stristr("status", argv[0])) {
tmp = switch_nat_status();
stream->write_function(stream, tmp);
switch_safe_free(tmp);
goto ok;
} else if (argv[0] && switch_stristr("republish", argv[0])) {
switch_nat_republish();
stream->write_function(stream, "true");
goto ok;
} else if (argv[0] && switch_stristr("reinit", argv[0])) {
switch_nat_reinit();
tmp = switch_nat_status();
stream->write_function(stream, tmp);
switch_safe_free(tmp);
goto ok;
}
if (argc < 3) {
goto error;
}
if (argv[2] && switch_stristr("tcp", argv[2])) {
proto = SWITCH_NAT_TCP;
} else if (argv[2] && switch_stristr("udp", argv[2])) {
proto = SWITCH_NAT_UDP;
}
if (argv[3] && switch_stristr("sticky", argv[3])) {
sticky = SWITCH_TRUE;
}
if (argv[0] && switch_stristr("add", argv[0])) {
if (switch_nat_add_mapping((switch_port_t)atoi(argv[1]), proto, &external_port, sticky) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "true"); /* still return true */
goto ok;
}
} else if (argv[0] && switch_stristr("del", argv[0])) {
if (switch_nat_del_mapping((switch_port_t)atoi(argv[1]), proto) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "true");
goto ok;
}
}
error:
stream->write_function(stream, "false");
ok:
switch_safe_free(mydata);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(time_test_function)
{
switch_time_t now, then;
int x;
long mss;
uint32_t total = 0;
int diff;
int max = 10, a = 0;
char *p;
if (zstr(cmd)){
stream->write_function(stream, "parameter missing\n");
return SWITCH_STATUS_SUCCESS;
}
mss = atol(cmd);
if (mss > 1000000) {
mss = 1000000;
}
if ((p = strchr(cmd, ' '))) {
if ((a = atoi(p+1)) > 0) {
max = a;
if (max > 100) {
max = 100;
}
}
}
for (x = 1; x <= max; x++) {
then = switch_time_now();
switch_yield(mss);
now = switch_time_now();
diff = (int) (now - then);
stream->write_function(stream, "test %d sleep %ld %d\n", x, mss, diff);
total += diff;
}
stream->write_function(stream, "avg %d\n", total / (x > 1 ? x - 1 : 1));
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(group_call_function)
{
char *domain;
char *group_name = NULL;
char *flags;
int ok = 0;
switch_channel_t *channel = NULL;
char *fp = NULL;
const char *call_delim = ",";
if (zstr(cmd)) {
goto end;
}
if (session) {
channel = switch_core_session_get_channel(session);
}
group_name = strdup(cmd);
switch_assert(group_name);
if ((flags = strchr(group_name, '+'))) {
*flags++ = '\0';
for (fp = flags; fp && *fp; fp++) {
switch(*fp) {
case 'F':
call_delim = "|";
break;
case 'A':
call_delim = ",";
case 'E':
call_delim = SWITCH_ENT_ORIGINATE_DELIM;
break;
default:
break;
}
}
}
domain = strchr(group_name, '@');
if (domain) {
*domain++ = '\0';
} else {
domain = switch_core_get_variable("domain");
}
if (!zstr(domain)) {
switch_xml_t xml, x_domain, x_group;
switch_event_t *params;
switch_stream_handle_t dstream = { 0 };
SWITCH_STANDARD_STREAM(dstream);
switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "group", group_name);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "domain", domain);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "action", "group_call");
if (switch_xml_locate_group(group_name, domain, &xml, &x_domain, &x_group, params) == SWITCH_STATUS_SUCCESS) {
switch_xml_t x_user, x_users, x_param, x_params;
if ((x_users = switch_xml_child(x_group, "users"))) {
ok++;
for(x_user = switch_xml_child(x_users, "user"); x_user; x_user = x_user->next) {
const char *id = switch_xml_attr_soft(x_user, "id");
const char *dest = NULL;
char *d_dest = NULL;
if ((x_params = switch_xml_child(x_domain, "params"))) {
for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
const char *var = switch_xml_attr(x_param, "name");
const char *val = switch_xml_attr(x_param, "value");
if (!strcasecmp(var, "group-dial-string")) {
dest = val;
break;
}
if (!strcasecmp(var, "dial-string")) {
dest = val;
}
}
}
if ((x_params = switch_xml_child(x_group, "params"))) {
for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
const char *var = switch_xml_attr(x_param, "name");
const char *val = switch_xml_attr(x_param, "value");
if (!strcasecmp(var, "group-dial-string")) {
dest = val;
break;
}
if (!strcasecmp(var, "dial-string")) {
dest = val;
}
}
}
if ((x_params = switch_xml_child(x_user, "params"))) {
for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
const char *var = switch_xml_attr(x_param, "name");
const char *val = switch_xml_attr(x_param, "value");
if (!strcasecmp(var, "group-dial-string")) {
dest = val;
break;
}
if (!strcasecmp(var, "dial-string")) {
dest = val;
}
}
}
if (dest) {
if (channel) {
switch_channel_set_variable(channel, "dialed_group", group_name);
switch_channel_set_variable(channel, "dialed_user", id);
switch_channel_set_variable(channel, "dialed_domain", domain);
d_dest = switch_channel_expand_variables(channel, dest);
} else {
switch_event_del_header(params, "dialed_user");
switch_event_del_header(params, "dialed_group");
switch_event_del_header(params, "dialed_domain");
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "dialed_user", id);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "dialed_group", group_name);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "dialed_domain", domain);
d_dest = switch_event_expand_headers(params, dest);
}
} else {
d_dest = switch_mprintf("user/%s@%s", id, domain);
}
if (d_dest) {
dstream.write_function(&dstream, "%s%s", d_dest, call_delim);
if (d_dest != dest) {
free(d_dest);
}
}
}
if (ok && dstream.data) {
char *data = (char *) dstream.data;
char *p;
if ((p = strstr(end_of_p(data) - 3, call_delim))) {
*p = '\0';
}
for (p = data; p && *p; p++) {
if (*p == '{') {
*p = '[';
} else if (*p == '}') {
*p = ']';
}
}
stream->write_function(stream, "%s", data);
free(dstream.data);
} else {
ok = 0;
}
}
}
switch_xml_free(xml);
switch_event_destroy(&params);
}
end:
switch_safe_free(group_name);
if (!ok) {
stream->write_function(stream, "error/NO_ROUTE_DESTINATION");
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(in_group_function)
{
switch_xml_t x_domain, xml = NULL, x_user = NULL, x_group;
int argc;
char *mydata = NULL, *argv[2], *user, *domain;
char delim = ',';
switch_event_t *params = NULL;
const char *rval = "false";
char *group;
if (zstr(cmd) || !(mydata = strdup(cmd))) {
goto end;
}
if ((argc = switch_separate_string(mydata, delim, argv, (sizeof(argv) / sizeof(argv[0])))) < 2) {
goto end;
}
user = argv[0];
group = argv[1];
if ((domain = strchr(user, '@'))) {
*domain++ = '\0';
} else {
domain = switch_core_get_variable("domain");
}
switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "user", user);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "domain", domain);
if (switch_xml_locate_group(group, domain, &xml, &x_domain, &x_group, params) == SWITCH_STATUS_SUCCESS) {
switch_xml_t x_users;
if ((x_users = switch_xml_child(x_group, "users"))) {
if ((x_user = switch_xml_find_child(x_users, "user", "id", user))) {
rval = "true";
}
}
}
end:
stream->write_function(stream, "%s", rval);
switch_xml_free(xml);
free(mydata);
switch_event_destroy(&params);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(user_data_function)
{
switch_xml_t x_domain, xml = NULL, x_user = NULL, x_param, x_params;
int argc;
char *mydata = NULL, *argv[3], *key = NULL, *type = NULL, *user, *domain;
char delim = ' ';
const char *container = "params", *elem = "param";
switch_event_t *params = NULL;
if (zstr(cmd) || !(mydata = strdup(cmd))) {
goto end;
}
if ((argc = switch_separate_string(mydata, delim, argv, (sizeof(argv) / sizeof(argv[0])))) < 3) {
goto end;
}
user = argv[0];
type = argv[1];
key = argv[2];
if ((domain = strchr(user, '@'))) {
*domain++ = '\0';
} else {
if (!(domain = switch_core_get_variable("domain"))) {
domain = "cluecon.com";
}
}
switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "user", user);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "domain", domain);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "type", type);
if (key && type && switch_xml_locate_user("id", user, domain, NULL, &xml, &x_domain, &x_user, NULL, params) == SWITCH_STATUS_SUCCESS) {
if (!strcmp(type, "attr")) {
const char *attr = switch_xml_attr_soft(x_user, key);
stream->write_function(stream, "%s", attr);
goto end;
}
if (!strcmp(type, "var")) {
container = "variables";
elem = "variable";
}
if ((x_params = switch_xml_child(x_user, container))) {
for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
const char *var = switch_xml_attr(x_param, "name");
const char *val = switch_xml_attr(x_param, "value");
if (var && val && !strcasecmp(var, key)) {
stream->write_function(stream, "%s", val);
goto end;
}
}
}
if ((x_params = switch_xml_child(x_domain, container))) {
for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
const char *var = switch_xml_attr(x_param, "name");
const char *val = switch_xml_attr(x_param, "value");
if (var && val && !strcasecmp(var, key)) {
stream->write_function(stream, "%s", val);
goto end;
}
}
}
}
end:
switch_xml_free(xml);
free(mydata);
switch_event_destroy(&params);
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t _find_user(const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream, switch_bool_t tf)
{
switch_xml_t x_domain = NULL, x_user = NULL, xml = NULL;
int argc;
char *mydata = NULL, *argv[3];
char *key, *user, *domain;
char *xmlstr;
char *path_info = NULL;
char delim = ' ';
char *host = NULL;
const char *err = NULL;
if (stream->param_event && (host = switch_event_get_header(stream->param_event, "http-host"))) {
stream->write_function(stream, "Content-Type: text/xml\r\n\r\n");
if ((path_info = switch_event_get_header(stream->param_event, "http-path-info"))) {
cmd = path_info;
delim = '/';
}
}
if (!cmd) {
err = "bad args";
goto end;
}
mydata = strdup(cmd);
switch_assert(mydata);
argc = switch_separate_string(mydata, delim, argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 3) {
err = "bad args";
goto end;
}
key = argv[0];
user = argv[1];
domain = argv[2];
if (!(key && user && domain)) {
err = "bad args";
goto end;
}
if (switch_xml_locate_user(key, user, domain, NULL, &xml, &x_domain, &x_user, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
err = "can't find user";
goto end;
}
end:
if (session || tf) {
stream->write_function(stream, err ? "false" : "true");
} else {
if (err) {
if (host) {
stream->write_function(stream, "<error>%s</error>\n", err);
} else {
stream->write_function(stream, "-Error %s\n", err);
}
}
if (x_user) {
xmlstr = switch_xml_toxml(x_user, SWITCH_FALSE);
switch_assert(xmlstr);
stream->write_function(stream, "%s", xmlstr);
free(xmlstr);
}
}
switch_xml_free(xml);
free(mydata);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(md5_function)
{
char digest[SWITCH_MD5_DIGEST_STRING_SIZE] = { 0 };
if (zstr(cmd)) {
stream->write_function(stream, "%s", "!err!");
} else {
switch_md5_string(digest, (void *) cmd, strlen(cmd));
stream->write_function(stream, "%s", digest);
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(url_decode_function)
{
char *reply = "";
char *data = NULL;
if (!zstr(cmd)) {
data = strdup(cmd);
switch_url_decode(data);
reply = data;
}
stream->write_function(stream, "%s", reply);
switch_safe_free(data);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(echo_function)
{
stream->write_function(stream, "%s", cmd);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(stun_function)
{
char *stun_ip = NULL;
switch_port_t stun_port = (switch_port_t)SWITCH_STUN_DEFAULT_PORT;
char *p;
char ip_buf[256] = "";
char *ip = NULL;
char *pip = NULL;
switch_port_t port = 0;
switch_memory_pool_t *pool = NULL;
char *error = "";
ip = ip_buf;
if (zstr(cmd)) {
stream->write_function(stream, "%s", "-STUN Failed! NO STUN SERVER\n");
return SWITCH_STATUS_SUCCESS;
}
stun_ip = strdup(cmd);
switch_assert(stun_ip);
if ((p = strchr(stun_ip, ':'))) {
int iport;
*p++ = '\0';
iport = atoi(p);
if (iport > 0 && iport < 0xFFFF) {
stun_port = (switch_port_t) iport;
}
} else {
p = stun_ip;
}
if (p && (pip = strchr(p, ' '))) {
*pip++ = '\0';
}
if (pip) {
switch_copy_string(ip_buf, pip, sizeof(ip_buf));
} else {
switch_find_local_ip(ip_buf, sizeof(ip_buf), NULL, AF_INET);
}
switch_core_new_memory_pool(&pool);
if (zstr(stun_ip)) {
stream->write_function(stream, "%s", "-STUN Failed! NO STUN SERVER\n");
} else {
if ((switch_stun_lookup(&ip, &port, stun_ip, stun_port, &error, pool)) == SWITCH_STATUS_SUCCESS && ip && port) {
stream->write_function(stream, "%s:%u\n", ip, port);
} else {
stream->write_function(stream, "-STUN Failed! [%s]\n", error);
}
}
switch_core_destroy_memory_pool(&pool);
free(stun_ip);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(expand_function)
{
char *expanded;
char *dup;
char *arg;
char *mycmd;
switch_status_t status;
const char *p;
switch_core_session_t *xsession;
char uuid[80] = "";
if (zstr(cmd)) {
stream->write_function(stream, "-ERR, no input\n");
return SWITCH_STATUS_SUCCESS;
}
dup = strdup(cmd);
mycmd = dup;
if (!strncasecmp(mycmd, "uuid:", 5)) {
p = cmd + 5;
if ((mycmd = strchr(p, ' ')) && *mycmd++) {
switch_copy_string(uuid, p, mycmd - p);
}
}
if (zstr(mycmd)) {
stream->write_function(stream, "-ERR, no input\n");
return SWITCH_STATUS_SUCCESS;
}
if (*uuid) {
if ((xsession = switch_core_session_locate(uuid))) {
switch_channel_event_set_data(switch_core_session_get_channel(xsession), stream->param_event);
switch_core_session_rwunlock(xsession);
}
}
if ((arg = strchr(mycmd, ' '))) {
*arg++ = '\0';
}
expanded = arg ? switch_event_expand_headers(stream->param_event, arg) : arg;
if ((status = switch_api_execute(mycmd, expanded, session, stream)) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "-ERR, error executing command\n");
}
if (expanded != arg) {
free(expanded);
expanded = NULL;
}
free(dup);
dup = NULL;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(eval_function)
{
char *expanded;
switch_event_t *event;
char uuid[80] = "";
const char *p, *input = cmd;
if (zstr(cmd)) {
stream->write_function(stream, "%s", "");
return SWITCH_STATUS_SUCCESS;
}
if (!strncasecmp(cmd, "uuid:", 5)) {
p = cmd + 5;
if ((input = strchr(p, ' ')) && *input++) {
switch_copy_string(uuid, p, input - p);
}
}
if (zstr(input)) {
stream->write_function(stream, "%s", "");
return SWITCH_STATUS_SUCCESS;
}
switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA);
if (*uuid) {
if ((session = switch_core_session_locate(uuid))) {
switch_channel_event_set_data(switch_core_session_get_channel(session), event);
switch_core_session_rwunlock(session);
}
}
expanded = switch_event_expand_headers(event, input);
stream->write_function(stream, "%s", expanded);
if (expanded != input) {
free(expanded);
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(module_exists_function)
{
if (!zstr(cmd)) {
if (switch_loadable_module_exists(cmd) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "true");
} else {
stream->write_function(stream, "false");
}
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(domain_exists_function)
{
switch_xml_t root = NULL, domain = NULL;
if (!zstr(cmd)) {
if (switch_xml_locate_domain(cmd, NULL, &root, &domain) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "true");
switch_xml_free(root);
} else {
stream->write_function(stream, "false");
}
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(url_encode_function)
{
char *reply = "";
char *data = NULL;
int len = 0 ;
if (!zstr(cmd)) {
len = (strlen(cmd) * 3) + 1;
switch_zmalloc(data, len);
switch_url_encode(cmd, data, len);
reply = data;
}
stream->write_function(stream, "%s", reply);
switch_safe_free(data);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(user_exists_function)
{
return _find_user(cmd, session, stream, SWITCH_TRUE);
}
SWITCH_STANDARD_API(find_user_function)
{
return _find_user(cmd, session, stream, SWITCH_FALSE);
}
SWITCH_STANDARD_API(xml_locate_function)
{
switch_xml_t xml = NULL, obj = NULL;
int argc;
char *mydata = NULL, *argv[4];
char *section, *tag, *tag_attr_name, *tag_attr_val;
switch_event_t *params = NULL;
char *xmlstr;
char *path_info, delim = ' ';
char *host = NULL;
const char *err = NULL;
if (stream->param_event && (host = switch_event_get_header(stream->param_event, "http-host"))) {
stream->write_function(stream, "Content-Type: text/xml\r\n\r\n");
if ((path_info = switch_event_get_header(stream->param_event, "http-path-info"))) {
cmd = path_info;
delim = '/';
}
}
if (!cmd) {
err = "bad args";
goto end;
}
mydata = strdup(cmd);
switch_assert(mydata);
argc = switch_separate_string(mydata, delim, argv, (sizeof(argv) / sizeof(argv[0])));
if (argc == 1 && !strcasecmp(argv[0], "root")) {
const char *error;
xml = switch_xml_open_root(0, &error);
obj = xml;
goto end;
}
if (argc != 1 && argc != 4) {
err = "bad args";
goto end;
}
section = argv[0];
tag = argv[1];
tag_attr_name = argv[2];
tag_attr_val = argv[3];
switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(params);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "section", section);
if (tag) {
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "tag", tag);
}
if (tag_attr_name) {
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "tag_attr_name", tag_attr_name);
}
if (tag_attr_val) {
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "tag_attr_val", tag_attr_val);
}
if (switch_xml_locate(section, tag, tag_attr_name, tag_attr_val, &xml, &obj, params, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "can't find anything\n");
goto end;
}
end:
if (err) {
if (host) {
stream->write_function(stream, "<error>%s</error>\n", err);
} else {
stream->write_function(stream, "-Error %s\n", err);
}
}
if (obj) {
xmlstr = switch_xml_toxml(obj, SWITCH_FALSE);
switch_assert(xmlstr);
stream->write_function(stream, "%s", xmlstr);
free(xmlstr);
}
switch_xml_free(xml);
switch_event_destroy(&params);
free(mydata);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(reload_acl_function)
{
const char *err;
switch_xml_t xml_root;
if (cmd && !strcmp(cmd, "reloadxml")) {
if ((xml_root = switch_xml_open_root(1, &err))) {
switch_xml_free(xml_root);
}
}
switch_load_network_lists(SWITCH_TRUE);
stream->write_function(stream, "+OK acl reloaded\n");
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(acl_function)
{
int argc;
char *mydata = NULL, *argv[3];
if (!cmd) {
goto error;
}
mydata = strdup(cmd);
switch_assert(mydata);
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2) {
goto error;
}
if (switch_check_network_list_ip(argv[0], argv[1])) {
stream->write_function(stream, "true");
goto ok;
}
error:
stream->write_function(stream, "false");
ok:
switch_safe_free(mydata);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(regex_function)
{
switch_regex_t *re = NULL;
int ovector[30];
int argc;
char *mydata = NULL, *argv[3];
size_t len = 0;
char *substituted = NULL;
int proceed = 0;
char *d;
char delim = '|';
if (!cmd) {
goto error;
}
mydata = strdup(cmd);
switch_assert(mydata);
d = mydata;
if (*d == 'm' && *(d + 1) == ':' && *(d + 2)) {
char t = *(d + 2);
switch (t) {
case '|':
case '~':
case '/':
d += 3;
delim = t;
break;
default:
break;
}
}
argc = switch_separate_string(d, delim, argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2) {
goto error;
}
if ((proceed = switch_regex_perform(argv[0], argv[1], &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (argc > 2) {
len = (strlen(argv[0]) + strlen(argv[2]) + 10) * proceed;
substituted = malloc(len);
switch_assert(substituted);
memset(substituted, 0, len);
switch_replace_char(argv[2], '%', '$', SWITCH_FALSE);
switch_perform_substitution(re, proceed, argv[2], argv[0], substituted, len, ovector);
stream->write_function(stream, "%s", substituted);
free(substituted);
} else {
stream->write_function(stream, "true");
}
} else {
if (argc > 2) {
stream->write_function(stream, "%s", argv[0]);
} else {
stream->write_function(stream, "false");
}
}
goto ok;
error:
stream->write_function(stream, "-ERR");
ok:
switch_regex_safe_free(re);
switch_safe_free(mydata);
return SWITCH_STATUS_SUCCESS;
}
typedef enum {
O_NONE,
O_EQ,
O_NE,
O_GT,
O_GE,
O_LT,
O_LE
} o_t;
SWITCH_STANDARD_API(cond_function)
{
int argc;
char *mydata = NULL, *argv[3];
char *expr;
char *a, *b;
double a_f = 0.0, b_f = 0.0;
o_t o = O_NONE;
int is_true = 0;
char *p;
if (!cmd) {
goto error;
}
mydata = strdup(cmd);
switch_assert(mydata);
if ((p = strchr(mydata, '?'))) {
*p = ':';
} else {
goto error;
}
argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc != 3) {
goto error;
}
a = argv[0];
if ((expr = strchr(a, '!'))) {
*expr++ = '\0';
if (*expr == '=') {
o = O_NE;
}
} else if ((expr = strchr(a, '>'))) {
if (*(expr + 1) == '=') {
*expr++ = '\0';
o = O_GE;
} else {
o = O_GT;
}
} else if ((expr = strchr(a, '<'))) {
if (*(expr + 1) == '=') {
*expr++ = '\0';
o = O_LE;
} else {
o = O_LT;
}
} else if ((expr = strchr(a, '='))) {
*expr++ = '\0';
if (*expr == '=') {
o = O_EQ;
}
}
if (o) {
char *s_a = NULL, *s_b = NULL;
int a_is_num, b_is_num;
*expr++ = '\0';
b = expr;
s_a = switch_strip_spaces(a);
s_b = switch_strip_spaces(b);
a_is_num = switch_is_number(s_a);
b_is_num = switch_is_number(s_b);
a_f = a_is_num ? atof(s_a) : (float) strlen(s_a);
b_f = b_is_num ? atof(s_b) : (float) strlen(s_b);
switch (o) {
case O_EQ:
if (!a_is_num && !b_is_num) {
is_true = !strcmp(s_a, s_b);
} else {
is_true = a_f == b_f;
}
break;
case O_NE:
if (!a_is_num && !b_is_num) {
is_true = strcmp(s_a, s_b);
} else {
is_true = a_f != b_f;
}
break;
case O_GT:
is_true = a_f > b_f;
break;
case O_GE:
is_true = a_f >= b_f;
break;
case O_LT:
is_true = a_f < b_f;
break;
case O_LE:
is_true = a_f <= b_f;
break;
default:
break;
}
switch_safe_free(s_a);
switch_safe_free(s_b);
stream->write_function(stream, "%s", is_true ? argv[1] : argv[2]);
goto ok;
}
error:
stream->write_function(stream, "-ERR");
ok:
switch_safe_free(mydata);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(lan_addr_function)
{
stream->write_function(stream, "%s", switch_is_lan_addr(cmd) ? "true" : "false");
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(status_function)
{
uint8_t html = 0;
switch_core_time_duration_t duration = { 0 };
char *http = NULL;
int sps = 0, last_sps = 0;
const char *var;
switch_core_measure_time(switch_core_uptime(), &duration);
if (stream->param_event) {
http = switch_event_get_header(stream->param_event, "http-host");
if ((var = switch_event_get_header(stream->param_event, "content-type"))) {
if (!strcasecmp(var, "text/plain")) {
http = NULL;
}
}
}
if (http) {
stream->write_function(stream, "%s", "Content-Type: text/html\n\n");
}
if (http || (cmd && strstr(cmd, "html"))) {
html = 1;
stream->write_function(stream, "<h1>FreeSWITCH Status</h1>\n<b>");
}
stream->write_function(stream,
"UP %u year%s, %u day%s, %u hour%s, %u minute%s, %u second%s, %u millisecond%s, %u microsecond%s\n",
duration.yr, duration.yr == 1 ? "" : "s", duration.day, duration.day == 1 ? "" : "s",
duration.hr, duration.hr == 1 ? "" : "s", duration.min, duration.min == 1 ? "" : "s",
duration.sec, duration.sec == 1 ? "" : "s", duration.ms, duration.ms == 1 ? "" : "s", duration.mms,
duration.mms == 1 ? "" : "s");
stream->write_function(stream, "%" SWITCH_SIZE_T_FMT " session(s) since startup\n", switch_core_session_id() - 1);
switch_core_session_ctl(SCSC_LAST_SPS, &last_sps);
switch_core_session_ctl(SCSC_SPS, &sps);
stream->write_function(stream, "%d session(s) %d/%d\n", switch_core_session_count(), last_sps, sps);
stream->write_function(stream, "%d session(s) max\n", switch_core_session_limit(0));
if (html) {
stream->write_function(stream, "</b>\n");
}
if (cmd && strstr(cmd, "refresh=")) {
char *refresh = strchr(cmd, '=');
if (refresh) {
int r;
refresh++;
r = atoi(refresh);
if (r > 0) {
stream->write_function(stream, "<META HTTP-EQUIV=REFRESH CONTENT=\"%d; URL=/api/status?refresh=%d%s\">\n", r, r, html ? "html=1" : "");
}
}
}
return SWITCH_STATUS_SUCCESS;
}
#define CTL_SYNTAX "[send_sighup|hupall|pause|resume|shutdown [cancel|elegant|asap|restart]|sps|sync_clock|reclaim_mem|max_sessions|min_dtmf_duration [num]|max_dtmf_duration [num]|default_dtmf_duration [num]|loglevel [level]]"
SWITCH_STANDARD_API(ctl_function)
{
int argc;
char *mydata, *argv[5];
int32_t arg = 0;
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", CTL_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if ((mydata = strdup(cmd))) {
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (!strcasecmp(argv[0], "hupall")) {
arg = 1;
switch_core_session_ctl(SCSC_HUPALL, &arg);
stream->write_function(stream, "+OK\n");
} else if (!strcasecmp(argv[0], "pause")) {
arg = 1;
switch_core_session_ctl(SCSC_PAUSE_INBOUND, &arg);
stream->write_function(stream, "+OK\n");
} else if (!strcasecmp(argv[0], "send_sighup")) {
arg = 1;
switch_core_session_ctl(SCSC_SEND_SIGHUP, &arg);
stream->write_function(stream, "+OK\n");
} else if (!strcasecmp(argv[0], "resume")) {
arg = 0;
switch_core_session_ctl(SCSC_PAUSE_INBOUND, &arg);
stream->write_function(stream, "+OK\n");
} else if (!strcasecmp(argv[0], "shutdown")) {
switch_session_ctl_t command = SCSC_SHUTDOWN;
int x = 0;
arg = 0;
for (x = 1; x < 5; x++) {
if (argv[x]) {
if (!strcasecmp(argv[x], "cancel")) {
arg = 0;
command = SCSC_CANCEL_SHUTDOWN;
break;
} else if (!strcasecmp(argv[x], "elegant")) {
command = SCSC_SHUTDOWN_ELEGANT;
} else if (!strcasecmp(argv[x], "asap")) {
command = SCSC_SHUTDOWN_ASAP;
} else if (!strcasecmp(argv[x], "restart")) {
arg = 1;
}
} else {
break;
}
}
switch_core_session_ctl(command, &arg);
stream->write_function(stream, "+OK\n");
} else if (!strcasecmp(argv[0], "reclaim_mem")) {
switch_core_session_ctl(SCSC_RECLAIM, &arg);
stream->write_function(stream, "+OK\n");
} else if (!strcasecmp(argv[0], "max_sessions")) {
if (argc > 1) {
arg = atoi(argv[1]);
}
switch_core_session_ctl(SCSC_MAX_SESSIONS, &arg);
stream->write_function(stream, "+OK max sessions: %d\n", arg);
} else if (!strcasecmp(argv[0], "max_dtmf_duration")) {
if (argc > 1) {
arg = atoi(argv[1]);
}
switch_core_session_ctl(SCSC_MAX_DTMF_DURATION, &arg);
stream->write_function(stream, "+OK max dtmf duration: %d\n", arg);
} else if (!strcasecmp(argv[0], "min_dtmf_duration")) {
if (argc > 1) {
arg = atoi(argv[1]);
}
switch_core_session_ctl(SCSC_MIN_DTMF_DURATION, &arg);
stream->write_function(stream, "+OK min dtmf duration: %d\n", arg);
} else if (!strcasecmp(argv[0], "default_dtmf_duration")) {
if (argc > 1) {
arg = atoi(argv[1]);
}
switch_core_session_ctl(SCSC_DEFAULT_DTMF_DURATION, &arg);
stream->write_function(stream, "+OK default dtmf duration: %d\n", arg);
} else if (!strcasecmp(argv[0], "loglevel")) {
if (argc > 1) {
if (*argv[1] > 47 && *argv[1] < 58) {
arg = atoi(argv[1]);
} else {
arg = switch_log_str2level(argv[1]);
}
} else {
arg = -1;
}
if (arg == SWITCH_LOG_INVALID) {
stream->write_function(stream, "-ERR syntax error, log level not set!\n");
} else {
switch_core_session_ctl(SCSC_LOGLEVEL, &arg);
stream->write_function(stream, "+OK log level: %s [%d]\n", switch_log_level2str(arg), arg);
}
} else if (!strcasecmp(argv[0], "last_sps")) {
switch_core_session_ctl(SCSC_LAST_SPS, &arg);
stream->write_function(stream, "+OK last sessions per second: %d\n", arg);
} else if (!strcasecmp(argv[0], "sps")) {
if (argc > 1) {
arg = atoi(argv[1]);
} else {
arg = 0;
}
switch_core_session_ctl(SCSC_SPS, &arg);
stream->write_function(stream, "+OK sessions per second: %d\n", arg);
} else if (!strcasecmp(argv[0], "sync_clock")) {
arg = 0;
switch_core_session_ctl(SCSC_SYNC_CLOCK, &arg);
stream->write_function(stream, "+OK clock synchronized\n");
} else {
stream->write_function(stream, "-ERR INVALID COMMAND\nUSAGE: fsctl %s", CTL_SYNTAX);
goto end;
}
end:
free(mydata);
} else {
stream->write_function(stream, "-ERR Memory Error\n");
}
return SWITCH_STATUS_SUCCESS;
}
#define LOAD_SYNTAX "<mod_name>"
SWITCH_STANDARD_API(load_function)
{
const char *err;
Modify XML Dialplan BTW, forget what I said yesterday RE: the strftime app I was at McDonalds, how can I concentrate there eh? see below.... The Definitive Guide To XML Dialplan: The "dialplan" section of the freeswitch.xml meta document may contain several contexts <?xml version="1.0"?> <document type="freeswitch/xml"> <section name="dialplan" description="Regex/XML Dialplan"> <!-- the default context is a safe start --> <context name="default"> <!-- one or more extension tags --> </context> <!-- more optional contexts --> </section> </document> The important thing to remember is that the dialplan is parsed once when the call hits the dialplan parser in the RING state. With one pass across the XML the result will be a complete list of instructions installed into the channel based on parsed <action> or <anti-action> tags. Those accustomed to Asterisk may expect the call to follow the dialplan by executing the applications as it parses them allowing data obtained from one action to influence the next action. This not the case with the exception being the %{api func} {api arg} field type where an pluggable api call from a module may be executed as the parsing occurs but this is meant to be used to draw realtime info such as date and time or other quickly accessible information and shold *not* be abused. The anatomy of an <extension> tag. Legend: Text wrapped in [] indicates optional and is not part of the actual code. a '|' inside [] indicates mutiple possible values and also is not part of the code. Text wrapped in {} indicates it's a description of the parameter in place of the param itself. <extension name="{exten_name}" [continue="[true|false]"]> continue=true means even if an extension executes to continue parsing the next extension too The {exten_name} above may anything but if it's an exact match with the destination number the parser will leap to this extension to begin the searching that does not mean it will execute the extension. Searching will either begin at the first extension in the context or at the point the the parser has jumped to in the case described above. Each condition is parsed in turn first taking the 'field' param. The parser will apply the perl regular expression to each 'field' param encountered. If the expression matches, it will parse each existing <action> tag in turn and add the data from the <application> tags to the channels todo list. If a matched expression contains any data wrapped in () the variables $1,$2..$N will be valid and expanded in any of 'data' params from the subsequent action tags. If the expression does NOT match, it will parse each <anti-action> tag in turn and add the data from the <application> tags to the channels todo list. *NOTE* since there was no match the () feature is not availabe in anti-actions The 'break' param indicates how to behave in relation to matching: *) 'on-true' - stop searching conditions after the first successful match. *) 'on-false' - stop searching after the first unsuccessful match. *) 'always' - stop at this conditon regardless of a match or non-match. *) 'never' - continue searching regardless of a match or non-match. <condition field="[{field name}|${variable name}|%{api func} {api arg}]" expression="{expression}" break="[on-true|on-false|always|never]"> <action application="{app name}" data="{app arg}"/> <anti-action application="{app name}" data="{app arg}"/> </condition> <!-- any number of condition tags may follow where the same rules apply --> </extension> git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2167 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-07-26 20:12:49 +00:00
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", LOAD_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR [%s]\n", err);
}
return SWITCH_STATUS_SUCCESS;
}
#define UNLOAD_SYNTAX "[-f] <mod_name>"
SWITCH_STANDARD_API(unload_function)
{
const char *err;
switch_bool_t force = SWITCH_FALSE;
const char *p = cmd;
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", UNLOAD_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if (*p == '-') {
p++;
while(p && *p) {
switch (*p) {
case ' ':
cmd = p+1;
goto end;
case 'f':
force = SWITCH_TRUE;
break;
default:
break;
}
p++;
}
}
end:
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", UNLOAD_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, force, &err) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR [%s]\n", err);
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(reload_function)
{
const char *err;
switch_bool_t force = SWITCH_FALSE;
const char *p = cmd;
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", UNLOAD_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if (*p == '-') {
p++;
while(p && *p) {
switch (*p) {
case ' ':
cmd = p+1;
goto end;
case 'f':
force = SWITCH_TRUE;
break;
default:
break;
}
p++;
}
}
end:
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", UNLOAD_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if (switch_loadable_module_unload_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, force, &err) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK module unloaded\n");
} else {
stream->write_function(stream, "-ERR unloading module [%s]\n", err);
return SWITCH_STATUS_SUCCESS;
}
if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK module loaded\n");
} else {
stream->write_function(stream, "-ERR loading module [%s]\n", err);
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(reload_xml_function)
{
const char *err;
switch_xml_t xml_root;
if ((xml_root = switch_xml_open_root(1, &err))) {
switch_xml_free(xml_root);
}
stream->write_function(stream, "+OK [%s]\n", err);
return SWITCH_STATUS_SUCCESS;
}
#define KILL_SYNTAX "<uuid> [cause]"
SWITCH_STANDARD_API(kill_function)
{
switch_core_session_t *ksession = NULL;
char *mycmd = NULL, *kcause = NULL;
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
if (zstr(cmd) || !(mycmd = strdup(cmd))) {
stream->write_function(stream, "-USAGE: %s\n", KILL_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if ((kcause = strchr(mycmd, ' '))) {
*kcause++ = '\0';
}
if (zstr(mycmd) || !(ksession = switch_core_session_locate(mycmd))) {
stream->write_function(stream, "-ERR No Such Channel!\n");
} else {
switch_channel_t *channel = switch_core_session_get_channel(ksession);
if (!zstr(kcause)){
cause = switch_channel_str2cause(kcause);
}
switch_channel_hangup(channel, cause);
switch_core_session_rwunlock(ksession);
stream->write_function(stream, "+OK\n");
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define PREPROCESS_SYNTAX "<>"
SWITCH_STANDARD_API(preprocess_function)
{
switch_core_session_t *ksession = NULL;
char *mycmd = NULL, *argv[3] = { 0 };
int argc = 0;
if (zstr(cmd) || !(mycmd = strdup(cmd))) {
goto usage;
}
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2) {
goto usage;
}
if (!(ksession = switch_core_session_locate(argv[0]))) {
stream->write_function(stream, "-ERR No Such Channel!\n");
goto done;
} else {
switch_ivr_preprocess_session(ksession, (char *)argv[1]);
switch_core_session_rwunlock(ksession);
stream->write_function(stream, "+OK\n");
goto done;
}
usage:
stream->write_function(stream, "-USAGE: %s\n", PREPROCESS_SYNTAX);
done:
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define PARK_SYNTAX "<uuid>"
SWITCH_STANDARD_API(park_function)
{
switch_core_session_t *ksession = NULL;
if (!cmd) {
stream->write_function(stream, "-USAGE: %s\n", PARK_SYNTAX);
} else if ((ksession = switch_core_session_locate(cmd))) {
switch_ivr_park_session(ksession);
switch_core_session_rwunlock(ksession);
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR No Such Channel!\n");
}
return SWITCH_STATUS_SUCCESS;
}
#define TRANSFER_SYNTAX "<uuid> [-bleg|-both] <dest-exten> [<dialplan>] [<context>]"
SWITCH_STANDARD_API(transfer_function)
{
switch_core_session_t *tsession = NULL, *other_session = NULL;
char *mycmd = NULL, *argv[5] = { 0 };
int argc = 0;
char *tuuid, *dest, *dp, *context, *arg = NULL;
Modify XML Dialplan BTW, forget what I said yesterday RE: the strftime app I was at McDonalds, how can I concentrate there eh? see below.... The Definitive Guide To XML Dialplan: The "dialplan" section of the freeswitch.xml meta document may contain several contexts <?xml version="1.0"?> <document type="freeswitch/xml"> <section name="dialplan" description="Regex/XML Dialplan"> <!-- the default context is a safe start --> <context name="default"> <!-- one or more extension tags --> </context> <!-- more optional contexts --> </section> </document> The important thing to remember is that the dialplan is parsed once when the call hits the dialplan parser in the RING state. With one pass across the XML the result will be a complete list of instructions installed into the channel based on parsed <action> or <anti-action> tags. Those accustomed to Asterisk may expect the call to follow the dialplan by executing the applications as it parses them allowing data obtained from one action to influence the next action. This not the case with the exception being the %{api func} {api arg} field type where an pluggable api call from a module may be executed as the parsing occurs but this is meant to be used to draw realtime info such as date and time or other quickly accessible information and shold *not* be abused. The anatomy of an <extension> tag. Legend: Text wrapped in [] indicates optional and is not part of the actual code. a '|' inside [] indicates mutiple possible values and also is not part of the code. Text wrapped in {} indicates it's a description of the parameter in place of the param itself. <extension name="{exten_name}" [continue="[true|false]"]> continue=true means even if an extension executes to continue parsing the next extension too The {exten_name} above may anything but if it's an exact match with the destination number the parser will leap to this extension to begin the searching that does not mean it will execute the extension. Searching will either begin at the first extension in the context or at the point the the parser has jumped to in the case described above. Each condition is parsed in turn first taking the 'field' param. The parser will apply the perl regular expression to each 'field' param encountered. If the expression matches, it will parse each existing <action> tag in turn and add the data from the <application> tags to the channels todo list. If a matched expression contains any data wrapped in () the variables $1,$2..$N will be valid and expanded in any of 'data' params from the subsequent action tags. If the expression does NOT match, it will parse each <anti-action> tag in turn and add the data from the <application> tags to the channels todo list. *NOTE* since there was no match the () feature is not availabe in anti-actions The 'break' param indicates how to behave in relation to matching: *) 'on-true' - stop searching conditions after the first successful match. *) 'on-false' - stop searching after the first unsuccessful match. *) 'always' - stop at this conditon regardless of a match or non-match. *) 'never' - continue searching regardless of a match or non-match. <condition field="[{field name}|${variable name}|%{api func} {api arg}]" expression="{expression}" break="[on-true|on-false|always|never]"> <action application="{app name}" data="{app arg}"/> <anti-action application="{app name}" data="{app arg}"/> </condition> <!-- any number of condition tags may follow where the same rules apply --> </extension> git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2167 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-07-26 20:12:49 +00:00
if (zstr(cmd) || !(mycmd = strdup(cmd))) {
stream->write_function(stream, "-USAGE: %s\n", TRANSFER_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2 || argc > 5) {
stream->write_function(stream, "-USAGE: %s\n", TRANSFER_SYNTAX);
goto done;
}
tuuid = argv[0];
dest = argv[1];
dp = argv[2];
context = argv[3];
if (zstr(tuuid) || !(tsession = switch_core_session_locate(tuuid))) {
stream->write_function(stream, "-ERR No Such Channel!\n");
goto done;
}
if (*dest == '-') {
arg = dest;
dest = argv[2];
dp = argv[3];
context = argv[4];
}
if (arg) {
switch_channel_t *channel = switch_core_session_get_channel(tsession);
const char *uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE);
arg++;
if (!strcasecmp(arg, "bleg")) {
if (uuid && (other_session = switch_core_session_locate(uuid))) {
switch_core_session_t *tmp = tsession;
tsession = other_session;
other_session = NULL;
switch_core_session_rwunlock(tmp);
}
} else if (!strcasecmp(arg, "both")) {
if (uuid && (other_session = switch_core_session_locate(uuid))) {
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
switch_channel_set_flag(other_channel, CF_REDIRECT);
switch_channel_set_flag(channel, CF_REDIRECT);
switch_ivr_session_transfer(other_session, dest, dp, context);
switch_core_session_rwunlock(other_session);
}
}
}
if (switch_ivr_session_transfer(tsession, dest, dp, context) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR\n");
}
switch_core_session_rwunlock(tsession);
done:
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define TONE_DETECT_SYNTAX "<uuid> <key> <tone_spec> [<flags> <timeout> <app> <args> <hits>]"
SWITCH_STANDARD_API(tone_detect_session_function)
{
char *argv[8] = { 0 };
int argc;
char *mydata = NULL;
time_t to = 0;
switch_core_session_t *rsession;
int hits = 1;
if (!cmd) {
stream->write_function(stream, "-USAGE: %s\n", TONE_DETECT_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
mydata = strdup(cmd);
switch_assert(mydata != NULL);
if ((argc = switch_separate_string(mydata, ' ', argv, sizeof(argv) / sizeof(argv[0]))) < 3 || !argv[0]) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "-ERR INVALID ARGS!\n");
return SWITCH_STATUS_SUCCESS;
}
if (!(rsession = switch_core_session_locate(argv[0]))) {
stream->write_function(stream, "-ERR Error Cannot locate session!\n");
return SWITCH_STATUS_SUCCESS;
}
if (argv[4]) {
uint32_t mto;
if (*argv[4] == '+') {
if ((mto = atoi(argv[4] + 1)) > 0) {
to = switch_epoch_time_now(NULL) + mto;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "INVALID Timeout!\n");
goto done;
}
} else {
if ((to = atoi(argv[4])) < switch_epoch_time_now(NULL)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "INVALID Timeout!\n");
to = 0;
goto done;
}
}
}
if (argv[7]) {
hits = atoi(argv[7]);
if (hits < 0) {
hits = 1;
}
}
switch_ivr_tone_detect_session(rsession, argv[1], argv[2], argv[3], to, hits, argv[5], argv[6], NULL);
stream->write_function(stream, "+OK Enabling tone detection '%s' '%s' '%s'\n", argv[1], argv[2], argv[3]);
done:
free(mydata);
switch_core_session_rwunlock(rsession);
return SWITCH_STATUS_SUCCESS;
}
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
SWITCH_STANDARD_API(uuid_function)
{
switch_uuid_t uuid;
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
switch_uuid_get(&uuid);
switch_uuid_format(uuid_str, &uuid);
stream->write_function(stream, "%s", uuid_str);
return SWITCH_STATUS_SUCCESS;
}
#define UUID_CHAT_SYNTAX "<uuid> <text>"
SWITCH_STANDARD_API(uuid_chat)
{
switch_core_session_t *tsession = NULL;
char *uuid = NULL, *text = NULL;
if (!zstr(cmd) && (uuid = strdup(cmd))) {
if ((text = strchr(uuid, ' '))) {
*text++ = '\0';
}
}
if (zstr(uuid) || zstr(text)) {
stream->write_function(stream, "-USAGE: %s\n", UUID_CHAT_SYNTAX);
} else {
if ((tsession = switch_core_session_locate(uuid))) {
switch_event_t *event;
if (switch_event_create(&event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
switch_event_add_body(event, "%s", text);
if (switch_core_session_receive_event(tsession, &event) != SWITCH_STATUS_SUCCESS) {
switch_event_destroy(&event);
stream->write_function(stream, "-ERR Send Failed\n");
} else {
stream->write_function(stream, "+OK\n");
}
}
switch_core_session_rwunlock(tsession);
} else {
stream->write_function(stream, "-ERR No Such Channel %s!\n", uuid);
}
}
switch_safe_free(uuid);
return SWITCH_STATUS_SUCCESS;
}
#define UUID_DEFLECT_SYNTAX "<uuid> <uri>"
SWITCH_STANDARD_API(uuid_deflect)
{
switch_core_session_t *tsession = NULL;
char *uuid = NULL, *text = NULL;
if (!zstr(cmd) && (uuid = strdup(cmd))) {
if ((text = strchr(uuid, ' '))) {
*text++ = '\0';
}
}
if (zstr(uuid) || zstr(text)) {
stream->write_function(stream, "-USAGE: %s\n", UUID_DEFLECT_SYNTAX);
} else {
if ((tsession = switch_core_session_locate(uuid))) {
switch_core_session_message_t msg = { 0 };
/* Tell the channel to deflect the call */
msg.from = __FILE__;
msg.string_arg = text;
msg.message_id = SWITCH_MESSAGE_INDICATE_DEFLECT;
switch_core_session_receive_message(tsession, &msg);
stream->write_function(stream, "+OK:%s\n", msg.string_reply);
switch_core_session_rwunlock(tsession);
} else {
stream->write_function(stream, "-ERR No Such Channel %s!\n", uuid);
}
}
switch_safe_free(uuid);
return SWITCH_STATUS_SUCCESS;
}
#define SCHED_TRANSFER_SYNTAX "[+]<time> <uuid> <extension> [<dialplan>] [<context>]"
SWITCH_STANDARD_API(sched_transfer_function)
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
{
switch_core_session_t *tsession = NULL;
char *mycmd = NULL, *argv[6] = { 0 };
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
int argc = 0;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
if (zstr(cmd) || argc < 2 || argc > 5 || zstr(argv[0])) {
stream->write_function(stream, "-USAGE: %s\n", SCHED_TRANSFER_SYNTAX);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
} else {
char *uuid = argv[1];
char *dest = argv[2];
char *dp = argv[3];
char *context = argv[4];
time_t when;
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
if (*argv[0] == '+') {
when = switch_epoch_time_now(NULL) + atol(argv[0] + 1);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
} else {
when = atol(argv[0]);
}
if ((tsession = switch_core_session_locate(uuid))) {
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
switch_ivr_schedule_transfer(when, uuid, dest, dp, context);
stream->write_function(stream, "+OK\n");
switch_core_session_rwunlock(tsession);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
} else {
stream->write_function(stream, "-ERR No Such Channel!\n");
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
}
}
switch_safe_free(mycmd);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
return SWITCH_STATUS_SUCCESS;
}
#define SCHED_HANGUP_SYNTAX "[+]<time> <uuid> [<cause>]"
SWITCH_STANDARD_API(sched_hangup_function)
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
{
switch_core_session_t *hsession = NULL;
char *mycmd = NULL, *argv[4] = { 0 };
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
int argc = 0;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
if (zstr(cmd) || argc < 1 || zstr(argv[0])) {
stream->write_function(stream, "-USAGE: %s\n", SCHED_HANGUP_SYNTAX);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
} else {
char *uuid = argv[1];
char *cause_str = argv[2];
time_t when;
switch_call_cause_t cause = SWITCH_CAUSE_ALLOTTED_TIMEOUT;
if (*argv[0] == '+') {
when = switch_epoch_time_now(NULL) + atol(argv[0] + 1);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
} else {
when = atol(argv[0]);
}
if (cause_str) {
cause = switch_channel_str2cause(cause_str);
}
if ((hsession = switch_core_session_locate(uuid))) {
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
switch_ivr_schedule_hangup(when, uuid, cause, SWITCH_FALSE);
stream->write_function(stream, "+OK\n");
switch_core_session_rwunlock(hsession);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
} else {
stream->write_function(stream, "-ERR No Such Channel!\n");
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
}
}
switch_safe_free(mycmd);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
return SWITCH_STATUS_SUCCESS;
}
#define MEDIA_SYNTAX "[off] <uuid>"
SWITCH_STANDARD_API(uuid_media_function)
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
{
char *mycmd = NULL, *argv[4] = { 0 };
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
if (zstr(cmd) || argc < 1 || zstr(argv[0])) {
stream->write_function(stream, "-USAGE: %s\n", MEDIA_SYNTAX);
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
} else {
if (!strcasecmp(argv[0], "off")) {
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
status = switch_ivr_nomedia(argv[1], SMF_REBRIDGE);
} else {
status = switch_ivr_media(argv[0], SMF_REBRIDGE);
}
}
if (status == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK Success\n");
} else {
stream->write_function(stream, "-ERR Operation Failed\n");
}
switch_safe_free(mycmd);
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
return SWITCH_STATUS_SUCCESS;
}
#define BROADCAST_SYNTAX "<uuid> <path> [aleg|bleg|both]"
SWITCH_STANDARD_API(uuid_broadcast_function)
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
{
char *mycmd = NULL, *argv[4] = { 0 };
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
if (zstr(cmd) || argc < 2) {
stream->write_function(stream, "-USAGE: %s\n", BROADCAST_SYNTAX);
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
} else {
switch_media_flag_t flags = SMF_NONE;
if (argv[2]) {
if (!strcasecmp(argv[2], "both")) {
flags |= (SMF_ECHO_ALEG | SMF_ECHO_BLEG);
} else if (!strcasecmp(argv[2], "aleg")) {
flags |= SMF_ECHO_ALEG;
} else if (!strcasecmp(argv[2], "bleg")) {
flags |= SMF_ECHO_BLEG;
}
} else {
flags |= SMF_ECHO_ALEG;
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
}
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
status = switch_ivr_broadcast(argv[0], argv[1], flags);
stream->write_function(stream, "+OK Message Sent\n");
}
switch_safe_free(mycmd);
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
return SWITCH_STATUS_SUCCESS;
}
#define SCHED_BROADCAST_SYNTAX "[+]<time> <uuid> <path> [aleg|bleg|both]"
SWITCH_STANDARD_API(sched_broadcast_function)
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
{
char *mycmd = NULL, *argv[4] = { 0 };
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
if (zstr(cmd) || argc < 3 || zstr(argv[0])) {
stream->write_function(stream, "-USAGE: %s\n", SCHED_BROADCAST_SYNTAX);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
} else {
switch_media_flag_t flags = SMF_NONE;
time_t when;
if (*argv[0] == '+') {
when = switch_epoch_time_now(NULL) + atol(argv[0] + 1);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
} else {
when = atol(argv[0]);
}
if (argv[3]) {
if (!strcasecmp(argv[3], "both")) {
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
flags |= (SMF_ECHO_ALEG | SMF_ECHO_BLEG);
} else if (!strcasecmp(argv[3], "aleg")) {
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
flags |= SMF_ECHO_ALEG;
} else if (!strcasecmp(argv[3], "bleg")) {
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
flags |= SMF_ECHO_BLEG;
}
} else {
flags |= SMF_ECHO_ALEG;
}
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
status = switch_ivr_schedule_broadcast(when, argv[1], argv[2], flags);
stream->write_function(stream, "+OK Message Scheduled\n");
}
switch_safe_free(mycmd);
Addition of scheduler engine and a few applications to use it. This patch adds a scheduler thread to the core and moves the heartbeat event to use the new scheduler as an example. Also The following features are implemented that use this scheduler: sched_hangup dialplan application: <action application="sched_hangup" data="+10 normal_clearing bleg"/> ** The cause code is optional and the optional bleg keyword will only hangup the channel the current channel is bridged to if the call is in a bridge. sched_transfer dialplan application: <action application="sched_transfer" data="+10 1000 XML default"/> ** The last 2 args (dialplan and context) are optional sched_broadcast dialplan application: <action application="sched_broadcast" data="+10 playback:/tmp/foo.wav"/> <action application="sched_broadcast" data="+10 playback!normal_clearing:/tmp/foo.wav"/> ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. sched_hangup api function: sched_hangup +10 <uuid_string> normal_clearing ** The cause code is optional sched_transfer api function: sched_transfer +10 <uuid_string> 1000 XML default ** The last 2 args (dialplan and context) are optional sched_broadcast api function: sched_broadcast +10 <uuid_str> playback:/tmp/foo.wav sched_broadcast +10 <uuid_str> playback!normal_clearing:/tmp/foo.wav ** The optional !<cause_code> can be added to make the channel hangup after broadcasting the file. The new C functions in the core are documented in the doxeygen. *NOTE* This commit should satisfy at least 2 bounties on the wiki git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4785 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-03-28 23:37:12 +00:00
return SWITCH_STATUS_SUCCESS;
}
#define HOLD_SYNTAX "[off] <uuid> [<display>]"
SWITCH_STANDARD_API(uuid_hold_function)
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
{
char *mycmd = NULL, *argv[4] = { 0 };
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
if (zstr(cmd) || argc < 1 || zstr(argv[0])) {
stream->write_function(stream, "-USAGE: %s\n", HOLD_SYNTAX);
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
} else {
if (!strcasecmp(argv[0], "off")) {
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
status = switch_ivr_unhold_uuid(argv[1]);
} else {
status = switch_ivr_hold_uuid(argv[0], argv[1], 1);
}
}
if (status == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK Success\n");
} else {
stream->write_function(stream, "-ERR Operation Failed\n");
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define DISPLAY_SYNTAX "<uuid> <display>"
SWITCH_STANDARD_API(uuid_display_function)
{
char *mycmd = NULL, *argv[2] = { 0 };
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (zstr(cmd) || argc < 2 || zstr(argv[0]) || zstr(argv[1])) {
stream->write_function(stream, "-USAGE: %s\n", DISPLAY_SYNTAX);
} else {
switch_core_session_message_t msg = { 0 };
switch_core_session_t *lsession = NULL;
msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
msg.string_arg = argv[1];
msg.from = __FILE__;
if ((lsession = switch_core_session_locate(argv[0]))) {
status = switch_core_session_receive_message(lsession, &msg);
switch_core_session_rwunlock(lsession);
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
}
}
if (status == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK Success\n");
} else {
stream->write_function(stream, "-ERR Operation Failed\n");
}
switch_safe_free(mycmd);
Media Management (Sponsored By Front Logic) This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan. It adds some API interface calls usable from a remote client such as mod_event_socket or the test console. 1) media [off] <uuid> Turns on/off the media on the call described by <uuid> The media will be redirected as desiered either into the switch or point to point. 2) hold [off] <uuid> Turns on/off endpoint specific hold state on the session described by <uuid> 3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both] A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated. If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified will hear the message. During playback when only one side is hearing the message the other end will hear silence. If media is not flowing across the switch when the message is broadcasted, the media will be directed to the switch for the duration of the call and then returned to it's previous state. Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media on the switch. <action application="set" data="no_media=true"/> <action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/> *NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled, the media for the first leg will be engaged with the switch until the second leg has answered and the other session description is available to establish a point to point connection at which time point-to-point mode will be enabled. *NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-10-31 21:38:06 +00:00
return SWITCH_STATUS_SUCCESS;
}
#define WARNING_SYNTAX "<uuid> <warning>"
SWITCH_STANDARD_API(uuid_warning_function)
{
char *mycmd = NULL, *argv[2] = { 0 };
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (zstr(cmd) || argc < 2 || zstr(argv[0]) || zstr(argv[1])) {
stream->write_function(stream, "-USAGE: %s\n", WARNING_SYNTAX);
} else {
switch_core_session_message_t msg = { 0 };
switch_core_session_t *lsession = NULL;
msg.message_id = SWITCH_MESSAGE_INDICATE_WARNING;
msg.string_arg = argv[1];
msg.from = __FILE__;
if ((lsession = switch_core_session_locate(argv[0]))) {
status = switch_core_session_receive_message(lsession, &msg);
switch_core_session_rwunlock(lsession);
}
}
if (status == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK Success\n");
} else {
stream->write_function(stream, "-ERR Operation Failed\n");
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define DEBUG_AUDIO_SYNTAX "<uuid> <read|write|both> <on|off>"
SWITCH_STANDARD_API(uuid_debug_audio_function)
{
char *mycmd = NULL, *argv[3] = { 0 };
int argc = 0;
switch_status_t status = SWITCH_STATUS_FALSE;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (zstr(cmd) || argc < 3 || zstr(argv[0]) || zstr(argv[1]) || zstr(argv[2])) {
stream->write_function(stream, "-USAGE: %s\n", DEBUG_AUDIO_SYNTAX);
} else {
switch_core_session_message_t msg = { 0 };
switch_core_session_t *lsession = NULL;
msg.message_id = SWITCH_MESSAGE_INDICATE_DEBUG_AUDIO;
msg.string_array_arg[0] = argv[1];
msg.string_array_arg[1] = argv[2];
msg.from = __FILE__;
if ((lsession = switch_core_session_locate(argv[0]))) {
status = switch_core_session_receive_message(lsession, &msg);
switch_core_session_rwunlock(lsession);
}
}
if (status == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK Success\n");
} else {
stream->write_function(stream, "-ERR Operation Failed\n");
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define UUID_SYNTAX "<uuid> <other_uuid>"
SWITCH_STANDARD_API(uuid_bridge_function)
{
char *mycmd = NULL, *argv[4] = { 0 };
int argc = 0;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (zstr(cmd) || argc < 2) {
stream->write_function(stream, "-USAGE: %s\n", UUID_SYNTAX);
} else {
switch_status_t status;
char *who = NULL;
if ((status = switch_ivr_uuid_bridge(argv[0], argv[1])) != SWITCH_STATUS_SUCCESS) {
if (argv[2]) {
if ((status = switch_ivr_uuid_bridge(argv[0], argv[2])) == SWITCH_STATUS_SUCCESS) {
who = argv[2];
}
}
} else {
who = argv[1];
}
if (status == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK %s\n", who);
} else {
stream->write_function(stream, "-ERR Invalid uuid\n");
}
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define SESS_REC_SYNTAX "<uuid> [start|stop] <path> [<limit>]"
SWITCH_STANDARD_API(session_record_function)
{
switch_core_session_t *rsession = NULL;
char *mycmd = NULL, *argv[4] = { 0 };
char *uuid = NULL, *action = NULL, *path = NULL;
int argc = 0;
uint32_t limit = 0;
if (zstr(cmd)) {
goto usage;
}
if (!(mycmd = strdup(cmd))) {
goto usage;
}
if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 3) {
goto usage;
}
uuid = argv[0];
action = argv[1];
path = argv[2];
limit = argv[3] ? atoi(argv[3]) : 0;
if (zstr(uuid) || zstr(action) || zstr(path)) {
goto usage;
}
if (!(rsession = switch_core_session_locate(uuid))) {
stream->write_function(stream, "-ERR Cannot locate session!\n");
return SWITCH_STATUS_SUCCESS;
}
if (!strcasecmp(action, "start")) {
if (switch_ivr_record_session(rsession, path, limit, NULL)!= SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "-ERR Cannot record session!\n");
} else {
stream->write_function(stream, "+OK Success\n");
}
} else if (!strcasecmp(action, "stop")) {
if (switch_ivr_stop_record_session(rsession, path) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "-ERR Cannot stop record session!\n");
} else {
stream->write_function(stream, "+OK Success\n");
}
} else {
goto usage;
}
goto done;
usage:
stream->write_function(stream, "-USAGE: %s\n", SESS_REC_SYNTAX);
done:
if (rsession) {
switch_core_session_rwunlock(rsession);
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define DISPLACE_SYNTAX "<uuid> [start|stop] <path> [<limit>] [mux]"
SWITCH_STANDARD_API(session_displace_function)
{
switch_core_session_t *rsession = NULL;
char *mycmd = NULL, *argv[5] = { 0 };
char *uuid = NULL, *action = NULL, *path = NULL;
int argc = 0;
uint32_t limit = 0;
char *flags = NULL;
if (zstr(cmd) || !(mycmd = strdup(cmd))) {
goto usage;
}
if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 3) {
goto usage;
}
uuid = argv[0];
action = argv[1];
path = argv[2];
limit = argv[3] ? atoi(argv[3]) : 0;
flags = argv[4];
if (zstr(uuid) || zstr(action) || zstr(path)) {
goto usage;
}
if (!(rsession = switch_core_session_locate(uuid))) {
stream->write_function(stream, "-ERR Cannot locate session!\n");
return SWITCH_STATUS_SUCCESS;
}
if (!strcasecmp(action, "start")) {
if (switch_ivr_displace_session(rsession, path, limit, flags) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "-ERR Cannot displace session!\n");
} else {
stream->write_function(stream, "+OK Success\n");
}
} else if (!strcasecmp(action, "stop")) {
if (switch_ivr_stop_displace_session(rsession, path) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "-ERR Cannot stop displace session!\n");
} else {
stream->write_function(stream, "+OK Success\n");
}
} else {
goto usage;
}
goto done;
usage:
stream->write_function(stream, "-USAGE: %s\n", DISPLACE_SYNTAX);
done:
if (rsession) {
switch_core_session_rwunlock(rsession);
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define BREAK_SYNTAX "<uuid> [all]"
SWITCH_STANDARD_API(break_function)
{
switch_core_session_t *psession = NULL;
char *mycmd = NULL, *flag;
switch_channel_t *channel = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", BREAK_SYNTAX);
goto done;
}
mycmd = strdup(cmd);
switch_assert(mycmd);
if ((flag = strchr(mycmd, ' '))) {
*flag++ = '\0';
}
if (!(psession = switch_core_session_locate(mycmd))) {
stream->write_function(stream, "-ERR No Such Channel!\n");
goto done;
}
if (flag && !strcasecmp(flag, "all")) {
switch_core_session_flush_private_events(psession);
}
channel = switch_core_session_get_channel(psession);
if (switch_channel_test_flag(channel, CF_BROADCAST)) {
switch_channel_stop_broadcast(channel);
} else {
switch_channel_set_flag(channel, CF_BREAK);
}
done:
if (psession) {
switch_core_session_rwunlock(psession);
}
switch_safe_free(mycmd);
return status;
}
#define PAUSE_SYNTAX "<uuid> <on|off>"
SWITCH_STANDARD_API(pause_function)
{
switch_core_session_t *psession = NULL;
char *mycmd = NULL, *argv[4] = { 0 };
int argc = 0;
Modify XML Dialplan BTW, forget what I said yesterday RE: the strftime app I was at McDonalds, how can I concentrate there eh? see below.... The Definitive Guide To XML Dialplan: The "dialplan" section of the freeswitch.xml meta document may contain several contexts <?xml version="1.0"?> <document type="freeswitch/xml"> <section name="dialplan" description="Regex/XML Dialplan"> <!-- the default context is a safe start --> <context name="default"> <!-- one or more extension tags --> </context> <!-- more optional contexts --> </section> </document> The important thing to remember is that the dialplan is parsed once when the call hits the dialplan parser in the RING state. With one pass across the XML the result will be a complete list of instructions installed into the channel based on parsed <action> or <anti-action> tags. Those accustomed to Asterisk may expect the call to follow the dialplan by executing the applications as it parses them allowing data obtained from one action to influence the next action. This not the case with the exception being the %{api func} {api arg} field type where an pluggable api call from a module may be executed as the parsing occurs but this is meant to be used to draw realtime info such as date and time or other quickly accessible information and shold *not* be abused. The anatomy of an <extension> tag. Legend: Text wrapped in [] indicates optional and is not part of the actual code. a '|' inside [] indicates mutiple possible values and also is not part of the code. Text wrapped in {} indicates it's a description of the parameter in place of the param itself. <extension name="{exten_name}" [continue="[true|false]"]> continue=true means even if an extension executes to continue parsing the next extension too The {exten_name} above may anything but if it's an exact match with the destination number the parser will leap to this extension to begin the searching that does not mean it will execute the extension. Searching will either begin at the first extension in the context or at the point the the parser has jumped to in the case described above. Each condition is parsed in turn first taking the 'field' param. The parser will apply the perl regular expression to each 'field' param encountered. If the expression matches, it will parse each existing <action> tag in turn and add the data from the <application> tags to the channels todo list. If a matched expression contains any data wrapped in () the variables $1,$2..$N will be valid and expanded in any of 'data' params from the subsequent action tags. If the expression does NOT match, it will parse each <anti-action> tag in turn and add the data from the <application> tags to the channels todo list. *NOTE* since there was no match the () feature is not availabe in anti-actions The 'break' param indicates how to behave in relation to matching: *) 'on-true' - stop searching conditions after the first successful match. *) 'on-false' - stop searching after the first unsuccessful match. *) 'always' - stop at this conditon regardless of a match or non-match. *) 'never' - continue searching regardless of a match or non-match. <condition field="[{field name}|${variable name}|%{api func} {api arg}]" expression="{expression}" break="[on-true|on-false|always|never]"> <action application="{app name}" data="{app arg}"/> <anti-action application="{app name}" data="{app arg}"/> </condition> <!-- any number of condition tags may follow where the same rules apply --> </extension> git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2167 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-07-26 20:12:49 +00:00
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (zstr(cmd) || argc < 2 || zstr(argv[0])) {
stream->write_function(stream, "-USAGE: %s\n", PAUSE_SYNTAX);
} else {
char *uuid = argv[0];
char *dest = argv[1];
if ((psession = switch_core_session_locate(uuid))) {
switch_channel_t *channel = switch_core_session_get_channel(psession);
if (!strcasecmp(dest, "on")) {
switch_channel_set_flag(channel, CF_HOLD);
} else {
switch_channel_clear_flag(channel, CF_HOLD);
}
switch_core_session_rwunlock(psession);
} else {
stream->write_function(stream, "-ERR No Such Channel!\n");
}
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define ORIGINATE_SYNTAX "<call url> <exten>|&<application_name>(<app_args>) [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>]"
SWITCH_STANDARD_API(originate_function)
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
{
switch_channel_t *caller_channel;
switch_core_session_t *caller_session = NULL;
char *mycmd = NULL, *argv[10] = { 0 };
int i = 0, x, argc = 0;
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
char *aleg, *exten, *dp, *context, *cid_name, *cid_num;
uint32_t timeout = 60;
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
uint8_t machine = 1;
switch_status_t status = SWITCH_STATUS_SUCCESS;
if (session || zstr(cmd)) {
stream->write_function(stream, "-USAGE %s\n", ORIGINATE_SYNTAX);
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
return SWITCH_STATUS_SUCCESS;
}
mycmd = strdup(cmd);
switch_assert(mycmd);
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2 || argc > 7) {
stream->write_function(stream, "-USAGE: %s\n", ORIGINATE_SYNTAX);
goto done;
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
}
for (x = 0; x < argc && argv[x]; x++) {
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
if (!strcasecmp(argv[x], "undef")) {
argv[x] = NULL;
}
}
if (argv[0] && !strcasecmp(argv[0], "machine")) {
machine = 1;
i++;
}
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
aleg = argv[i++];
exten = argv[i++];
dp = argv[i++];
context = argv[i++];
cid_name = argv[i++];
cid_num = argv[i++];
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
if (!dp) {
dp = "XML";
}
if (!context) {
context = "default";
}
if (argv[6]) {
timeout = atoi(argv[6]);
}
if (switch_ivr_originate(NULL, &caller_session, &cause, aleg, timeout, NULL, cid_name, cid_num, NULL, NULL, SOF_NONE, NULL) != SWITCH_STATUS_SUCCESS
|| !caller_session) {
if (machine) {
stream->write_function(stream, "-ERR %s\n", switch_channel_cause2str(cause));
} else {
stream->write_function(stream, "-ERR Cannot Create Outgoing Channel! [%s] cause: %s\n", aleg, switch_channel_cause2str(cause));
}
goto done;
}
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
caller_channel = switch_core_session_get_channel(caller_session);
switch_channel_clear_state_handler(caller_channel, NULL);
if (*exten == '&' && *(exten + 1)) {
switch_caller_extension_t *extension = NULL;
char *app_name = switch_core_session_strdup(caller_session, (exten + 1));
char *arg = NULL, *e;
if ((e = strchr(app_name, ')'))) {
*e = '\0';
}
if ((arg = strchr(app_name, '('))) {
*arg++ = '\0';
}
if ((extension = switch_caller_extension_new(caller_session, app_name, arg)) == 0) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n");
abort();
}
switch_caller_extension_add_application(caller_session, extension, app_name, arg);
switch_channel_set_caller_extension(caller_channel, extension);
switch_channel_set_state(caller_channel, CS_EXECUTE);
} else {
switch_ivr_session_transfer(caller_session, exten, dp, context);
}
if (machine) {
stream->write_function(stream, "+OK %s\n", switch_core_session_get_uuid(caller_session));
} else {
stream->write_function(stream, "+OK Created Session: %s\n", switch_core_session_get_uuid(caller_session));
}
switch_core_session_rwunlock(caller_session);
done:
switch_safe_free(mycmd);
return status;
*deep breath* Ok, This one adds a bunch of stuff on top of the framework restructuring from yesterday. 1) originate api function: Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] This will call the specified url then transfer the call to the specified extension example: originate exosip/1000@somehost 1000 XML default 2) mutiple destinations in outbound calls: This means any dialstring may contain an '&' separated list of call urls When using mutiple urls in this manner it is possible to map a certian key as required indication of an accepted call. You may also supply a filename to play possibly instructing the call recipiant to press the desired key etc... The example below will call 2 locations playing prompt.wav to any who answer and completing the call to the first offhook recipiant to dial "4" <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="set" data="call_timeout=60"/> <action application="set" data="group_confirm_file=/path/to/prompt.wav"/> <action application="set" data="group_confirm_key=4"/> <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> The following is the equivilant but the confirm data is passed vial the bridge parameters (This is for situations where there is no originating channel to set variables to) <extension name="3002"> <condition field="destination_number" expression="^3002$"> <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/> </condition> </extension> Omitting the file and key stuff will simply comeplete the call to whoever answers first. (this is similar to how other less fortunate software handles the situation with thier best effort.) This logic should be permitted in anything that establishes an outgoing call with switch_ivr_originate() Yes! That means even in this new originate api command you can call mutiple targets and send whoever answers first to an extension that calls more mutiple targets. (better test it though!) Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features please report any behaviour contrary to this account to me ASAP cos i would not be terribly suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2311 d0543943-73ff-0310-b7d9-9358b9ac24b2
2006-08-17 00:53:09 +00:00
}
SWITCH_STANDARD_API(sched_del_function)
{
uint32_t cnt = 0;
if (!cmd) {
stream->write_function(stream, "-ERR Invalid syntax\n");
return SWITCH_STATUS_SUCCESS;
}
if (switch_is_digit_string(cmd)) {
int64_t tmp;
tmp = (uint32_t) atoi(cmd);
if (tmp > 0) {
cnt = switch_scheduler_del_task_id((uint32_t) tmp);
}
} else {
cnt = switch_scheduler_del_task_group(cmd);
}
stream->write_function(stream, "+OK Deleted: %u\n", cnt);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(xml_wrap_api_function)
{
char *dcommand, *edata = NULL, *send = NULL, *command, *arg = NULL;
switch_stream_handle_t mystream = { 0 };
int encoded = 0, elen = 0;
if (!cmd) {
stream->write_function(stream, "-ERR Invalid syntax\n");
return SWITCH_STATUS_SUCCESS;
}
if ((dcommand = strdup(cmd))) {
if (!strncasecmp(dcommand, "encoded ", 8)) {
encoded++;
command = dcommand + 8;
} else {
command = dcommand;
}
if ((arg = strchr(command, ' '))) {
*arg++ = '\0';
}
SWITCH_STANDARD_STREAM(mystream);
switch_api_execute(command, arg, NULL, &mystream);
if (mystream.data) {
if (encoded) {
elen = (int) strlen(mystream.data) * 3;
edata = malloc(elen);
switch_assert(edata != NULL);
memset(edata, 0, elen);
switch_url_encode(mystream.data, edata, elen);
send = edata;
} else {
send = mystream.data;
}
}
stream->write_function(stream, "<result>\n" " <row id=\"1\">\n" " <data>%s</data>\n" " </row>\n" "</result>\n", send ? send : "ERROR");
switch_safe_free(mystream.data);
switch_safe_free(edata);
free(dcommand);
}
return SWITCH_STATUS_SUCCESS;
}
struct api_task {
uint32_t recur;
char cmd[];
};
static void sch_api_callback(switch_scheduler_task_t *task)
{
char *cmd, *arg = NULL;
switch_stream_handle_t stream = { 0 };
struct api_task *api_task = (struct api_task *) task->cmd_arg;
switch_assert(task);
cmd = strdup(api_task->cmd);
switch_assert(cmd);
if ((arg = strchr(cmd, ' '))) {
*arg++ = '\0';
}
SWITCH_STANDARD_STREAM(stream);
switch_api_execute(cmd, arg, NULL, &stream);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Command %s(%s):\n%s\n", cmd, switch_str_nil(arg), switch_str_nil((char *) stream.data));
switch_safe_free(stream.data);
switch_safe_free(cmd);
if (api_task->recur) {
task->runtime = switch_epoch_time_now(NULL) + api_task->recur;
}
}
#define UNSCHED_SYNTAX "<task_id>"
SWITCH_STANDARD_API(unsched_api_function)
{
uint32_t id;
if (!cmd) {
stream->write_function(stream, "-ERR Invalid syntax. USAGE: %s\n", UNSCHED_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if ((id = (uint32_t) atol(cmd))) {
stream->write_function(stream, "%s\n", switch_scheduler_del_task_id(id) ? "+OK" : "-ERR no such id");
}
return SWITCH_STATUS_SUCCESS;
}
#define SCHED_SYNTAX "[+@]<time> <group_name> <command_string>[&]"
SWITCH_STANDARD_API(sched_api_function)
{
char *tm = NULL, *dcmd, *group;
time_t when;
struct api_task *api_task = NULL;
uint32_t recur = 0;
int flags = SSHF_FREE_ARG;
if (!cmd) {
goto bad;
}
tm = strdup(cmd);
switch_assert(tm != NULL);
if ((group = strchr(tm, ' '))) {
uint32_t id;
*group++ = '\0';
if ((dcmd = strchr(group, ' '))) {
*dcmd++ = '\0';
if (*tm == '+') {
when = switch_epoch_time_now(NULL) + atol(tm + 1);
} else if (*tm == '@') {
recur = (uint32_t) atol(tm + 1);
when = switch_epoch_time_now(NULL) + recur;
} else {
when = atol(tm);
}
switch_zmalloc(api_task, sizeof(*api_task) + strlen(dcmd) + 1);
switch_copy_string(api_task->cmd, dcmd, strlen(dcmd) + 1);
api_task->recur = recur;
if (end_of(api_task->cmd) == '&') {
end_of(api_task->cmd) = '\0';
flags |= SSHF_OWN_THREAD;
}
id = switch_scheduler_add_task(when, sch_api_callback, (char *) __SWITCH_FUNC__, group, 0, api_task, flags);
stream->write_function(stream, "+OK Added: %u\n", id);
goto good;
}
}
bad:
stream->write_function(stream, "-ERR Invalid syntax. USAGE: %s\n", SCHED_SYNTAX);
good:
switch_safe_free(tm);
return SWITCH_STATUS_SUCCESS;
}
static switch_thread_rwlock_t *bgapi_rwlock = NULL;
struct bg_job {
char *cmd;
char *arg;
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
switch_memory_pool_t *pool;
};
static void *SWITCH_THREAD_FUNC bgapi_exec(switch_thread_t *thread, void *obj)
{
struct bg_job *job = (struct bg_job *) obj;
switch_stream_handle_t stream = { 0 };
switch_status_t status;
char *reply, *freply = NULL;
switch_event_t *event;
char *arg;
switch_memory_pool_t *pool;
if (!job) {
return NULL;
}
switch_thread_rwlock_rdlock(bgapi_rwlock);
pool = job->pool;
SWITCH_STANDARD_STREAM(stream);
if ((arg = strchr(job->cmd, ' '))) {
*arg++ = '\0';
}
if ((status = switch_api_execute(job->cmd, arg, NULL, &stream)) == SWITCH_STATUS_SUCCESS) {
reply = stream.data;
} else {
freply = switch_mprintf("%s: Command not found!\n", job->cmd);
reply = freply;
}
if (!reply) {
reply = "Command returned no output!";
}
if (switch_event_create(&event, SWITCH_EVENT_BACKGROUND_JOB) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-UUID", job->uuid_str);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command", job->cmd);
if (arg) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command-Arg", arg);
}
switch_event_add_body(event, "%s", reply);
switch_event_fire(&event);
}
switch_safe_free(stream.data);
switch_safe_free(freply);
job = NULL;
switch_core_destroy_memory_pool(&pool);
pool = NULL;
switch_thread_rwlock_unlock(bgapi_rwlock);
return NULL;
}
SWITCH_STANDARD_API(bgapi_function)
{
struct bg_job *job;
switch_uuid_t uuid;
switch_memory_pool_t *pool;
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
if (!cmd) {
stream->write_function(stream, "-ERR Invalid syntax\n");
return SWITCH_STATUS_SUCCESS;
}
switch_core_new_memory_pool(&pool);
job = switch_core_alloc(pool, sizeof(*job));
job->cmd = switch_core_strdup(pool, cmd);
job->pool = pool;
switch_uuid_get(&uuid);
switch_uuid_format(job->uuid_str, &uuid);
switch_threadattr_create(&thd_attr, job->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
stream->write_function(stream, "+OK Job-UUID: %s\n", job->uuid_str);
switch_thread_create(&thread, thd_attr, bgapi_exec, job, job->pool);
return SWITCH_STATUS_SUCCESS;
}
struct holder {
switch_stream_handle_t *stream;
char *http;
char *delim;
uint32_t count;
int print_title;
switch_xml_t xml;
int rows;
int justcount;
};
static int show_as_xml_callback(void *pArg, int argc, char **argv, char **columnNames)
{
struct holder *holder = (struct holder *) pArg;
switch_xml_t row, field;
int x, f_off = 0;
char id[50];
if (holder->count == 0) {
if (!(holder->xml = switch_xml_new("result"))) {
return -1;
}
}
if (holder->justcount) {
holder->count++;
return 0;
}
if (!(row = switch_xml_add_child_d(holder->xml, "row", holder->rows++))) {
return -1;
}
switch_snprintf(id, sizeof(id), "%d", holder->rows);
switch_xml_set_attr(switch_xml_set_flag(row, SWITCH_XML_DUP), strdup("row_id"), strdup(id));
for (x = 0; x < argc; x++) {
char *name = columnNames[x];
char *val = switch_str_nil(argv[x]);
if (!name) {
name = "undefined";
}
if ((field = switch_xml_add_child_d(row, name, f_off++))) {
switch_xml_set_txt_d(field, val);
} else {
return -1;
}
}
holder->count++;
return 0;
}
static int show_callback(void *pArg, int argc, char **argv, char **columnNames)
{
struct holder *holder = (struct holder *) pArg;
int x;
if (holder->justcount) {
holder->count++;
return 0;
}
if (holder->print_title && holder->count == 0) {
if (holder->http) {
holder->stream->write_function(holder->stream, "\n<tr>");
}
for (x = 0; x < argc; x++) {
char *name = columnNames[x];
if (!name) {
name = "undefined";
}
if (holder->http) {
holder->stream->write_function(holder->stream, "<td>");
holder->stream->write_function(holder->stream, "<b>%s</b>%s", name, x == (argc - 1) ? "</td></tr>\n" : "</td><td>");
} else {
holder->stream->write_function(holder->stream, "%s%s", name, x == (argc - 1) ? "\n" : holder->delim);
}
}
}
if (holder->http) {
holder->stream->write_function(holder->stream, "<tr bgcolor=%s>", holder->count % 2 == 0 ? "eeeeee" : "ffffff");
}
for (x = 0; x < argc; x++) {
char *val = switch_str_nil(argv[x]);
if (holder->http) {
char aval[512];
switch_amp_encode(val, aval, sizeof(aval));
holder->stream->write_function(holder->stream, "<td>");
holder->stream->write_function(holder->stream, "%s%s", aval, x == (argc - 1) ? "</td></tr>\n" : "</td><td>");
} else {
holder->stream->write_function(holder->stream, "%s%s", val, x == (argc - 1) ? "\n" : holder->delim);
}
}
holder->count++;
return 0;
}
#define COMPLETE_SYNTAX "add <word>|del [<word>|*]"
SWITCH_STANDARD_API(complete_function)
{
switch_status_t status;
if ((status = switch_console_set_complete(cmd)) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-USAGE: %s\n", COMPLETE_SYNTAX);
}
return SWITCH_STATUS_SUCCESS;
}
#define ALIAS_SYNTAX "add <alias> <command> | del [<alias>|*]"
SWITCH_STANDARD_API(alias_function)
{
switch_status_t status;
if ((status = switch_console_set_alias(cmd)) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-USAGE: %s\n", ALIAS_SYNTAX);
}
return SWITCH_STATUS_SUCCESS;
}
#define SHOW_SYNTAX "codec|endpoint|application|api|dialplan|file|timer|calls [count]|channels [count]|distinct_channels|aliases|complete|chat|endpoint|management|modules|nat_map|say|interfaces|interface_types"
SWITCH_STANDARD_API(show_function)
{
char sql[1024];
char *errmsg;
switch_cache_db_handle_t *db;
struct holder holder = { 0 };
int help = 0;
char *mydata = NULL, *argv[6] = { 0 };
int argc;
char *command = NULL, *as = NULL;
switch_core_flag_t cflags = switch_core_flags();
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_core_db_handle(&db);
holder.justcount = 0;
if (cmd && (mydata = strdup(cmd))) {
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
command = argv[0];
if (argv[2] && !strcasecmp(argv[1], "as")) {
as = argv[2];
}
}
if (stream->param_event) {
const char *var;
holder.http = switch_event_get_header(stream->param_event, "http-host");
if ((var = switch_event_get_header(stream->param_event, "content-type"))) {
if (!strcasecmp(var, "text/plain")) {
holder.http = NULL;
}
} else if (holder.http) {
stream->write_function(stream, "%s", "Content-Type: text/html\n\n");
}
}
holder.print_title = 1;
if (!(cflags & SCF_USE_SQL) && command && !strcasecmp(command, "channels")) {
stream->write_function(stream, "-ERR SQL DISABLED NO CHANNEL DATA AVAILABLE!\n");
goto end;
}
/* If you change the field qty or order of any of these select */
/* statements, you must also change show_callback and friends to match! */
if (!command) {
stream->write_function(stream, "-USAGE: %s\n", SHOW_SYNTAX);
goto end;
} else if (!strncasecmp(command, "codec", 5) ||
!strncasecmp(command, "dialplan", 8) ||
!strncasecmp(command, "file", 4) ||
!strncasecmp(command, "timer", 5) ||
!strncasecmp(command, "chat", 4) ||
!strncasecmp(command, "say", 3) ||
!strncasecmp(command, "management", 10) ||
!strncasecmp(command, "endpoint", 8)) {
if (end_of(command) == 's') {
end_of(command) = '\0';
}
sprintf(sql, "select type, name, key from interfaces where type = '%s' order by type,name", command);
} else if (!strncasecmp(command, "module", 6)) {
if (argv[1]) {
sprintf(sql, "select distinct type, name, key, filename from interfaces where key = '%s' order by type,name", argv[1]);
} else {
sprintf(sql, "select distinct type, name, key, filename from interfaces order by type,name");
}
} else if (!strcasecmp(command, "interfaces")) {
sprintf(sql, "select type, name, key from interfaces order by type,name");
} else if (!strcasecmp(command, "interface_types")) {
sprintf(sql, "select type,count(type) as total from interfaces group by type order by type");
} else if (!strcasecmp(command, "tasks")) {
sprintf(sql, "select * from %s", command);
} else if (!strcasecmp(command, "application") || !strcasecmp(command, "api")) {
if (argv[1] && strcasecmp(argv[1], "as")) {
sprintf(sql, "select name, description, syntax, key from interfaces where type = '%s' and description != '' and name = '%s' order by type,name", command, argv[1]);
} else {
sprintf(sql, "select name, description, syntax, key from interfaces where type = '%s' and description != '' order by type,name", command);
}
} else if (!strcasecmp(command, "calls")) {
sprintf(sql, "select * from calls order by call_created_epoch");
if (argv[1] && !strcasecmp(argv[1],"count")) {
holder.justcount = 1;
if (argv[3] && !strcasecmp(argv[2], "as")) {
as = argv[3];
}
}
} else if (!strcasecmp(command, "channels") && argv[1] && !strcasecmp(argv[1], "like")) {
if (argv[2]) {
char *p;
for (p = argv[2]; p && *p; p++) {
if (*p == '\'' || *p == ';') {
*p = ' ';
}
}
if (strchr(argv[2], '%')) {
sprintf(sql, "select * from channels where uuid like '%s' or name like '%s' or cid_name like '%s' or cid_num like '%s' order by created_epoch",
argv[2], argv[2], argv[2], argv[2]);
} else {
sprintf(sql, "select * from channels where uuid like '%%%s%%' or name like '%%%s%%' or cid_name like '%%%s%%' or cid_num like '%%%s%%' order by created_epoch",
argv[2], argv[2], argv[2], argv[2]);
}
if (argv[4] && !strcasecmp(argv[3], "as")) {
as = argv[4];
}
} else {
sprintf(sql, "select * from channels order by created_epoch");
}
} else if (!strcasecmp(command, "channels")) {
sprintf(sql, "select * from channels order by created_epoch");
if (argv[1] && !strcasecmp(argv[1],"count")) {
holder.justcount = 1;
if (argv[3] && !strcasecmp(argv[2], "as")) {
as = argv[3];
}
}
} else if (!strcasecmp(command, "distinct_channels")) {
sprintf(sql, "select * from channels left join calls on "
"channels.uuid=calls.caller_uuid where channels.uuid not in (select callee_uuid from calls) order by created_epoch");
if (argv[2] && !strcasecmp(argv[1], "as")) {
as = argv[2];
}
} else if (!strcasecmp(command, "aliases")) {
sprintf(sql, "select * from aliases order by alias");
} else if (!strcasecmp(command, "complete")) {
sprintf(sql, "select * from complete order by a1,a2,a3,a4,a5,a6,a7,a8,a9,a10");
} else if (!strncasecmp(command, "help", 4)) {
char *cmdname = NULL;
help = 1;
holder.print_title = 0;
if ((cmdname = strchr(command, ' ')) && strcasecmp(cmdname, "as")) {
*cmdname++ = '\0';
switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description, key from interfaces where type = 'api' and name = '%s' order by name",
cmdname);
} else {
switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description, key from interfaces where type = 'api' order by name");
}
} else if (!strcasecmp(command, "nat_map")) {
switch_snprintf(sql, sizeof(sql) - 1,
"SELECT port, "
" CASE proto "
" WHEN 0 THEN 'udp' "
" WHEN 1 THEN 'tcp' "
" ELSE 'unknown' "
" END AS proto, "
" proto AS proto_num, "
" sticky "
" FROM nat ORDER BY port, proto"
);
} else {
stream->write_function(stream, "-USAGE: %s\n", SHOW_SYNTAX);
goto end;
}
holder.stream = stream;
holder.count = 0;
if (holder.http) {
holder.stream->write_function(holder.stream, "<table cellpadding=1 cellspacing=4 border=1>\n");
}
if (!as) {
as = "delim";
holder.delim = ",";
}
/* switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SQL: %s.\n", sql); */
if (!strcasecmp(as, "delim") || !strcasecmp(as, "csv")) {
if (zstr(holder.delim)) {
if (!(holder.delim = argv[3])) {
holder.delim = ",";
}
}
switch_cache_db_execute_sql_callback(db, sql, show_callback, &holder, &errmsg);
if (holder.http) {
holder.stream->write_function(holder.stream, "</table>");
}
if (errmsg) {
stream->write_function(stream, "-ERR SQL Error [%s]\n", errmsg);
switch_core_db_free(errmsg);
errmsg = NULL;
} else if (help) {
if (holder.count == 0)
stream->write_function(stream, "-ERR No such command.\n");
} else {
stream->write_function(stream, "\n%u total.\n", holder.count);
}
} else if (!strcasecmp(as, "xml")) {
switch_cache_db_execute_sql_callback(db, sql, show_as_xml_callback, &holder, &errmsg);
if (errmsg) {
stream->write_function(stream, "-ERR SQL Error [%s]\n", errmsg);
switch_core_db_free(errmsg);
errmsg = NULL;
}
if (holder.xml) {
char count[50];
char *xmlstr;
switch_snprintf(count, sizeof(count), "%d", holder.count);
switch_xml_set_attr(switch_xml_set_flag(holder.xml, SWITCH_XML_DUP), strdup("row_count"), strdup(count));
xmlstr = switch_xml_toxml(holder.xml, SWITCH_FALSE);
switch_xml_free(holder.xml);
if (xmlstr) {
holder.stream->write_function(holder.stream, "%s", xmlstr);
free(xmlstr);
} else {
holder.stream->write_function(holder.stream, "<result row_count=\"0\"/>\n");
}
} else {
holder.stream->write_function(holder.stream, "<result row_count=\"0\"/>\n");
}
} else {
holder.stream->write_function(holder.stream, "-ERR Cannot find format %s\n", as);
}
end:
switch_safe_free(mydata);
if (db) {
switch_cache_db_release_db_handle(&db);
}
return status;
}
SWITCH_STANDARD_API(version_function)
{
char version_string[1024];
switch_snprintf(version_string, sizeof(version_string) - 1, "FreeSWITCH Version %s\n", SWITCH_VERSION_FULL);
stream->write_function(stream, version_string);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(help_function)
{
char showcmd[1024];
int all = 0;
if (zstr(cmd)) {
sprintf(showcmd, "help");
all = 1;
} else {
switch_snprintf(showcmd, sizeof(showcmd) - 1, "help %s", cmd);
}
if (all) {
stream->write_function(stream, "\nValid Commands:\n\n");
}
show_function(showcmd, session, stream);
return SWITCH_STATUS_SUCCESS;
}
#define HEARTBEAT_SYNTAX "<uuid> [sched] [0|<seconds>]"
SWITCH_STANDARD_API(uuid_session_heartbeat_function)
{
char *mycmd = NULL, *argv[3] = { 0 };
uint32_t seconds = 60;
int argc, tmp;
switch_core_session_t *l_session = NULL;
int x = 0, sched = 0;
if (zstr(cmd) || !(mycmd = strdup(cmd))) {
goto error;
}
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2 || !argv[0]) {
goto error;
}
if (!(l_session = switch_core_session_locate(argv[0]))) {
stream->write_function(stream, "-ERR Usage: cannot locate session.\n");
return SWITCH_STATUS_SUCCESS;
}
if (!strcasecmp(argv[1], "sched")) {
x = 2;
sched++;
} else {
x = 1;
}
if (switch_is_number(argv[x])) {
tmp = atoi(argv[x]);
if (tmp > 0) {
seconds = tmp;
}
} else if (!switch_true(argv[x])) {
seconds = 0;
}
if (seconds) {
if (sched) {
switch_core_session_sched_heartbeat(l_session, seconds);
} else {
switch_core_session_enable_heartbeat(l_session, seconds);
}
} else {
switch_core_session_disable_heartbeat(l_session);
}
switch_core_session_rwunlock(l_session);
switch_safe_free(mycmd);
stream->write_function(stream, "+OK\n");
return SWITCH_STATUS_SUCCESS;
error:
switch_safe_free(mycmd);
stream->write_function(stream, "-ERR Usage: uuid_session_heartbeat %s", HEARTBEAT_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(uuid_flush_dtmf_function)
{
switch_core_session_t *fsession;
if (!zstr(cmd) && (fsession = switch_core_session_locate(cmd))) {
switch_channel_flush_dtmf(switch_core_session_get_channel(fsession));
switch_core_session_rwunlock(fsession);
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR no such session\n");
}
return SWITCH_STATUS_SUCCESS;
}
#define SETVAR_SYNTAX "<uuid> <var> [value]"
SWITCH_STANDARD_API(uuid_setvar_function)
{
switch_core_session_t *psession = NULL;
char *mycmd = NULL, *argv[3] = { 0 };
int argc = 0;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if ((argc == 2 || argc == 3) && !zstr(argv[0])) {
char *uuid = argv[0];
char *var_name = argv[1];
char *var_value = NULL;
if (argc == 3) {
var_value = argv[2];
}
if ((psession = switch_core_session_locate(uuid))) {
switch_channel_t *channel;
channel = switch_core_session_get_channel(psession);
if (zstr(var_name)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n");
stream->write_function(stream, "-ERR No variable specified\n");
} else {
switch_channel_set_variable(channel, var_name, var_value);
stream->write_function(stream, "+OK\n");
}
switch_core_session_rwunlock(psession);
} else {
stream->write_function(stream, "-ERR No Such Channel!\n");
}
goto done;
}
}
stream->write_function(stream, "-USAGE: %s\n", SETVAR_SYNTAX);
done:
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define SETVAR_MULTI_SYNTAX "<uuid> <var>=<value>;<var>=<value>..."
SWITCH_STANDARD_API(uuid_setvar_multi_function)
{
switch_core_session_t *psession = NULL;
char *mycmd = NULL, *vars, *argv[64] = { 0 };
int argc = 0;
char *var_name, *var_value = NULL;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
char *uuid = mycmd;
if (!(vars = strchr(uuid, ' '))) {
goto done;
}
*vars++ = '\0';
if ((psession = switch_core_session_locate(uuid))) {
switch_channel_t *channel = switch_core_session_get_channel(psession);
int x, y = 0;
argc = switch_separate_string(vars, ';', argv, (sizeof(argv) / sizeof(argv[0])));
for (x = 0 ; x < argc; x++) {
var_name = argv[x];
if (var_name && (var_value = strchr(var_name, '='))) {
*var_value++ = '\0';
}
if (zstr(var_name)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n");
stream->write_function(stream, "-ERR No variable specified\n");
} else {
switch_channel_set_variable(channel, var_name, var_value);
y++;
}
}
switch_core_session_rwunlock(psession);
if (y) {
stream->write_function(stream, "+OK\n");
goto done;
}
} else {
stream->write_function(stream, "-ERR No Such Channel!\n");
}
}
stream->write_function(stream, "-USAGE: %s\n", SETVAR_MULTI_SYNTAX);
done:
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define EXISTS_SYNTAX "<uuid>"
SWITCH_STANDARD_API(uuid_exists_function)
{
switch_bool_t exists = SWITCH_FALSE;
if (cmd) {
exists = switch_ivr_uuid_exists(cmd);
}
stream->write_function(stream, "%s", exists ? "true" : "false");
return SWITCH_STATUS_SUCCESS;
}
#define GETVAR_SYNTAX "<uuid> <var>"
SWITCH_STANDARD_API(uuid_getvar_function)
{
switch_core_session_t *psession = NULL;
char *mycmd = NULL, *argv[4] = { 0 };
int argc = 0;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc >= 2 && !zstr(argv[0])) {
char *uuid = argv[0];
char *var_name = argv[1];
const char *var_value = NULL;
if ((psession = switch_core_session_locate(uuid))) {
switch_channel_t *channel;
channel = switch_core_session_get_channel(psession);
if (zstr(var_name)) {
stream->write_function(stream, "-ERR No variable name specified!\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n");
} else {
var_value = switch_channel_get_variable(channel, var_name);
if (var_value != NULL) {
stream->write_function(stream, "%s", var_value);
} else {
stream->write_function(stream, "_undef_");
}
}
switch_core_session_rwunlock(psession);
} else {
stream->write_function(stream, "-ERR No Such Channel!\n");
}
goto done;
}
}
stream->write_function(stream, "-USAGE: %s\n", GETVAR_SYNTAX);
done:
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define UUID_SEND_DTMF_SYNTAX "<uuid> <dtmf_data>"
SWITCH_STANDARD_API(uuid_send_dtmf_function)
{
switch_core_session_t *psession = NULL;
char *mycmd = NULL, *argv[2] = { 0 };
char *uuid = NULL, *dtmf_data = NULL;
int argc = 0;
if (zstr(cmd)) {
goto usage;
}
if (!(mycmd = strdup(cmd))) {
goto usage;
}
if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 2) {
goto usage;
}
uuid = argv[0];
dtmf_data = argv[1];
if (zstr(uuid) || zstr(dtmf_data)) {
goto usage;
}
if (!(psession = switch_core_session_locate(uuid))) {
stream->write_function(stream, "-ERR Cannot locate session!\n");
return SWITCH_STATUS_SUCCESS;
}
switch_core_session_send_dtmf_string(psession, (const char *) dtmf_data);
goto done;
usage:
stream->write_function(stream, "-USAGE: %s\n", UUID_SEND_DTMF_SYNTAX);
done:
if (psession) {
switch_core_session_rwunlock(psession);
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define DUMP_SYNTAX "<uuid> [format]"
SWITCH_STANDARD_API(uuid_dump_function)
{
switch_core_session_t *psession = NULL;
char *mycmd = NULL, *argv[4] = { 0 };
int argc = 0;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc >= 0 && !zstr(argv[0])) {
char *uuid = argv[0];
char *format = argv[1];
if (!format) {
format = "txt";
}
if ((psession = switch_core_session_locate(uuid))) {
switch_channel_t *channel;
switch_event_t *event;
char *buf;
channel = switch_core_session_get_channel(psession);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
switch_xml_t xml;
switch_channel_event_set_data(channel, event);
if (!strcasecmp(format, "xml")) {
if ((xml = switch_event_xmlize(event, "%s", ""))) {
buf = switch_xml_toxml(xml, SWITCH_FALSE);
switch_xml_free(xml);
} else {
stream->write_function(stream, "-ERR Unable to create xml!\n");
switch_event_destroy(&event);
switch_core_session_rwunlock(psession);
goto done;
}
} else {
switch_event_serialize(event, &buf, strcasecmp(format, "plain"));
}
switch_assert(buf);
stream->raw_write_function(stream, (unsigned char *) buf, strlen(buf));
switch_event_destroy(&event);
free(buf);
} else {
stream->write_function(stream, "-ERR Allocation error\n");
}
switch_core_session_rwunlock(psession);
} else {
stream->write_function(stream, "-ERR No Such Channel!\n");
}
goto done;
}
}
stream->write_function(stream, "-USAGE: %s\n", DUMP_SYNTAX);
done:
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define GLOBAL_SETVAR_SYNTAX "<var> <value>"
SWITCH_STANDARD_API(global_setvar_function)
{
char *mycmd = NULL, *argv[2] = { 0 };
int argc = 0;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, '=', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc > 0 && !zstr(argv[0])) {
char *var_name = argv[0];
char *var_value = argv[1];
if (zstr(var_value)) {
var_value = NULL;
}
switch_core_set_variable(var_name, var_value);
stream->write_function(stream, "+OK");
goto done;
}
}
stream->write_function(stream, "-USAGE: %s\n", GLOBAL_SETVAR_SYNTAX);
done:
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define GLOBAL_GETVAR_SYNTAX "<var>"
SWITCH_STANDARD_API(global_getvar_function)
{
if (zstr(cmd)) {
switch_core_dump_variables(stream);
} else {
stream->write_function(stream, "%s", switch_str_nil(switch_core_get_variable(cmd)));
}
return SWITCH_STATUS_SUCCESS;
}
#define SYSTEM_SYNTAX "<command>"
SWITCH_STANDARD_API(system_function)
{
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", SYSTEM_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Executing command: %s\n", cmd);
if (switch_system(cmd, SWITCH_TRUE) < 0) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd);
}
stream->write_function(stream, "+OK\n");
return SWITCH_STATUS_SUCCESS;
}
#define SYSTEM_SYNTAX "<command>"
SWITCH_STANDARD_API(bg_system_function)
{
if (zstr(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", SYSTEM_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Executing command: %s\n", cmd);
if (switch_system(cmd, SWITCH_FALSE) < 0) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd);
}
stream->write_function(stream, "+OK\n");
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(strftime_tz_api_function)
{
char *format = NULL;
const char *tz_name = NULL;
char date[80] = "";
if (!zstr(cmd)) {
format = strchr(cmd, ' ');
tz_name = cmd;
if (format) {
*format++ = '\0';
}
}
if (switch_strftime_tz(tz_name, format, date, sizeof(date), 0) == SWITCH_STATUS_SUCCESS) { /* The lookup of the zone may fail. */
stream->write_function(stream, "%s", date);
} else {
stream->write_function(stream, "-ERR Invalid Timezone\n");
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_STANDARD_API(hupall_api_function)
{
char *mycmd = NULL, *argv[3] = { 0 };
int argc = 0;
char *var = NULL;
char *val = NULL;
switch_call_cause_t cause = SWITCH_CAUSE_MANAGER_REQUEST;
if (!zstr(cmd) && (mycmd = strdup(cmd))) {
argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
switch_assert(argv[0]);
if ((cause = switch_channel_str2cause(argv[0])) == SWITCH_CAUSE_NONE) {
cause = SWITCH_CAUSE_MANAGER_REQUEST;
}
var = argv[1];
val = argv[2];
}
if (!val) {
var = NULL;
}
if (zstr(var)) {
switch_core_session_hupall(cause);
} else {
switch_core_session_hupall_matching_var(var, val, cause);
}
if (zstr(var)) {
stream->write_function(stream, "+OK hangup all channels with cause %s\n", switch_channel_cause2str(cause));
} else {
stream->write_function(stream, "+OK hangup all channels matching [%s]=[%s] with cause: %s\n", var, val, switch_channel_cause2str(cause));
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_commands_shutdown)
{
int x;
for (x = 30; x > 0; x--) {
if (switch_thread_rwlock_trywrlock(bgapi_rwlock) == SWITCH_STATUS_SUCCESS) {
switch_thread_rwlock_unlock(bgapi_rwlock);
break;
}
if (x == 30) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for bgapi threads.\n");
}
switch_yield(1000000);
}
if (!x) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Giving up waiting for bgapi threads.\n");
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
{
switch_api_interface_t *commands_api_interface;
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
switch_thread_rwlock_create(&bgapi_rwlock, pool);
SWITCH_ADD_API(commands_api_interface, "group_call", "Generate a dial string to call a group", group_call_function, "<group>[@<domain>]");
SWITCH_ADD_API(commands_api_interface, "in_group", "determine if a user is in a group", in_group_function, "<user>[@<domain>] <group_name>");
SWITCH_ADD_API(commands_api_interface, "uuid_flush_dtmf", "Flush dtmf on a given uuid", uuid_flush_dtmf_function, "<uuid>");
SWITCH_ADD_API(commands_api_interface, "md5", "md5", md5_function, "<data>");
SWITCH_ADD_API(commands_api_interface, "hupall", "hupall", hupall_api_function, "<cause> [<var> <value>]");
SWITCH_ADD_API(commands_api_interface, "strftime_tz", "strftime_tz", strftime_tz_api_function, "<Timezone_name> [format string]");
SWITCH_ADD_API(commands_api_interface, "originate", "Originate a Call", originate_function, ORIGINATE_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "tone_detect", "Start Tone Detection on a channel", tone_detect_session_function, TONE_DETECT_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_kill", "Kill Channel", kill_function, KILL_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_preprocess", "Pre-process Channel", preprocess_function, PREPROCESS_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_park", "Park Channel", park_function, PARK_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "[reloadxml]");
switch_console_set_complete("add reloadacl reloadxml");
SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_xml_function, "");
SWITCH_ADD_API(commands_api_interface, "unload", "Unload Module", unload_function, UNLOAD_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "reload", "Reload Module", reload_function, UNLOAD_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "load", "Load Module", load_function, LOAD_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_transfer", "Transfer a session", transfer_function, TRANSFER_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "pause", "Pause", pause_function, PAUSE_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "break", "Break", break_function, BREAK_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "show", "Show", show_function, SHOW_SYNTAX);
switch_console_set_complete("add show channels");
switch_console_set_complete("add show codec");
switch_console_set_complete("add show application");
switch_console_set_complete("add show api");
switch_console_set_complete("add show dialplan");
switch_console_set_complete("add show file");
switch_console_set_complete("add show timer");
switch_console_set_complete("add show calls");
switch_console_set_complete("add show channels");
switch_console_set_complete("add show aliases");
switch_console_set_complete("add show complete");
switch_console_set_complete("add show distinct_channels");
switch_console_set_complete("add show chat");
switch_console_set_complete("add show endpoint");
switch_console_set_complete("add show management");
switch_console_set_complete("add show modules");
switch_console_set_complete("add show nat_map");
switch_console_set_complete("add nat_map status");
switch_console_set_complete("add nat_map republish");
switch_console_set_complete("add nat_map reinit");
switch_console_set_complete("add show say");
switch_console_set_complete("add show interfaces");
switch_console_set_complete("add show interface_types");
SWITCH_ADD_API(commands_api_interface, "complete", "Complete", complete_function, COMPLETE_SYNTAX);
switch_console_set_complete("add complete add");
switch_console_set_complete("add complete del");
SWITCH_ADD_API(commands_api_interface, "alias", "Alias", alias_function, ALIAS_SYNTAX);
switch_console_set_complete("add alias add");
switch_console_set_complete("add alias del");
SWITCH_ADD_API(commands_api_interface, "status", "status", status_function, "");
SWITCH_ADD_API(commands_api_interface, "uuid_session_heartbeat", "uuid_session_heartbeat", uuid_session_heartbeat_function, HEARTBEAT_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_bridge", "uuid_bridge", uuid_bridge_function, "");
SWITCH_ADD_API(commands_api_interface, "uuid_setvar", "uuid_setvar", uuid_setvar_function, SETVAR_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_setvar_multi", "uuid_setvar_multi", uuid_setvar_multi_function, SETVAR_MULTI_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_getvar", "uuid_getvar", uuid_getvar_function, GETVAR_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_exists", "see if a uuid exists", uuid_exists_function, EXISTS_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_dump", "uuid_dump", uuid_dump_function, DUMP_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "global_setvar", "global_setvar", global_setvar_function, GLOBAL_SETVAR_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "global_getvar", "global_getvar", global_getvar_function, GLOBAL_GETVAR_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_displace", "session displace", session_displace_function, "<uuid> [start|stop] <path> [<limit>] [mux]");
SWITCH_ADD_API(commands_api_interface, "uuid_record", "session record", session_record_function, SESS_REC_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_broadcast", "broadcast", uuid_broadcast_function, BROADCAST_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_hold", "hold", uuid_hold_function, HOLD_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_display", "change display", uuid_display_function, DISPLAY_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_warning", "send popup", uuid_warning_function, WARNING_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_debug_audio", "debug audio", uuid_debug_audio_function, DEBUG_AUDIO_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_media", "media", uuid_media_function, MEDIA_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "fsctl", "control messages", ctl_function, CTL_SYNTAX);
switch_console_set_complete("add fsctl hupall");
switch_console_set_complete("add fsctl pause");
switch_console_set_complete("add fsctl resume");
switch_console_set_complete("add fsctl shutdown");
switch_console_set_complete("add fsctl shutdown restart");
switch_console_set_complete("add fsctl shutdown elegant");
switch_console_set_complete("add fsctl shutdown asap");
switch_console_set_complete("add fsctl shutdown elegant restart");
switch_console_set_complete("add fsctl shutdown restart elegant");
switch_console_set_complete("add fsctl shutdown asap restart");
switch_console_set_complete("add fsctl shutdown restart asap");
switch_console_set_complete("add fsctl shutdown cancel");
switch_console_set_complete("add fsctl sps");
switch_console_set_complete("add fsctl sync_clock");
switch_console_set_complete("add fsctl reclaim_mem");
switch_console_set_complete("add fsctl max_sessions");
switch_console_set_complete("add fsctl max_dtmf_duration");
switch_console_set_complete("add fsctl min_dtmf_duration");
switch_console_set_complete("add fsctl default_dtmf_duration");
SWITCH_ADD_API(commands_api_interface, "help", "Show help for all the api commands", help_function, "");
SWITCH_ADD_API(commands_api_interface, "version", "Show version of the switch", version_function, "");
SWITCH_ADD_API(commands_api_interface, "sched_hangup", "Schedule a running call to hangup", sched_hangup_function, SCHED_HANGUP_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "sched_broadcast", "Schedule a broadcast event to a running call", sched_broadcast_function,
SCHED_BROADCAST_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "sched_transfer", "Schedule a transfer for a running call", sched_transfer_function,
SCHED_TRANSFER_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "create_uuid", "Create a uuid", uuid_function, UUID_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "sched_api", "Schedule an api command", sched_api_function, SCHED_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "unsched_api", "Unschedule an api command", unsched_api_function, UNSCHED_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "bgapi", "Execute an api command in a thread", bgapi_function, "<command>[ <arg>]");
SWITCH_ADD_API(commands_api_interface, "sched_del", "Delete a Scheduled task", sched_del_function, "<task_id>|<group_id>");
SWITCH_ADD_API(commands_api_interface, "xml_wrap", "Wrap another api command in xml", xml_wrap_api_function, "<command> <args>");
SWITCH_ADD_API(commands_api_interface, "is_lan_addr", "see if an ip is a lan addr", lan_addr_function, "<ip>");
SWITCH_ADD_API(commands_api_interface, "cond", "Eval a conditional", cond_function, "<expr> ? <true val> : <false val>");
SWITCH_ADD_API(commands_api_interface, "regex", "Eval a regex", regex_function, "<data>|<pattern>[|<subst string>]");
SWITCH_ADD_API(commands_api_interface, "acl", "compare an ip to an acl list", acl_function, "<ip> <list_name>");
SWITCH_ADD_API(commands_api_interface, "uuid_chat", "Send a chat message", uuid_chat, UUID_CHAT_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_deflect", "Send a deflect", uuid_deflect, UUID_DEFLECT_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "find_user_xml", "find a user", find_user_function, "<key> <user> <domain>");
SWITCH_ADD_API(commands_api_interface, "user_exists", "find a user", user_exists_function, "<key> <user> <domain>");
SWITCH_ADD_API(commands_api_interface, "xml_locate", "find some xml", xml_locate_function, "[root | <section> <tag> <tag_attr_name> <tag_attr_val>]");
SWITCH_ADD_API(commands_api_interface, "user_data", "find user data", user_data_function, "<user>@<domain> [var|param|attr] <name>");
SWITCH_ADD_API(commands_api_interface, "url_encode", "url encode a string", url_encode_function, "<string>");
SWITCH_ADD_API(commands_api_interface, "url_decode", "url decode a string", url_decode_function, "<string>");
SWITCH_ADD_API(commands_api_interface, "module_exists", "check if module exists", module_exists_function, "<module>");
SWITCH_ADD_API(commands_api_interface, "domain_exists", "check if a domain exists", domain_exists_function, "<domain>");
SWITCH_ADD_API(commands_api_interface, "uuid_send_dtmf", "send dtmf digits", uuid_send_dtmf_function, UUID_SEND_DTMF_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "eval", "eval (noop)", eval_function, "[uuid:<uuid> ]<expression>");
SWITCH_ADD_API(commands_api_interface, "expand", "expand vars and execute", expand_function, "[uuid:<uuid> ]<cmd> <args>");
SWITCH_ADD_API(commands_api_interface, "echo", "echo", echo_function, "<data>");
SWITCH_ADD_API(commands_api_interface, "stun", "stun", stun_function, "<stun_server>[:port]");
SWITCH_ADD_API(commands_api_interface, "system", "Execute a system command", system_function, SYSTEM_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "bg_system", "Execute a system command in the background", bg_system_function, SYSTEM_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "time_test", "time_test", time_test_function, "<mss>");
SWITCH_ADD_API(commands_api_interface, "nat_map", "nat_map", nat_map_function, "[status|republish|reinit] | [add|del] <port> [tcp|udp] [static]");
SWITCH_ADD_API(commands_api_interface, "host_lookup", "host_lookup", host_lookup_function, "<hostname>");
SWITCH_ADD_API(commands_api_interface, "hostname", "Returns the system hostname", hostname_api_function, "");
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_NOUNLOAD;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/