diff --git a/conf/vanilla/vars.xml b/conf/vanilla/vars.xml
index 2792a567ce..8c8d0cf90c 100644
--- a/conf/vanilla/vars.xml
+++ b/conf/vanilla/vars.xml
@@ -14,6 +14,28 @@
-->
+
+
diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c
index 5ab14a31d6..8f09145e71 100644
--- a/libs/stfu/stfu.c
+++ b/libs/stfu/stfu.c
@@ -447,6 +447,10 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint16_t seq, uin
if (i->max_drift) {
+ if (i->drift_dropped_packets > 500) {
+ stfu_n_reset(i);
+ }
+
if (i->ts_drift < i->max_drift) {
if (++i->drift_dropped_packets < i->drift_max_dropped) {
stfu_log(STFU_LOG_EMERG, "%s TOO LATE !!! %u \n\n\n", i->name, ts);
diff --git a/scripts/gentls_cert.in b/scripts/gentls_cert.in
index 26da60c7f8..f2e4cd5a99 100644
--- a/scripts/gentls_cert.in
+++ b/scripts/gentls_cert.in
@@ -7,7 +7,7 @@ export KEY_SIZE=${KEY_SIZE}
TMPFILE="/tmp/fs-ca-$$-$(date +%Y%m%d%H%M%S)"
-COMMON_NAME="FreesSWITCH CA"
+COMMON_NAME="FreeSWITCH CA"
ALT_NAME="DNS:test.freeswitch.org"
ORG_NAME="FreeSWITCH"
OUTFILE="agent.pem"
@@ -47,6 +47,7 @@ setup_ca() {
default_bits = \$ENV::KEY_SIZE
prompt = no
distinguished_name = req_dn
+ x509_extensions = v3_ca
[ req_dn ]
commonName = %CN%
@@ -69,6 +70,12 @@ setup_ca() {
subjectAltName=%ALTNAME%
nsCertType=client
extendedKeyUsage=clientAuth
+
+ [ v3_ca ]
+ subjectKeyIdentifier=hash
+ authorityKeyIdentifier=keyid:always,issuer
+ basicConstraints=CA:TRUE
+
EOF
fi
@@ -80,10 +87,12 @@ setup_ca() {
"${CONFDIR}/CA/config.tpl" \
> "${TMPFILE}.cfg" || exit 1
+ openssl ecparam -name secp160r2 -out CA_CURVE.pem
openssl req -out "${CONFDIR}/CA/cacert.pem" \
- -new -x509 -keyout "${CONFDIR}/CA/cakey.pem" \
+ -new -x509 -keyout "${CONFDIR}/CA/cakey.pem" -newkey ec:CA_CURVE.pem \
-config "${TMPFILE}.cfg" -nodes -days ${DAYS} -sha1 >/dev/null || exit 1
cat "${CONFDIR}/CA/cacert.pem" > "${CONFDIR}/cafile.pem"
+ cp $TMPFILE.cfg /tmp/ssl.cfg
rm "${TMPFILE}.cfg"
echo "DONE"
@@ -122,7 +131,7 @@ generate_cert() {
> "${TMPFILE}.cfg" || exit 1
openssl req -new -out "${TMPFILE}.req" \
- -newkey rsa:${KEY_SIZE} -keyout "${TMPFILE}.key" \
+ -newkey ec:CA_CURVE.pem -keyout "${TMPFILE}.key" \
-config "${TMPFILE}.cfg" -nodes -sha1 >/dev/null || exit 1
openssl x509 -req -CAkey "${CONFDIR}/CA/cakey.pem" -CA "${CONFDIR}/CA/cacert.pem" -CAcreateserial \
@@ -148,7 +157,6 @@ remove_ca() {
}
OUTFILESET="0"
command="$1"
-shift
while [ $# -gt 0 ]; do
case $1 in
diff --git a/src/include/switch_console.h b/src/include/switch_console.h
index e6f6cf476e..73410bd248 100644
--- a/src/include/switch_console.h
+++ b/src/include/switch_console.h
@@ -83,6 +83,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_add_complete_func(const char *nam
SWITCH_DECLARE(switch_status_t) switch_console_del_complete_func(const char *name);
SWITCH_DECLARE(switch_status_t) switch_console_run_complete_func(const char *func, const char *line,
const char *last_word, switch_console_callback_match_t **matches);
+SWITCH_DECLARE(void) switch_console_push_match_unique(switch_console_callback_match_t **matches, const char *new_val);
SWITCH_DECLARE(void) switch_console_push_match(switch_console_callback_match_t **matches, const char *new_val);
SWITCH_DECLARE(void) switch_console_free_matches(switch_console_callback_match_t **matches);
SWITCH_DECLARE(unsigned char) switch_console_complete(const char *line, const char *last_word,
diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h
index 5deb8ee313..24b8765faf 100644
--- a/src/include/switch_utils.h
+++ b/src/include/switch_utils.h
@@ -464,14 +464,27 @@ SWITCH_DECLARE(switch_status_t) switch_resolve_host(const char *host, char *buf,
/*!
\brief find local ip of the box
- \param buf the buffer to write the ip adress found into
+ \param buf the buffer to write the ip address found into
\param len the length of the buf
+ \param mask the CIDR found (AF_INET only)
\param family the address family to return (AF_INET or AF_INET6)
\return SWITCH_STATUS_SUCCESSS for success, otherwise failure
*/
SWITCH_DECLARE(switch_status_t) switch_find_local_ip(_Out_opt_bytecapcount_(len)
char *buf, _In_ int len, _In_opt_ int *mask, _In_ int family);
+/*!
+ \brief find primary ip of the specified interface
+ \param buf the buffer to write the ip address found into
+ \param len the length of the buf
+ \param mask the CIDR found (AF_INET only)
+ \param ifname interface name to check
+ \param family the address family to return (AF_INET or AF_INET6)
+ \return SWITCH_STATUS_SUCCESSS for success, otherwise failure
+*/
+SWITCH_DECLARE(switch_status_t) switch_find_interface_ip(_Out_opt_bytecapcount_(len)
+ char *buf, _In_ int len, _In_opt_ int *mask, _In_ const char *ifname, _In_ int family);
+
/*!
\brief find the char representation of an ip adress
\param buf the buffer to write the ip adress found into
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index fc74c3dd65..abc0aace9a 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -6028,6 +6028,49 @@ SWITCH_STANDARD_API(file_exists_function)
return SWITCH_STATUS_SUCCESS;
}
+#define INTERFACE_IP_SYNTAX "[auto|ipv4|ipv6] "
+SWITCH_STANDARD_API(interface_ip_function)
+{
+ char *mydata = NULL, *argv[3] = { 0 };
+ int argc = 0;
+ char addr[INET6_ADDRSTRLEN];
+
+ if (!zstr(cmd)) {
+ mydata = strdup(cmd);
+ switch_assert(mydata);
+ argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (argc < 2) {
+ stream->write_function(stream, "USAGE: interface_ip %s\n", INTERFACE_IP_SYNTAX);
+ goto end;
+ }
+
+ if (!strcasecmp(argv[0], "ipv4")) {
+ if (switch_find_interface_ip(addr, sizeof(addr), NULL, argv[1], AF_INET) == SWITCH_STATUS_SUCCESS) {
+ stream->write_function(stream, "%s", addr);
+ }
+ }
+ else if (!strcasecmp(argv[0], "ipv6")) {
+ if (switch_find_interface_ip(addr, sizeof(addr), NULL, argv[1], AF_INET6) == SWITCH_STATUS_SUCCESS) {
+ stream->write_function(stream, "%s", addr);
+ }
+ }
+ else if (!strcasecmp(argv[0], "auto")) {
+ if (switch_find_interface_ip(addr, sizeof(addr), NULL, argv[1], AF_UNSPEC) == SWITCH_STATUS_SUCCESS) {
+ stream->write_function(stream, "%s", addr);
+ }
+ }
+ else {
+ stream->write_function(stream, "USAGE: interface_ip %s\n", INTERFACE_IP_SYNTAX);
+ }
+
+end:
+ switch_safe_free(mydata);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
{
switch_api_interface_t *commands_api_interface;
@@ -6065,6 +6108,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
SWITCH_ADD_API(commands_api_interface, "help", "Show help for all the api commands", help_function, "");
SWITCH_ADD_API(commands_api_interface, "host_lookup", "Lookup host", host_lookup_function, "");
SWITCH_ADD_API(commands_api_interface, "hostname", "Return the system hostname", hostname_api_function, "");
+ SWITCH_ADD_API(commands_api_interface, "interface_ip", "Return the primary IP of an interface", interface_ip_function, INTERFACE_IP_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "switchname", "Return the switch name", switchname_api_function, "");
SWITCH_ADD_API(commands_api_interface, "hupall", "hupall", hupall_api_function, " [ ]");
SWITCH_ADD_API(commands_api_interface, "in_group", "Determine if a user is in a group", in_group_function, "[@] ");
@@ -6217,6 +6261,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
switch_console_set_complete("add fsctl flush_db_handles");
switch_console_set_complete("add fsctl min_idle_cpu");
switch_console_set_complete("add fsctl send_sighup");
+ switch_console_set_complete("add interface_ip auto ::console::list_interfaces");
+ switch_console_set_complete("add interface_ip ipv4 ::console::list_interfaces");
+ switch_console_set_complete("add interface_ip ipv6 ::console::list_interfaces");
switch_console_set_complete("add load ::console::list_available_modules");
switch_console_set_complete("add nat_map reinit");
switch_console_set_complete("add nat_map republish");
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index 7ea86fa973..bbf4ac3032 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -8815,7 +8815,8 @@ static void call_setup_event_handler(switch_event_t *event)
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "conference_track_status", "true");
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "conference_track_call_id", call_id);
- switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "sip_invite_domain", domain);
+ switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "sip_invite_domain", domain);
+ switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "sip_invite_contact_params", "~isfocus");
if (!strncasecmp(ostr, "url+", 4)) {
ostr += 4;
diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c
index dff09844e7..9040c2c141 100644
--- a/src/mod/endpoints/mod_skinny/skinny_server.c
+++ b/src/mod/endpoints/mod_skinny/skinny_server.c
@@ -438,6 +438,7 @@ switch_status_t skinny_session_send_call_info_all(switch_core_session_t *session
struct skinny_session_set_variables_helper {
private_t *tech_pvt;
switch_channel_t *channel;
+ listener_t *listener;
uint32_t count;
};
@@ -463,6 +464,9 @@ int skinny_session_set_variables_callback(void *pArg, int argc, char **argv, cha
struct skinny_session_set_variables_helper *helper = pArg;
char *tmp;
+ listener_t *listener;
+
+ switch_xml_t xroot, xdomain, xuser, xvariables, xvariable;
helper->count++;
switch_channel_set_variable_name_printf(helper->channel, device_name, "skinny_device_name_%d", helper->count);
@@ -482,6 +486,50 @@ int skinny_session_set_variables_callback(void *pArg, int argc, char **argv, cha
switch_channel_set_variable_name_printf(helper->channel, value, "skinny_line_value_%d", helper->count);
switch_channel_set_variable_name_printf(helper->channel, caller_name, "skinny_line_caller_name_%d", helper->count);
+ listener = helper->listener;
+
+ if ( ! listener ) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_DEBUG,
+ "no defined listener on channel var setup, will not attempt to set variables\n");
+ return(0);
+ }
+
+ /* Process through and extract any variables from the user and set in the channel */
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_DEBUG,
+ "searching for user (id=%s) in profile %s in channel var setup\n",
+ listener->device_name, listener->profile->domain);
+
+ if (switch_xml_locate_user("id", listener->device_name, listener->profile->domain, "",
+ &xroot, &xdomain, &xuser, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_WARNING,
+ "unable to find user (id=%s) in channel var setup\n", listener->device_name);
+ }
+
+ if ( xuser ) {
+ char *uid = (char *) switch_xml_attr_soft(xuser, "id");
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_DEBUG,
+ "found user (id=%s) in channel var setup\n", uid);
+
+ if ((xvariables = switch_xml_child(xuser, "variables"))) {
+
+ for (xvariable = switch_xml_child(xvariables, "variable"); xvariable; xvariable = xvariable->next) {
+ char *var = (char *) switch_xml_attr_soft(xvariable, "name");
+ char *val = (char *) switch_xml_attr_soft(xvariable, "value");
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(helper->tech_pvt->session), SWITCH_LOG_DEBUG,
+ "found variable (%s=%s) for user (%s) in channel var setup\n", listener->device_name, val, var);
+
+ switch_channel_set_variable_name_printf(helper->channel, var, "%s", val);
+ }
+ }
+ }
+
+ if ( xroot ) {
+ switch_xml_free(xroot);
+ }
+
return 0;
}
@@ -492,6 +540,7 @@ switch_status_t skinny_session_set_variables(switch_core_session_t *session, lis
helper.tech_pvt = switch_core_session_get_private(session);
helper.channel = switch_core_session_get_channel(session);
+ helper.listener = listener;
helper.count = 0;
switch_channel_set_variable(helper.channel, "skinny_profile_name", helper.tech_pvt->profile->name);
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index c98417f374..cfdf687b93 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -1300,19 +1300,18 @@ static void our_sofia_event_callback(nua_event_t event,
}
- if ((refer_to = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_refer_to))) {
-
- if ((tmp = sofia_glue_get_url_from_contact(refer_to, 0))) {
- refer_to = tmp;
- }
-
- if ((iparams = strrchr(refer_to, ';'))) {
+ if ((refer_to = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_refer_to))) {
+ if ((iparams = strchr(refer_to, ';'))) {
*iparams++ = '\0';
- if (!switch_stristr("method=", iparams)) {
+ if (!params || !switch_stristr("method=", params)) {
params = iparams;
}
}
+
+ if ((tmp = sofia_glue_get_url_from_contact(refer_to, 0))) {
+ refer_to = tmp;
+ }
}
if (params) {
@@ -4052,9 +4051,22 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
}
} else if (!strcasecmp(var, "rtp-ip")) {
char *ip = mod_sofia_globals.guess_ip;
+ char buf[64];
if (!strcmp(val, "0.0.0.0")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip);
+ } else if (!strncasecmp(val, "interface:", 10)) {
+ char *ifname = val+10;
+ int family = AF_UNSPEC;
+ if (!strncasecmp(ifname, "auto/", 5)) { ifname += 5; family = AF_UNSPEC; }
+ if (!strncasecmp(ifname, "ipv4/", 5)) { ifname += 5; family = AF_INET; }
+ if (!strncasecmp(ifname, "ipv6/", 5)) { ifname += 5; family = AF_INET6; }
+ if (switch_find_interface_ip(buf, sizeof(buf), NULL, ifname, family) == SWITCH_STATUS_SUCCESS) {
+ ip = buf;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using %s IP for interface %s for rtp-ip\n", ip, val+10);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown IP for interface %s for rtp-ip\n", val+10);
+ }
} else {
ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
}
@@ -4065,9 +4077,22 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
}
} else if (!strcasecmp(var, "sip-ip")) {
char *ip = mod_sofia_globals.guess_ip;
+ char buf[64];
if (!strcmp(val, "0.0.0.0")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip);
+ } else if (!strncasecmp(val, "interface:", 10)) {
+ char *ifname = val+10;
+ int family = AF_UNSPEC;
+ if (!strncasecmp(ifname, "auto/", 5)) { ifname += 5; family = AF_UNSPEC; }
+ if (!strncasecmp(ifname, "ipv4/", 5)) { ifname += 5; family = AF_INET; }
+ if (!strncasecmp(ifname, "ipv6/", 5)) { ifname += 5; family = AF_INET6; }
+ if (switch_find_interface_ip(buf, sizeof(buf), NULL, ifname, family) == SWITCH_STATUS_SUCCESS) {
+ ip = buf;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using %s IP for interface %s for sip-ip\n", ip, val+10);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown IP for interface %s for sip-ip\n", val+10);
+ }
} else {
ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
}
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index 7414bc7326..5140192847 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -1459,7 +1459,12 @@ char *sofia_overcome_sip_uri_weakness(switch_core_session_t *session, const char
char *stripped = switch_core_session_strdup(session, uri);
char *new_uri = NULL;
char *p;
+ const char *url_params = NULL;
+ if (!zstr(params) && *params == '~') {
+ url_params = params + 1;
+ params = NULL;
+ }
stripped = sofia_glue_get_url_from_contact(stripped, 0);
@@ -1504,7 +1509,9 @@ char *sofia_overcome_sip_uri_weakness(switch_core_session_t *session, const char
}
}
-
+ if (url_params && !uri_only) {
+ new_uri = switch_core_session_sprintf(session, "%s;%s", new_uri, url_params);
+ }
if (!zstr(invite_tel_params)) {
char *lhs, *rhs = strchr(new_uri, '@');
@@ -2388,7 +2395,6 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
switch_channel_set_variable(channel, "sip_outgoing_contact_uri", invite_contact);
-
/*
Does the "genius" who wanted SIP to be "text-based" so it was "easier to read" even use it now,
or did he just suggest it to make our lives miserable?
diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c
index be66fe877c..3004601661 100644
--- a/src/mod/event_handlers/mod_rayo/mod_rayo.c
+++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c
@@ -718,6 +718,9 @@ struct rayo_actor *rayo_actor_locate(const char *jid, const char *file, int line
{
struct rayo_actor *actor = NULL;
switch_mutex_lock(globals.actors_mutex);
+ if (!strncmp("xmpp:", jid, 5)) {
+ jid = jid + 5;
+ }
actor = (struct rayo_actor *)switch_core_hash_find(globals.actors, jid);
if (actor) {
if (!actor->destroy) {
@@ -824,13 +827,30 @@ int rayo_actor_seq_next(struct rayo_actor *actor)
return seq;
}
-#define RAYO_CALL_LOCATE(call_uuid) rayo_call_locate(call_uuid, __FILE__, __LINE__)
+#define RAYO_CALL_LOCATE(call_uri) rayo_call_locate(call_uri, __FILE__, __LINE__)
/**
- * Get exclusive access to Rayo call data. Use to access call data outside channel thread.
+ * Get access to Rayo call data. Use to access call data outside channel thread.
+ * @param call_uri the Rayo XMPP URI
+ * @return the call or NULL.
+ */
+static struct rayo_call *rayo_call_locate(const char *call_uri, const char *file, int line)
+{
+ struct rayo_actor *actor = rayo_actor_locate(call_uri, file, line);
+ if (actor && is_call_actor(actor)) {
+ return RAYO_CALL(actor);
+ } else if (actor) {
+ RAYO_UNLOCK(actor);
+ }
+ return NULL;
+}
+
+#define RAYO_CALL_LOCATE_BY_ID(call_uuid) rayo_call_locate_by_id(call_uuid, __FILE__, __LINE__)
+/**
+ * Get access to Rayo call data. Use to access call data outside channel thread.
* @param call_uuid the FreeSWITCH call UUID
* @return the call or NULL.
*/
-static struct rayo_call *rayo_call_locate(const char *call_uuid, const char *file, int line)
+static struct rayo_call *rayo_call_locate_by_id(const char *call_uuid, const char *file, int line)
{
struct rayo_actor *actor = rayo_actor_locate_by_id(call_uuid, file, line);
if (actor && is_call_actor(actor)) {
@@ -1692,18 +1712,18 @@ static iks *on_rayo_hangup(struct rayo_actor *call, struct rayo_message *msg, vo
* @param call the call that joins
* @param session the session
* @param node the join request
- * @param call_id to join
+ * @param call_uri to join
* @param media mode (direct/bridge)
* @return the response
*/
-static iks *join_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_id, const char *media)
+static iks *join_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_uri, const char *media)
{
iks *response = NULL;
/* take call out of media path if media = "direct" */
const char *bypass = !strcmp("direct", media) ? "true" : "false";
/* check if joining to rayo call */
- struct rayo_call *b_call = RAYO_CALL_LOCATE(call_id);
+ struct rayo_call *b_call = RAYO_CALL_LOCATE(call_uri);
if (!b_call) {
/* not a rayo call */
response = iks_new_error_detailed(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg is not a rayo call");
@@ -1712,18 +1732,17 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, ik
response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "multiple joined calls not supported");
RAYO_UNLOCK(b_call);
} else {
- RAYO_UNLOCK(b_call);
-
/* bridge this call to call-uri */
switch_channel_set_variable(switch_core_session_get_channel(session), "bypass_media", bypass);
if (switch_false(bypass)) {
switch_channel_pre_answer(switch_core_session_get_channel(session));
}
- if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), call_id) == SWITCH_STATUS_SUCCESS) {
+ if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), rayo_call_get_uuid(b_call)) == SWITCH_STATUS_SUCCESS) {
response = iks_new_iq_result(node);
} else {
response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to bridge call");
}
+ RAYO_UNLOCK(b_call);
}
return response;
}
@@ -1797,7 +1816,7 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
iks *join = iks_find(node, "join");
const char *join_id;
const char *mixer_name;
- const char *call_id;
+ const char *call_uri;
/* validate input attributes */
if (!VALIDATE_RAYO_JOIN(join)) {
@@ -1806,22 +1825,22 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
goto done;
}
mixer_name = iks_find_attrib(join, "mixer-name");
- call_id = iks_find_attrib(join, "call-uri");
+ call_uri = iks_find_attrib(join, "call-uri");
if (!zstr(mixer_name)) {
join_id = mixer_name;
} else {
- join_id = call_id;
+ join_id = call_uri;
}
/* can't join both mixer and call */
- if (!zstr(mixer_name) && !zstr(call_id)) {
+ if (!zstr(mixer_name) && !zstr(call_uri)) {
response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "mixer-name and call-uri are mutually exclusive");
goto done;
}
/* need to join *something* */
- if (zstr(mixer_name) && zstr(call_id)) {
+ if (zstr(mixer_name) && zstr(call_uri)) {
response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "mixer-name or call-uri is required");
goto done;
}
@@ -1838,7 +1857,7 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
response = join_mixer(RAYO_CALL(call), session, node, mixer_name, iks_find_attrib(join, "direction"));
} else {
/* bridge calls */
- response = join_call(RAYO_CALL(call), session, node, call_id, iks_find_attrib(join, "media"));
+ response = join_call(RAYO_CALL(call), session, node, call_uri, iks_find_attrib(join, "media"));
}
done:
@@ -1850,21 +1869,22 @@ done:
* @param call the call that unjoined
* @param session the session
* @param node the unjoin request
- * @param call_id the b-leg uuid
+ * @param call_uri the b-leg xmpp URI
* @return the response
*/
-static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_id)
+static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_uri)
{
iks *response = NULL;
- const char *bleg = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_BRIDGE_UUID_VARIABLE);
+ const char *bleg_uuid = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_BRIDGE_UUID_VARIABLE);
+ const char *bleg_uri = switch_core_session_sprintf(session, "xmpp:%s@%s", bleg_uuid ? bleg_uuid : "", RAYO_JID(globals.server));
- /* bleg must match call_id */
- if (!zstr(bleg) && !strcmp(bleg, call_id)) {
+ /* bleg must match call_uri */
+ if (!zstr(bleg_uri) && !strcmp(bleg_uri, call_uri)) {
/* unbridge call */
response = iks_new_iq_result(node);
switch_ivr_park_session(session);
} else {
- /* not bridged or wrong b-leg UUID */
+ /* not bridged or wrong b-leg URI */
response = iks_new_error(node, STANZA_ERROR_SERVICE_UNAVAILABLE);
}
@@ -1919,16 +1939,16 @@ static iks *on_rayo_unjoin(struct rayo_actor *call, struct rayo_message *msg, vo
switch_core_session_t *session = (switch_core_session_t *)session_data;
iks *response = NULL;
iks *unjoin = iks_find(node, "unjoin");
- const char *call_id = iks_find_attrib(unjoin, "call-uri");
+ const char *call_uri = iks_find_attrib(unjoin, "call-uri");
const char *mixer_name = iks_find_attrib(unjoin, "mixer-name");
- if (!zstr(call_id) && !zstr(mixer_name)) {
+ if (!zstr(call_uri) && !zstr(mixer_name)) {
response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
} else if (!RAYO_CALL(call)->joined) {
/* not joined to anything */
response = iks_new_error(node, STANZA_ERROR_SERVICE_UNAVAILABLE);
- } else if (!zstr(call_id)) {
- response = unjoin_call(RAYO_CALL(call), session, node, call_id);
+ } else if (!zstr(call_uri)) {
+ response = unjoin_call(RAYO_CALL(call), session, node, call_uri);
} else if (!zstr(mixer_name)) {
response = unjoin_mixer(RAYO_CALL(call), session, node, mixer_name);
} else {
@@ -2043,20 +2063,20 @@ static void *SWITCH_THREAD_FUNC rayo_dial_thread(switch_thread_t *thread, void *
if (join) {
/* check join args */
- const char *call_id = iks_find_attrib(join, "call-uri");
+ const char *call_uri = iks_find_attrib(join, "call-uri");
const char *mixer_name = iks_find_attrib(join, "mixer-name");
- if (!zstr(call_id) && !zstr(mixer_name)) {
+ if (!zstr(call_uri) && !zstr(mixer_name)) {
/* can't join both */
response = iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
goto done;
- } else if (zstr(call_id) && zstr(mixer_name)) {
+ } else if (zstr(call_uri) && zstr(mixer_name)) {
/* nobody to join to? */
response = iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
goto done;
- } else if (!zstr(call_id)) {
+ } else if (!zstr(call_uri)) {
/* bridge */
- struct rayo_call *b_call = RAYO_CALL_LOCATE(call_id);
+ struct rayo_call *b_call = RAYO_CALL_LOCATE(call_uri);
/* is b-leg available? */
if (!b_call) {
response = iks_new_error_detailed(iq, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg not found");
@@ -2066,8 +2086,8 @@ static void *SWITCH_THREAD_FUNC rayo_dial_thread(switch_thread_t *thread, void *
RAYO_UNLOCK(b_call);
goto done;
}
+ stream.write_function(&stream, "%s%s &rayo(bridge %s)", gateway->dial_prefix, dial_to_stripped, rayo_call_get_uuid(b_call));
RAYO_UNLOCK(b_call);
- stream.write_function(&stream, "%s%s &rayo(bridge %s)", gateway->dial_prefix, dial_to_stripped, call_id);
} else {
/* conference */
stream.write_function(&stream, "%s%s &rayo(conference %s@%s)", gateway->dial_prefix, dial_to_stripped, mixer_name, globals.mixer_conf_profile);
@@ -2399,7 +2419,7 @@ static void on_mixer_delete_member_event(struct rayo_mixer *mixer, switch_event_
switch_core_hash_delete(mixer->members, uuid);
/* flag call as available to join another mixer */
- call = RAYO_CALL_LOCATE(uuid);
+ call = RAYO_CALL_LOCATE_BY_ID(uuid);
if (call) {
call->joined = 0;
call->joined_id = NULL;
@@ -2415,7 +2435,7 @@ static void on_mixer_delete_member_event(struct rayo_mixer *mixer, switch_event_
/* broadcast member unjoined event to subscribers */
delete_member_event = iks_new_presence("unjoined", RAYO_NS, RAYO_JID(mixer), "");
x = iks_find(delete_member_event, "unjoined");
- iks_insert_attrib(x, "call-uri", uuid);
+ iks_insert_attrib_printf(x, "call-uri", "xmpp:%s@%s", uuid, RAYO_JID(globals.server));
broadcast_mixer_event(mixer, delete_member_event);
iks_delete(delete_member_event);
@@ -2451,7 +2471,7 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *
{
iks *add_member_event = NULL, *x;
const char *uuid = switch_event_get_header(event, "Unique-ID");
- struct rayo_call *call = RAYO_CALL_LOCATE(uuid);
+ struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(uuid);
if (!mixer) {
/* new mixer */
@@ -2493,7 +2513,7 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *
/* broadcast member joined event to subscribers */
add_member_event = iks_new_presence("joined", RAYO_NS, RAYO_JID(mixer), "");
x = iks_find(add_member_event, "joined");
- iks_insert_attrib(x, "call-uri", uuid);
+ iks_insert_attrib_printf(x, "call-uri", "xmpp:%s@%s", uuid, RAYO_JID(globals.server));
broadcast_mixer_event(mixer, add_member_event);
iks_delete(add_member_event);
}
@@ -2539,7 +2559,7 @@ static void on_call_originate_event(struct rayo_client *rclient, switch_event_t
{
switch_core_session_t *session = NULL;
const char *uuid = switch_event_get_header(event, "Unique-ID");
- struct rayo_call *call = RAYO_CALL_LOCATE(uuid);
+ struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(uuid);
if (call && (session = switch_core_session_locate(uuid))) {
iks *response, *ref;
@@ -2556,11 +2576,7 @@ static void on_call_originate_event(struct rayo_client *rclient, switch_event_t
ref = iks_insert(response, "ref");
iks_insert_attrib(ref, "xmlns", RAYO_NS);
-#ifdef RAYO_UUID_IN_REF_URI
- iks_insert_attrib(ref, "uri", uuid);
-#else
iks_insert_attrib_printf(ref, "uri", "xmpp:%s", RAYO_JID(call));
-#endif
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), response);
call->dial_id = NULL;
}
@@ -2573,7 +2589,7 @@ static void on_call_originate_event(struct rayo_client *rclient, switch_event_t
*/
static void on_call_end_event(switch_event_t *event)
{
- struct rayo_call *call = RAYO_CALL_LOCATE(switch_event_get_header(event, "Unique-ID"));
+ struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
if (call) {
#if 0
@@ -2597,7 +2613,7 @@ static void on_call_end_event(switch_event_t *event)
*/
static void on_call_answer_event(struct rayo_client *rclient, switch_event_t *event)
{
- struct rayo_call *call = RAYO_CALL_LOCATE(switch_event_get_header(event, "Unique-ID"));
+ struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
if (call) {
iks *revent = iks_new_presence("answered", RAYO_NS,
switch_event_get_header(event, "variable_rayo_call_jid"),
@@ -2616,7 +2632,7 @@ static void on_call_ringing_event(struct rayo_client *rclient, switch_event_t *e
{
const char *call_direction = switch_event_get_header(event, "Call-Direction");
if (call_direction && !strcmp(call_direction, "outbound")) {
- struct rayo_call *call = RAYO_CALL_LOCATE(switch_event_get_header(event, "Unique-ID"));
+ struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
if (call) {
switch_mutex_lock(RAYO_ACTOR(call)->mutex);
if (!call->ringing_sent) {
@@ -2641,7 +2657,7 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev
{
const char *a_uuid = switch_event_get_header(event, "Unique-ID");
const char *b_uuid = switch_event_get_header(event, "Bridge-B-Unique-ID");
- struct rayo_call *call = RAYO_CALL_LOCATE(a_uuid);
+ struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(a_uuid);
struct rayo_call *b_call;
if (call) {
@@ -2650,7 +2666,7 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev
switch_event_get_header(event, "variable_rayo_call_jid"),
switch_event_get_header(event, "variable_rayo_dcp_jid"));
iks *joined = iks_find(revent, "joined");
- iks_insert_attrib(joined, "call-uri", b_uuid);
+ iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
call->joined = JOINED_CALL;
call->joined_id = switch_core_strdup(RAYO_POOL(call), b_uuid);
@@ -2658,11 +2674,11 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
/* send B-leg event */
- b_call = RAYO_CALL_LOCATE(b_uuid);
+ b_call = RAYO_CALL_LOCATE_BY_ID(b_uuid);
if (b_call) {
revent = iks_new_presence("joined", RAYO_NS, RAYO_JID(b_call), rayo_call_get_dcp_jid(b_call));
joined = iks_find(revent, "joined");
- iks_insert_attrib(joined, "call-uri", a_uuid);
+ iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", a_uuid, RAYO_JID(globals.server));
b_call->joined = JOINED_CALL;
b_call->joined_id = switch_core_strdup(RAYO_POOL(b_call), a_uuid);
@@ -2683,7 +2699,7 @@ static void on_call_unbridge_event(struct rayo_client *rclient, switch_event_t *
{
const char *a_uuid = switch_event_get_header(event, "Unique-ID");
const char *b_uuid = switch_event_get_header(event, "Bridge-B-Unique-ID");
- struct rayo_call *call = RAYO_CALL_LOCATE(a_uuid);
+ struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(a_uuid);
struct rayo_call *b_call;
if (call) {
@@ -2692,18 +2708,18 @@ static void on_call_unbridge_event(struct rayo_client *rclient, switch_event_t *
switch_event_get_header(event, "variable_rayo_call_jid"),
switch_event_get_header(event, "variable_rayo_dcp_jid"));
iks *joined = iks_find(revent, "unjoined");
- iks_insert_attrib(joined, "call-uri", b_uuid);
+ iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
call->joined = 0;
call->joined_id = NULL;
/* send B-leg event */
- b_call = RAYO_CALL_LOCATE(b_uuid);
+ b_call = RAYO_CALL_LOCATE_BY_ID(b_uuid);
if (b_call) {
revent = iks_new_presence("unjoined", RAYO_NS, RAYO_JID(b_call), rayo_call_get_dcp_jid(b_call));
joined = iks_find(revent, "unjoined");
- iks_insert_attrib(joined, "call-uri", a_uuid);
+ iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", a_uuid, RAYO_JID(globals.server));
RAYO_SEND_MESSAGE(b_call, rayo_call_get_dcp_jid(b_call), revent);
b_call->joined = 0;
diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.h b/src/mod/event_handlers/mod_rayo/mod_rayo.h
index 260c811a45..dd0adb3192 100644
--- a/src/mod/event_handlers/mod_rayo/mod_rayo.h
+++ b/src/mod/event_handlers/mod_rayo/mod_rayo.h
@@ -51,9 +51,6 @@
#define RAT_PEER_SERVER "PEER_SERVER"
#define RAT_CLIENT "CLIENT"
-/* these are support punchblock.. undefine once punchblock is fixed */
-#define RAYO_UUID_IN_REF_URI
-
struct rayo_actor;
struct rayo_call;
struct rayo_mixer;
diff --git a/src/mod/event_handlers/mod_rayo/rayo_components.c b/src/mod/event_handlers/mod_rayo/rayo_components.c
index b376e97770..b5137d9459 100644
--- a/src/mod/event_handlers/mod_rayo/rayo_components.c
+++ b/src/mod/event_handlers/mod_rayo/rayo_components.c
@@ -58,11 +58,7 @@ void rayo_component_send_start(struct rayo_component *component, iks *iq)
iks *response = iks_new_iq_result(iq);
iks *ref = iks_insert(response, "ref");
iks_insert_attrib(ref, "xmlns", RAYO_NS);
-#ifdef RAYO_UUID_IN_REF_URI
- iks_insert_attrib(ref, "uri", component->ref);
-#else
iks_insert_attrib_printf(ref, "uri", "xmpp:%s", RAYO_JID(component));
-#endif
RAYO_SEND_REPLY(component, iks_find_attrib(response, "to"), response);
}
diff --git a/src/switch_console.c b/src/switch_console.c
index b1e2c8e271..b2c003a6c6 100644
--- a/src/switch_console.c
+++ b/src/switch_console.c
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#define CMD_BUFLEN 1024
#ifdef SWITCH_HAVE_LIBEDIT
@@ -619,6 +620,36 @@ SWITCH_DECLARE_NONSTD(switch_status_t) switch_console_list_loaded_modules(const
return SWITCH_STATUS_FALSE;
}
+#ifdef HAVE_GETIFADDRS
+#include
+#include
+SWITCH_DECLARE_NONSTD(switch_status_t) switch_console_list_interfaces(const char *line, const char *cursor, switch_console_callback_match_t **matches)
+{
+ struct match_helper h = { 0 };
+ struct ifaddrs *addrs, *addr;
+
+ getifaddrs(&addrs);
+ for(addr = addrs; addr; addr = addr->ifa_next) {
+ if (addr->ifa_flags & IFF_UP) {
+ switch_console_push_match_unique(&h.my_matches, addr->ifa_name);
+ }
+ }
+ freeifaddrs(addrs);
+
+ if (h.my_matches) {
+ *matches = h.my_matches;
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ return SWITCH_STATUS_FALSE;
+}
+#else
+SWITCH_DECLARE_NONSTD(switch_status_t) switch_console_list_interfaces(const char *line, const char *cursor, switch_console_callback_match_t **matches)
+{
+ return SWITCH_STATUS_FALSE;
+}
+#endif
+
static int uuid_callback(void *pArg, int argc, char **argv, char **columnNames)
{
struct match_helper *h = (struct match_helper *) pArg;
@@ -1631,6 +1662,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_init(switch_memory_pool_t *pool)
switch_core_hash_init(&globals.func_hash, pool);
switch_console_add_complete_func("::console::list_available_modules", (switch_console_complete_callback_t) switch_console_list_available_modules);
switch_console_add_complete_func("::console::list_loaded_modules", (switch_console_complete_callback_t) switch_console_list_loaded_modules);
+ switch_console_add_complete_func("::console::list_interfaces", (switch_console_complete_callback_t) switch_console_list_interfaces);
switch_console_add_complete_func("::console::list_uuid", (switch_console_complete_callback_t) switch_console_list_uuid);
return SWITCH_STATUS_SUCCESS;
}
@@ -1741,6 +1773,20 @@ SWITCH_DECLARE(void) switch_console_sort_matches(switch_console_callback_match_t
}
}
+SWITCH_DECLARE(void) switch_console_push_match_unique(switch_console_callback_match_t **matches, const char *new_val)
+{
+ /* Ignore the entry if it is already in the list */
+ if (*matches) {
+ switch_console_callback_match_node_t *node;
+
+ for(node = (*matches)->head; node; node = node->next) {
+ if (!strcasecmp(node->val, new_val)) return;
+ }
+ }
+
+ switch_console_push_match(matches, new_val);
+}
+
SWITCH_DECLARE(void) switch_console_push_match(switch_console_callback_match_t **matches, const char *new_val)
{
switch_console_callback_match_node_t *match;
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index 131de61b8d..cc6dfd5675 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -2616,6 +2616,10 @@ SWITCH_DECLARE(void) switch_rtp_set_flag(switch_rtp_t *rtp_session, switch_rtp_f
rtp_session->autoadj_window = 20;
rtp_session->autoadj_tally = 0;
rtp_flush_read_buffer(rtp_session, SWITCH_RTP_FLUSH_ONCE);
+
+ if (rtp_session->jb) {
+ stfu_n_reset(rtp_session->jb);
+ }
} else if (flags & SWITCH_RTP_FLAG_NOBLOCK) {
switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, TRUE);
}
diff --git a/src/switch_utils.c b/src/switch_utils.c
index da89f0c9c0..36ee3a36ca 100644
--- a/src/switch_utils.c
+++ b/src/switch_utils.c
@@ -1262,7 +1262,7 @@ static int get_netmask(struct sockaddr_in *me, int *mask)
struct sockaddr_in *s = (struct sockaddr_in *) i->ifa_addr;
struct sockaddr_in *m = (struct sockaddr_in *) i->ifa_netmask;
- if (s && m && s->sin_addr.s_addr == me->sin_addr.s_addr) {
+ if (s && m && s->sin_family == AF_INET && s->sin_addr.s_addr == me->sin_addr.s_addr) {
*mask = m->sin_addr.s_addr;
freeifaddrs(ifaddrs);
return 0;
@@ -1569,6 +1569,61 @@ SWITCH_DECLARE(switch_status_t) switch_find_local_ip(char *buf, int len, int *ma
return status;
}
+#ifdef HAVE_GETIFADDRS
+# include
+# include
+#endif
+SWITCH_DECLARE(switch_status_t) switch_find_interface_ip(char *buf, int len, int *mask, const char *ifname, int family)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+#ifdef HAVE_GETIFADDRS
+
+ struct ifaddrs *addrs, *addr;
+
+ getifaddrs(&addrs);
+ for(addr = addrs; addr; addr = addr->ifa_next)
+ {
+ if (!(addr->ifa_flags & IFF_UP)) continue; // Address is not UP
+ if (!addr->ifa_addr) continue; // No address set
+ if (!addr->ifa_netmask) continue; // No netmask set
+ if (family != AF_UNSPEC && addr->ifa_addr->sa_family != family) continue; // Not the address family we're looking for
+ if (strcmp(addr->ifa_name, ifname)) continue; // Not the interface we're looking for
+
+ switch(addr->ifa_addr->sa_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &( ((struct sockaddr_in*)(addr->ifa_addr))->sin_addr ), buf, len - 1);
+ break;
+ case AF_INET6:
+ inet_ntop(AF_INET6, &( ((struct sockaddr_in6*)(addr->ifa_addr))->sin6_addr ), buf, len - 1);
+ break;
+ default:
+ continue;
+ }
+
+ if (mask && addr->ifa_netmask->sa_family == AF_INET) {
+ *mask = ((struct sockaddr_in*)(addr->ifa_addr))->sin_addr.s_addr;
+ }
+
+ status = SWITCH_STATUS_SUCCESS;
+ break;
+ }
+ freeifaddrs(addrs);
+
+#elif defined(__linux__)
+
+ // TODO Not implemented, contributions welcome.
+
+#elif defined(WIN32)
+
+ // TODO Not implemented, contributions welcome.
+
+#endif
+
+ return status;
+}
+
+
SWITCH_DECLARE(switch_time_t) switch_str_time(const char *in)
{
switch_time_exp_t tm = { 0 };