Merge branch 'master' into davidy_test
This commit is contained in:
commit
d7141be3bc
|
@ -1950,7 +1950,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
|
|||
ftdm_channel_lock(ftdmchan);
|
||||
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already terminating\n");
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already TERMINATING\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -1962,14 +1962,27 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
|
|||
goto done;
|
||||
}
|
||||
|
||||
|
||||
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
|
||||
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
|
||||
}
|
||||
|
||||
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
|
||||
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
|
||||
}
|
||||
|
||||
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
|
||||
|
||||
done:
|
||||
|
@ -2011,6 +2024,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file,
|
|||
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
|
||||
call_hangup(ftdmchan, file, func, line);
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
return FTDM_SUCCESS;
|
||||
|
@ -2084,8 +2098,13 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
|
|||
{
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
switch (indication) {
|
||||
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (indication) {
|
||||
/* FIXME: ring and busy cannot be used with all signaling stacks
|
||||
* (particularly isdn stacks I think, we should emulate or just move to hangup with busy cause) */
|
||||
case FTDM_CHANNEL_INDICATE_RING:
|
||||
|
@ -2112,6 +2131,13 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
|
|||
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
|
||||
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
|
||||
}
|
||||
|
||||
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
|
||||
}
|
||||
break;
|
||||
|
@ -2122,6 +2148,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
|
|||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
|
|
|
@ -78,8 +78,8 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
|||
{
|
||||
SS7_FUNC_TRACE_ENTER(__FUNCTION__);
|
||||
|
||||
sngss7_chan_data_t *sngss7_info ;
|
||||
ftdm_channel_t *ftdmchan;
|
||||
sngss7_chan_data_t *sngss7_info = NULL;
|
||||
ftdm_channel_t *ftdmchan = NULL;
|
||||
|
||||
/* get the ftdmchan and ss7_chan_data from the circuit */
|
||||
if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) {
|
||||
|
@ -121,14 +121,14 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
|||
/* check whether the ftdm channel is in a state to accept a call */
|
||||
switch (ftdmchan->state) {
|
||||
/**************************************************************************/
|
||||
case (FTDM_CHANNEL_STATE_DOWN): /* only state it is fully valid to get IAM */
|
||||
case (FTDM_CHANNEL_STATE_DOWN): /* only state it is valid to get IAM (except if there is glare */
|
||||
|
||||
/* fill in the channels SS7 Stack information */
|
||||
sngss7_info->suInstId = get_unique_id();
|
||||
sngss7_info->spInstId = spInstId;
|
||||
|
||||
/* try to open the ftdm channel */
|
||||
if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
|
||||
/* check if there is any reason why we can't use this channel */
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
|
||||
/* channel is already requested for use by the ftdm core */
|
||||
goto handle_glare;
|
||||
} else if(ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
|
||||
/* channel is not inuse but we can't open it...fail the call */
|
||||
SS7_ERROR("Failed to open span: %d, chan: %d\n",
|
||||
ftdmchan->physical_span_id,
|
||||
ftdmchan->physical_chan_id);
|
||||
|
@ -143,6 +143,10 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
|||
|
||||
} else {
|
||||
|
||||
/* fill in the channels SS7 Stack information */
|
||||
sngss7_info->suInstId = get_unique_id();
|
||||
sngss7_info->spInstId = spInstId;
|
||||
|
||||
/* fill in calling party information */
|
||||
if (siConEvnt->cgPtyNum.eh.pres) {
|
||||
if (siConEvnt->cgPtyNum.addrSig.pres) {
|
||||
|
@ -211,7 +215,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
|||
/* set the state of the channel to collecting...the rest is done by the chan monitor */
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
|
||||
|
||||
} /* if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) */
|
||||
} /* if (channel is usable */
|
||||
|
||||
break;
|
||||
/**************************************************************************/
|
||||
|
@ -219,8 +223,11 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
|||
case (FTDM_CHANNEL_STATE_TERMINATING):
|
||||
case (FTDM_CHANNEL_STATE_HANGUP):
|
||||
case (FTDM_CHANNEL_STATE_HANGUP_COMPLETE):
|
||||
|
||||
SS7_INFO_CHAN(ftdmchan, "Got IAM on channel in %s state...glare!\n", ftdm_channel_state2str (ftdmchan->state));
|
||||
handle_glare:
|
||||
/* the core already has plans for this channel...glare */
|
||||
SS7_INFO_CHAN(ftdmchan, "Got IAM on channel that is already inuse (state=%s|inuse=%d)...glare!\n",
|
||||
ftdm_channel_state2str (ftdmchan->state),
|
||||
ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE));
|
||||
|
||||
/* save the info so that we can use it later on */
|
||||
sngss7_info->glare.spInstId = spInstId;
|
||||
|
@ -239,8 +246,7 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
|||
|
||||
/* move the state of the channel to Terminating to end the call */
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
|
||||
}
|
||||
|
||||
} /* if (!(sngss7_test_flag(sngss7_info, FLAG_GLARE))) */
|
||||
break;
|
||||
/**************************************************************************/
|
||||
default: /* should not have gotten an IAM while in this state */
|
||||
|
|
|
@ -1391,9 +1391,13 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
|
|||
|
||||
switch_assert(listener != NULL);
|
||||
|
||||
#if MOD_SKINNY_NONBLOCK
|
||||
switch_socket_opt_set(listener->sock, SWITCH_SO_TCP_NODELAY, TRUE);
|
||||
switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE);
|
||||
|
||||
#else
|
||||
switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, FALSE);
|
||||
switch_socket_timeout_set(listener->sock, 5000000);
|
||||
#endif
|
||||
if (listener->profile->debug > 0) {
|
||||
if (zstr(listener->remote_ip)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Open\n");
|
||||
|
@ -1402,7 +1406,6 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
|
|||
}
|
||||
}
|
||||
|
||||
switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE);
|
||||
switch_set_flag_locked(listener, LFLAG_RUNNING);
|
||||
keepalive_listener(listener, NULL);
|
||||
add_listener(listener);
|
||||
|
@ -1413,8 +1416,6 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
|
|||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch(status) {
|
||||
case SWITCH_STATUS_BREAK:
|
||||
break;
|
||||
case SWITCH_STATUS_TIMEOUT:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Communication Time Out with %s:%d.\n",
|
||||
listener->remote_ip, listener->remote_port);
|
||||
|
|
|
@ -118,10 +118,6 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req)
|
|||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
if (!listener_is_ready(listener)) {
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
ptr = mbuf;
|
||||
|
||||
while (listener_is_ready(listener)) {
|
||||
|
@ -137,10 +133,10 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req)
|
|||
status = switch_socket_recv(listener->sock, ptr, &mlen);
|
||||
|
||||
if (!listener_is_ready(listener)) {
|
||||
return SWITCH_STATUS_BREAK;
|
||||
break;
|
||||
}
|
||||
if (!SWITCH_STATUS_IS_BREAK(status) && status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Socket break.\n");
|
||||
if ((status != 70007 /* APR_TIMEUP */) && !SWITCH_STATUS_IS_BREAK(status) && (status != SWITCH_STATUS_SUCCESS)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Socket break with status=%d.\n", status);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -3300,7 +3300,6 @@ SWITCH_STANDARD_API(sofia_contact_function)
|
|||
char *p;
|
||||
sofia_profile_t *profile = NULL;
|
||||
const char *exclude_contact = NULL;
|
||||
const char *user_replacement = NULL;
|
||||
char *reply = "error/facility_not_subscribed";
|
||||
|
||||
if (!cmd) {
|
||||
|
@ -3311,7 +3310,6 @@ SWITCH_STANDARD_API(sofia_contact_function)
|
|||
if (session) {
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
exclude_contact = switch_channel_get_variable(channel, "sip_exclude_contact");
|
||||
user_replacement = switch_channel_get_variable(channel, "sip_contact_user_replacement");
|
||||
}
|
||||
|
||||
|
||||
|
@ -3390,93 +3388,6 @@ SWITCH_STANDARD_API(sofia_contact_function)
|
|||
reply = "error/user_not_registered";
|
||||
}
|
||||
|
||||
if (user_replacement) {
|
||||
int urlcount = 0;
|
||||
int copyerr = 0;
|
||||
char *newreply = NULL;
|
||||
char *urlstart = NULL;
|
||||
char *newptr = NULL;
|
||||
char *bufend = NULL;
|
||||
char *str = reply;
|
||||
switch_size_t copysize = 0;
|
||||
switch_size_t replacesize = strlen(user_replacement);
|
||||
switch_size_t allocsize = 0;
|
||||
|
||||
/* first pass to count how many URLs we have */
|
||||
while ((urlstart = strcasestr(str, "sip:")) || (urlstart = strcasestr(str, "sips:"))) {
|
||||
urlcount++;
|
||||
str = urlstart + 4;
|
||||
}
|
||||
|
||||
if (!urlcount) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): no sip URLs found to replace the user\n");
|
||||
copyerr++;
|
||||
goto copydone;
|
||||
}
|
||||
|
||||
/* this allocates a bit more than needed but better safe than sorry doing more funky math */
|
||||
allocsize = strlen(reply) + (urlcount * replacesize);
|
||||
newreply = switch_core_session_alloc(session, allocsize);
|
||||
if (!newreply) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): no buffer space available for replacement\n");
|
||||
copyerr++;
|
||||
goto copydone;
|
||||
}
|
||||
|
||||
/* get a working pointer to the new reply */
|
||||
newptr = newreply;
|
||||
|
||||
/* pointer to the end of the allocated buffer for safety checks */
|
||||
bufend = newreply + allocsize - 1;
|
||||
*bufend = 0;
|
||||
|
||||
/* go thru all the urls and replace the user part */
|
||||
str = reply;
|
||||
while ((urlstart = strcasestr(str, "sip:")) || (urlstart = strcasestr(str, "sips:"))) {
|
||||
|
||||
/* found an URL, copy up to the start of the url */
|
||||
copysize = ( urlstart - str ) + 4;
|
||||
|
||||
/* double check boundaries before copying anything at all (this should not happen) */
|
||||
if ((newptr + copysize + replacesize) >= bufend) {
|
||||
copyerr++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): wow buffer was not big enough!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy the original contact string except for the user */
|
||||
memcpy(newptr, str, copysize);
|
||||
newptr += copysize;
|
||||
|
||||
/* copy the user replacement */
|
||||
memcpy(newptr, user_replacement, replacesize);
|
||||
newptr += replacesize;
|
||||
|
||||
/* skip the original user part */
|
||||
str = strchr(urlstart, '@');
|
||||
if (!str) {
|
||||
copyerr++;
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): not host part found for contact\n");
|
||||
break;
|
||||
}
|
||||
/* continue searching for the next sip: URL */
|
||||
}
|
||||
|
||||
copydone:
|
||||
if (!copyerr) {
|
||||
/* copy the remaining reply string */
|
||||
copysize = strlen(str);
|
||||
if ((newptr + copysize) >= bufend) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "sofia_contact(): wow buffer was not big enough, close, but not enough!\n");
|
||||
} else {
|
||||
strcpy(newptr, str);
|
||||
reply = newreply;
|
||||
}
|
||||
} else {
|
||||
reply = "error/replacement error";
|
||||
}
|
||||
}
|
||||
|
||||
stream->write_function(stream, "%s", reply);
|
||||
reply = NULL;
|
||||
|
||||
|
|
|
@ -1007,3 +1007,4 @@ switch_t38_options_t *sofia_glue_extract_t38_options(switch_core_session_t *sess
|
|||
char *sofia_glue_get_multipart(switch_core_session_t *session, const char *prefix, const char *sdp, char **mp_type);
|
||||
void sofia_glue_tech_simplify(private_object_t *tech_pvt);
|
||||
switch_console_callback_match_t *sofia_reg_find_reg_url_multi(sofia_profile_t *profile, const char *user, const char *host);
|
||||
switch_bool_t sofia_glue_profile_exists(const char *key);
|
||||
|
|
|
@ -4174,6 +4174,19 @@ switch_status_t sofia_glue_profile_rdlock__(const char *file, const char *func,
|
|||
return status;
|
||||
}
|
||||
|
||||
switch_bool_t sofia_glue_profile_exists(const char *key)
|
||||
{
|
||||
switch_bool_t tf = SWITCH_FALSE;
|
||||
|
||||
switch_mutex_lock(mod_sofia_globals.hash_mutex);
|
||||
if (switch_core_hash_find(mod_sofia_globals.profile_hash, key)) {
|
||||
tf = SWITCH_TRUE;
|
||||
}
|
||||
switch_mutex_unlock(mod_sofia_globals.hash_mutex);
|
||||
|
||||
return tf;
|
||||
}
|
||||
|
||||
sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, const char *key)
|
||||
{
|
||||
sofia_profile_t *profile;
|
||||
|
|
|
@ -1179,20 +1179,13 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
|
|||
switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET);
|
||||
|
||||
if (profile->reg_db_domain) {
|
||||
sofia_profile_t *xprofile;
|
||||
|
||||
if ((xprofile = sofia_glue_find_profile(to_host))) {
|
||||
sofia_glue_release_profile(xprofile);
|
||||
} else {
|
||||
|
||||
if (!sofia_glue_profile_exists(to_host)) {
|
||||
if (sofia_glue_add_profile(switch_core_strdup(profile->pool, to_host), profile) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Auto-Adding Alias [%s] for profile [%s]\n", to_host, profile->name);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Alias [%s] for profile [%s] (already exists)\n",
|
||||
to_host, profile->name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -574,7 +574,7 @@ SWITCH_DECLARE(const char *) switch_dir_next_file(switch_dir_t *thedir, char *bu
|
|||
|
||||
while (apr_dir_read(&(thedir->finfo), finfo_flags, thedir->dir_handle) == SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
if (thedir->finfo.filetype != APR_REG) {
|
||||
if (thedir->finfo.filetype != APR_REG && thedir->finfo.filetype != APR_LNK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1539,7 +1539,7 @@ static void switch_load_core_config(const char *file)
|
|||
SWITCH_DECLARE(const char *) switch_core_banner(void)
|
||||
{
|
||||
|
||||
#if 0
|
||||
|
||||
return ("\n"
|
||||
" _____ ______ _____ _____ ____ _ _ \n"
|
||||
" | ___| __ ___ ___/ ___\\ \\ / /_ _|_ _/ ___| | | | \n"
|
||||
|
@ -1552,20 +1552,6 @@ SWITCH_DECLARE(const char *) switch_core_banner(void)
|
|||
"* FreeSWITCH (http://www.freeswitch.org) *\n"
|
||||
"* Paypal Donations Appreciated: paypal@freeswitch.org *\n"
|
||||
"* Brought to you by ClueCon http://www.cluecon.com/ *\n" "************************************************************\n" "\n");
|
||||
#else
|
||||
return (
|
||||
"\n _____ ___ ___ _ _ _____ _ \n"
|
||||
"/ ___| | \\/ | | (_) | __ \\ | | \n"
|
||||
"\\ `--. __ _ _ __ __ _ ___ _ __ ___ __ _ | . . | ___ __| |_ __ _ | | \\/ __ _| |_ _____ ____ _ _ _ \n"
|
||||
" `--. \\/ _` | '_ \\ / _` |/ _ \\| '_ ` _ \\ / _` | | |\\/| |/ _ \\/ _` | |/ _` | | | __ / _` | __|/ _ \\ \\ /\\ / / _` | | | |\n"
|
||||
"/\\__/ / (_| | | | | (_| | (_) | | | | | | (_| | | | | | __/ (_| | | (_| | | |_\\ \\ (_| | |_| __/\\ V V / (_| | |_| |\n"
|
||||
"\\____/ \\__,_|_| |_|\\__, |\\___/|_| |_| |_|\\__,_| \\_| |_/\\___|\\__,_|_|\\__,_| \\____/\\__,_|\\__|\\___| \\_/\\_/ \\__,_|\\__, |\n"
|
||||
" __/ | __/ |\n"
|
||||
" |___/ |___/ \n"
|
||||
"************************************************************\n"
|
||||
"* Powered by: FreeSWITCH (http://www.freeswitch.org) *\n"
|
||||
"************************************************************\n" "\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue