mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-03-13 12:40:17 +00:00
%FEATURE Add new feature to filter the SDP on bypass_media calls to remove or limit codecs.
VARIABLE: bypass_media_sdp_filter Can be set globally or per leg on the inbound side of a bypass_media bridge. VALID FILTERS: remove(): Removes the specified codec if it exists in the SDP. only(): Removes all codecs besides the one specified (providing that it exists in the sdp) (will not remove telephone-event)) EXAMPLE 1 (remove everything leaving only g729): <action application="set" data="bypass_media_sdp_filter=only(g729)"/> <action application="set" data="bypass_media=true"/> <action application="bridge" data="sofia/internal/1238@conference.freeswitch.org"/> EXAMPLE 2 (remove everything leaving only g729 and also remove dtmf): <action application="set" data="bypass_media_sdp_filter=only(g729)|remove(telephone-event)"/> <action application="set" data="bypass_media=true"/> <action application="bridge" data="sofia/internal/1238@conference.freeswitch.org"/> EXAMPLE 3 (remove alaw and speex): <action application="set" data="bypass_media_sdp_filter=remove(pcma)|remove(speex)"/> <action application="set" data="bypass_media=true"/> <action application="bridge" data="sofia/internal/1238@conference.freeswitch.org"/>
This commit is contained in:
parent
92a66fb1e7
commit
24084adf77
@ -678,7 +678,8 @@ SWITCH_DECLARE(void) switch_channel_release_device_record(switch_device_record_t
|
|||||||
SWITCH_DECLARE(switch_status_t) switch_channel_bind_device_state_handler(switch_device_state_function_t function, void *user_data);
|
SWITCH_DECLARE(switch_status_t) switch_channel_bind_device_state_handler(switch_device_state_function_t function, void *user_data);
|
||||||
SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switch_device_state_function_t function);
|
SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switch_device_state_function_t function);
|
||||||
SWITCH_DECLARE(const char *) switch_channel_device_state2str(switch_device_state_t device_state);
|
SWITCH_DECLARE(const char *) switch_channel_device_state2str(switch_device_state_t device_state);
|
||||||
|
SWITCH_DECLARE(switch_status_t) switch_channel_pass_sdp(switch_channel_t *from_channel, switch_channel_t *to_channel, const char *sdp);
|
||||||
|
|
||||||
SWITCH_END_EXTERN_C
|
SWITCH_END_EXTERN_C
|
||||||
#endif
|
#endif
|
||||||
/* For Emacs:
|
/* For Emacs:
|
||||||
|
@ -275,7 +275,7 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se
|
|||||||
SWITCH_DECLARE(switch_rtp_crypto_key_type_t) switch_core_media_crypto_str2type(const char *str);
|
SWITCH_DECLARE(switch_rtp_crypto_key_type_t) switch_core_media_crypto_str2type(const char *str);
|
||||||
SWITCH_DECLARE(const char *) switch_core_media_crypto_type2str(switch_rtp_crypto_key_type_t type);
|
SWITCH_DECLARE(const char *) switch_core_media_crypto_type2str(switch_rtp_crypto_key_type_t type);
|
||||||
SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t type);
|
SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t type);
|
||||||
|
SWITCH_DECLARE(char *) switch_core_media_filter_sdp(const char *sdp, const char *cmd, const char *arg);
|
||||||
|
|
||||||
SWITCH_END_EXTERN_C
|
SWITCH_END_EXTERN_C
|
||||||
#endif
|
#endif
|
||||||
|
@ -418,6 +418,7 @@ SWITCH_DECLARE(switch_status_t) switch_frame_alloc(switch_frame_t **frame, switc
|
|||||||
SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_frame_t **clone);
|
SWITCH_DECLARE(switch_status_t) switch_frame_dup(switch_frame_t *orig, switch_frame_t **clone);
|
||||||
SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame);
|
SWITCH_DECLARE(switch_status_t) switch_frame_free(switch_frame_t **frame);
|
||||||
SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str);
|
SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str);
|
||||||
|
SWITCH_DECLARE(switch_bool_t) switch_is_leading_number(const char *str);
|
||||||
SWITCH_DECLARE(char *) switch_find_parameter(const char *str, const char *param, switch_memory_pool_t *pool);
|
SWITCH_DECLARE(char *) switch_find_parameter(const char *str, const char *param, switch_memory_pool_t *pool);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -6567,9 +6567,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
|||||||
}
|
}
|
||||||
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||||
other_channel = switch_core_session_get_channel(other_session);
|
other_channel = switch_core_session_get_channel(other_session);
|
||||||
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
|
switch_channel_pass_sdp(channel, other_channel, r_sdp);
|
||||||
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
|
|
||||||
}
|
|
||||||
//switch_channel_pre_answer(other_channel);
|
//switch_channel_pre_answer(other_channel);
|
||||||
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_PROGRESS);
|
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_PROGRESS);
|
||||||
switch_core_session_rwunlock(other_session);
|
switch_core_session_rwunlock(other_session);
|
||||||
@ -6626,9 +6625,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
|||||||
other_channel = switch_core_session_get_channel(other_session);
|
other_channel = switch_core_session_get_channel(other_session);
|
||||||
//other_tech_pvt = switch_core_session_get_private(other_session);
|
//other_tech_pvt = switch_core_session_get_private(other_session);
|
||||||
|
|
||||||
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
|
switch_channel_pass_sdp(channel, other_channel, r_sdp);
|
||||||
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
|
|
||||||
}
|
|
||||||
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
|
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
|
||||||
switch_core_session_rwunlock(other_session);
|
switch_core_session_rwunlock(other_session);
|
||||||
}
|
}
|
||||||
@ -7114,10 +7111,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
|||||||
|
|
||||||
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||||
other_channel = switch_core_session_get_channel(other_session);
|
other_channel = switch_core_session_get_channel(other_session);
|
||||||
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
|
switch_channel_pass_sdp(channel, other_channel, r_sdp);
|
||||||
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
|
if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n");
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n");
|
||||||
sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
|
sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
|
||||||
@ -7218,10 +7213,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
|||||||
|
|
||||||
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||||
other_channel = switch_core_session_get_channel(other_session);
|
other_channel = switch_core_session_get_channel(other_session);
|
||||||
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
|
switch_channel_pass_sdp(channel, other_channel, r_sdp);
|
||||||
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
|
|
||||||
}
|
|
||||||
|
|
||||||
//switch_channel_answer(other_channel);
|
//switch_channel_answer(other_channel);
|
||||||
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
|
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
|
||||||
|
|
||||||
|
@ -2401,7 +2401,8 @@ static void pass_sdp(verto_pvt_t *tech_pvt)
|
|||||||
|
|
||||||
if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||||
other_channel = switch_core_session_get_channel(other_session);
|
other_channel = switch_core_session_get_channel(other_session);
|
||||||
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, tech_pvt->r_sdp);
|
switch_channel_pass_sdp(tech_pvt->channel, other_channel, tech_pvt->r_sdp);
|
||||||
|
|
||||||
switch_channel_set_flag(other_channel, CF_PROXY_MODE);
|
switch_channel_set_flag(other_channel, CF_PROXY_MODE);
|
||||||
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
|
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
|
||||||
switch_core_session_rwunlock(other_session);
|
switch_core_session_rwunlock(other_session);
|
||||||
|
@ -5220,6 +5220,65 @@ SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switc
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SWITCH_DECLARE(switch_status_t) switch_channel_pass_sdp(switch_channel_t *from_channel, switch_channel_t *to_channel, const char *sdp)
|
||||||
|
{
|
||||||
|
char *use_sdp = (char *) sdp;
|
||||||
|
char *patched_sdp = NULL;
|
||||||
|
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||||
|
|
||||||
|
if (!switch_channel_get_variable(to_channel, SWITCH_B_SDP_VARIABLE)) {
|
||||||
|
const char *var;
|
||||||
|
|
||||||
|
if ((var = switch_channel_get_variable(from_channel, "bypass_media_sdp_filter"))) {
|
||||||
|
char *cmd = switch_core_session_strdup(from_channel->session, var);
|
||||||
|
int argc = 0;
|
||||||
|
char *argv[50];
|
||||||
|
int x = 0;
|
||||||
|
|
||||||
|
argc = switch_split(cmd, '|', argv);
|
||||||
|
|
||||||
|
for (x = 0; x < argc; x++) {
|
||||||
|
char *command = argv[x];
|
||||||
|
char *arg = strchr(command, '(');
|
||||||
|
|
||||||
|
if (arg) {
|
||||||
|
char *e = switch_find_end_paren(arg, '(', ')');
|
||||||
|
*arg++ = '\0';
|
||||||
|
if (e) *e = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zstr(command) || zstr(arg)) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(from_channel), SWITCH_LOG_WARNING, "%s SDP FILTER PARSE ERROR\n", from_channel->name);
|
||||||
|
} else {
|
||||||
|
char *tmp_sdp = NULL;
|
||||||
|
|
||||||
|
if (patched_sdp) {
|
||||||
|
tmp_sdp = switch_core_media_filter_sdp(patched_sdp, command, arg);
|
||||||
|
} else {
|
||||||
|
tmp_sdp = switch_core_media_filter_sdp(use_sdp, command, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(from_channel), SWITCH_LOG_DEBUG,
|
||||||
|
"Filter command %s(%s)\nFROM:\n==========\n%s\nTO:\n==========\n%s\n\n",
|
||||||
|
command, arg, patched_sdp ? patched_sdp : use_sdp, tmp_sdp);
|
||||||
|
|
||||||
|
|
||||||
|
if (tmp_sdp) {
|
||||||
|
switch_safe_free(patched_sdp);
|
||||||
|
patched_sdp = use_sdp = tmp_sdp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_channel_set_variable(to_channel, SWITCH_B_SDP_VARIABLE, use_sdp);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_safe_free(patched_sdp);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/* For Emacs:
|
/* For Emacs:
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
|
@ -8854,6 +8854,220 @@ SWITCH_DECLARE(void) switch_core_media_deinit(void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int payload_number(const char *name)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(name, "pcmu")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "pcma")) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "gsm")) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "g722")) {
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "g729")) {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "dvi4")) {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "h261")) {
|
||||||
|
return 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(name, "h263")) {
|
||||||
|
return 34;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_pt(const char *sdp, const char *name)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
if ((p = switch_stristr(name, sdp))) {
|
||||||
|
if (p < end_of_p(sdp) && *(p+strlen(name)) == '/' && *(p-1) == ' ') {
|
||||||
|
p -= 2;
|
||||||
|
|
||||||
|
while(*p > 47 && *p < 58) {
|
||||||
|
p--;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
return atoi(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SWITCH_DECLARE(char *) switch_core_media_filter_sdp(const char *sdp_str, const char *cmd, const char *arg)
|
||||||
|
{
|
||||||
|
char *new_sdp = NULL;
|
||||||
|
int pt = -1, te = -1;
|
||||||
|
switch_size_t len;
|
||||||
|
const char *i;
|
||||||
|
char *o;
|
||||||
|
int in_m = 0, m_tally = 0, slash = 0;
|
||||||
|
int number = 0, skip = 0;
|
||||||
|
int remove = !strcasecmp(cmd, "remove");
|
||||||
|
int only = !strcasecmp(cmd, "only");
|
||||||
|
char *end = end_of_p((char *)sdp_str);
|
||||||
|
int tst;
|
||||||
|
end++;
|
||||||
|
|
||||||
|
|
||||||
|
if (remove || only) {
|
||||||
|
pt = payload_number(arg);
|
||||||
|
|
||||||
|
if (pt < 0) {
|
||||||
|
pt = find_pt(sdp_str, arg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (only) {
|
||||||
|
te = find_pt(sdp_str, "telephone-event");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
len = strlen(sdp_str);
|
||||||
|
new_sdp = malloc(len);
|
||||||
|
o = new_sdp;
|
||||||
|
i = sdp_str;
|
||||||
|
|
||||||
|
|
||||||
|
while(i && *i && i < end) {
|
||||||
|
|
||||||
|
if (*i == 'm' && *(i+1) == '=') {
|
||||||
|
in_m = 1;
|
||||||
|
m_tally++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_m) {
|
||||||
|
if (*i == '\r' || *i == '\n') {
|
||||||
|
in_m = 0;
|
||||||
|
slash = 0;
|
||||||
|
} else {
|
||||||
|
if (*i == '/') {
|
||||||
|
slash++;
|
||||||
|
while(*i != ' ' && i < end) {
|
||||||
|
*o++ = *i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*o++ = *i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slash && switch_is_leading_number(i)) {
|
||||||
|
|
||||||
|
|
||||||
|
number = atoi(i);
|
||||||
|
|
||||||
|
while(i < end && ((*i > 47 && *i < 58) || *i == ' ')) {
|
||||||
|
|
||||||
|
if (remove) {
|
||||||
|
tst = (number != pt);
|
||||||
|
} else {
|
||||||
|
tst = (number == pt || number == te);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tst) {
|
||||||
|
*o++ = *i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (*i == ' ') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove) {
|
||||||
|
tst = (number == pt);
|
||||||
|
} else {
|
||||||
|
tst = (number != pt && number != te);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tst) {
|
||||||
|
skip++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < end && !strncasecmp(i, "a=rtpmap:", 9)) {
|
||||||
|
const char *t = i + 9;
|
||||||
|
|
||||||
|
number = atoi(t);
|
||||||
|
|
||||||
|
if (remove) {
|
||||||
|
tst = (number == pt);
|
||||||
|
} else {
|
||||||
|
tst = (number != pt && number != te);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(i < end && (*i != '\r' && *i != '\n')) {
|
||||||
|
if (!tst) *o++ = *i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(i < end && (*i == '\r' || *i == '\n')) {
|
||||||
|
if (!tst) *o++ = *i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < end && !strncasecmp(i, "a=fmtp:", 7)) {
|
||||||
|
const char *t = i + 7;
|
||||||
|
|
||||||
|
number = atoi(t);
|
||||||
|
|
||||||
|
if (remove) {
|
||||||
|
tst = (number == pt);
|
||||||
|
} else {
|
||||||
|
tst = (number != pt && number != te);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(i < end && (*i != '\r' && *i != '\n')) {
|
||||||
|
if (!tst) *o++ = *i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(i < end && (*i == '\r' || *i == '\n')) {
|
||||||
|
if (!tst) *o++ = *i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skip) {
|
||||||
|
*o++ = *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip = 0;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*o = '\0';
|
||||||
|
|
||||||
|
return new_sdp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* For Emacs:
|
/* For Emacs:
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
|
@ -654,7 +654,7 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) {
|
if ((val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) {
|
||||||
switch_channel_set_variable(peer_channel, SWITCH_B_SDP_VARIABLE, val);
|
switch_channel_pass_sdp(channel, peer_channel, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
|
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
|
||||||
|
@ -1231,6 +1231,25 @@ SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SWITCH_DECLARE(switch_bool_t) switch_is_leading_number(const char *str)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
switch_bool_t r = SWITCH_FALSE;
|
||||||
|
|
||||||
|
if (*str == '-' || *str == '+') {
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p = str; p && *p; p++) {
|
||||||
|
if ((*p == '.' || (*p > 47 && *p < 58))) {
|
||||||
|
r = SWITCH_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
SWITCH_DECLARE(const char *) switch_stristr(const char *instr, const char *str)
|
SWITCH_DECLARE(const char *) switch_stristr(const char *instr, const char *str)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user