提交 0d23976f authored 作者: Anthony Minessale's avatar Anthony Minessale

Insane amounts of yucky satanic code to make transfer and that kind of thing work.
Transfers work better when both legs of the call live in thier own channel eg bridged calls
A -> B where you want a to make B -> C

when you route a call to an IVR or playback app you are not really bridging you have
A all alone executing the script so it's hard to transfer that.

I do have it aparently working but it's goofy and you are better off
putting your IVR on it's own switch so they are all inbound calls
then you have A -> B -> IVR
now A can happily transfer B who can stay on line with IVR without stopping
the execution.  You can also accomplish this by calling in a loop back to the same box
if you dont want to have 2 boxes.


Also the beginning effort at bridging calls with no media is here
set this magic variable in your dialplan to convince mod_sofia
to pass A's sdp as it's own to B and return B's sdp back to A on 200 or 183

<action application="set" data="no_media=true"/>
<action application="bridge" data="sofia/id@host.com"/>

You will need a new sofia tarball for this version


There is a bunch of other odds and ends added like a function or 2 etc
Oh,

And don't be suprised if it introduces all kinds of bugs!



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2992 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 d7959131
......@@ -223,6 +223,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
void *session_data,
void *peer_session_data);
/*!
\brief Bridge Signalling from one session to another
\param session one session
\param peer_session the other session
\return SWITCH_STATUS_SUCCESS if all is well
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *session, switch_core_session_t *peer_session);
/*!
\brief Transfer an existing session to another location
......
......@@ -72,6 +72,11 @@ SWITCH_BEGIN_EXTERN_C
#define SWITCH_HTDOCS_DIR SWITCH_PREFIX_DIR SWITCH_PATH_SEPARATOR "htdocs"
#endif
#define SWITCH_R_SDP_VARIABLE "_switch_r_sdp_"
#define SWITCH_L_SDP_VARIABLE "_switch_l_sdp_"
#define SWITCH_BRIDGE_VARIABLE "BRIDGETO"
#define SWITCH_SIGNAL_BRIDGE_VARIABLE "SIGNAL_BRIDGETO"
#define SWITCH_BITS_PER_BYTE 8
typedef uint8_t switch_byte_t;
......@@ -232,7 +237,8 @@ typedef enum {
SWITCH_MESSAGE_TRANSMIT_TEXT - A text message
SWITCH_MESSAGE_INDICATE_PROGRESS - indicate progress
SWITCH_MESSAGE_INDICATE_BRIDGE - indicate a bridge starting
SWITCH_MESSAGE_INDICATE_UNBRIDGE - indicate a bridge ending
SWITCH_MESSAGE_INDICATE_UNBRIDGE - indicate a bridge ending
SWITCH_MESSAGE_INDICATE_TRANSFER - indicate a transfer is taking place
</pre>
*/
typedef enum {
......@@ -240,7 +246,8 @@ typedef enum {
SWITCH_MESSAGE_TRANSMIT_TEXT,
SWITCH_MESSAGE_INDICATE_PROGRESS,
SWITCH_MESSAGE_INDICATE_BRIDGE,
SWITCH_MESSAGE_INDICATE_UNBRIDGE
SWITCH_MESSAGE_INDICATE_UNBRIDGE,
SWITCH_MESSAGE_INDICATE_TRANSFER
} switch_core_session_message_types_t;
......@@ -392,6 +399,7 @@ CF_SERVICE = (1 << 9) - Channel has a service thread
CF_TAGGED = (1 << 10) - Channel is tagged
CF_WINNER = (1 << 11) - Channel is the winner
CF_CONTROLLED = (1 << 12) - Channel is under control
CF_NOMEDIA = (1 << 13) - Channel has no media
</pre>
*/
......@@ -408,7 +416,8 @@ typedef enum {
CF_SERVICE = (1 << 9),
CF_TAGGED = (1 << 10),
CF_WINNER = (1 << 11),
CF_CONTROLLED = (1 << 12)
CF_CONTROLLED = (1 << 12),
CF_NOMEDIA = (1 << 13)
} switch_channel_flag_t;
......
......@@ -192,6 +192,16 @@ if (vname) {free(vname); vname = NULL;}vname = strdup(string);}
*/
SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen);
/*!
\brief Escape a string by prefixing a list of characters with an escape character
\param pool a memory pool to use
\param in the string
\param delim the list of characters to escape
\param esc the escape character
\return the escaped string
*/
SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, char *delim, char esc);
/*!
\brief Create a set of file descriptors to poll
\param poll the polfd to create
......
......@@ -51,23 +51,32 @@ static void audio_bridge_function(switch_core_session_t *session, char *data)
timelimit = atoi(var);
}
if ((var = switch_channel_get_variable(caller_channel, "no_media"))) {
switch_channel_set_flag(caller_channel, CF_NOMEDIA);
}
if (switch_ivr_originate(session, &peer_session, &cause, data, timelimit, NULL, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel!\n");
/* Hangup the channel with the cause code from the failed originate.*/
switch_channel_hangup(caller_channel, cause);
return;
} else {
switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL);
if (switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
switch_ivr_signal_bridge(session, peer_session);
} else {
switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL);
}
}
}
static const switch_application_interface_t bridge_application_interface = {
/*.interface_name */ "bridge",
/*.application_function */ audio_bridge_function
/*.application_function */ audio_bridge_function,
/* long_desc */ "Bridge the audio between two sessions",
/* short_desc */ "Bridge Audio",
/* syntax */ "<channel_url>",
};
static const switch_loadable_module_interface_t mod_bridgecall_module_interface = {
/*.module_name = */ modname,
/*.endpoint_interface = */ NULL,
......
......@@ -145,55 +145,55 @@ SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_
if (caller_profile->username) {
snprintf(header_name, sizeof(header_name), "%s-Username", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->username);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->username);
}
if (caller_profile->dialplan) {
snprintf(header_name, sizeof(header_name), "%s-Dialplan", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->dialplan);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->dialplan);
}
if (caller_profile->caller_id_name) {
snprintf(header_name, sizeof(header_name), "%s-Caller-ID-Name", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->caller_id_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->caller_id_name);
}
if (caller_profile->caller_id_number) {
snprintf(header_name, sizeof(header_name), "%s-Caller-ID-Number", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->caller_id_number);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->caller_id_number);
}
if (caller_profile->network_addr) {
snprintf(header_name, sizeof(header_name), "%s-Network-Addr", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->network_addr);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->network_addr);
}
if (caller_profile->ani) {
snprintf(header_name, sizeof(header_name), "%s-ANI", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->ani);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->ani);
}
if (caller_profile->ani2) {
snprintf(header_name, sizeof(header_name), "%s-ANI2", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->ani2);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->ani2);
}
if (caller_profile->destination_number) {
snprintf(header_name, sizeof(header_name), "%s-Destination-Number", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->destination_number);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->destination_number);
}
if (caller_profile->uuid) {
snprintf(header_name, sizeof(header_name), "%s-Unique-ID", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->uuid);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->uuid);
}
if (caller_profile->source) {
snprintf(header_name, sizeof(header_name), "%s-Source", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->source);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->source);
}
if (caller_profile->context) {
snprintf(header_name, sizeof(header_name), "%s-Context", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->context);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->context);
}
if (caller_profile->rdnis) {
snprintf(header_name, sizeof(header_name), "%s-RDNIS", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->rdnis);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->rdnis);
}
if (caller_profile->chan_name) {
snprintf(header_name, sizeof(header_name), "%s-Channel-Name", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->chan_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->chan_name);
}
}
......
......@@ -88,7 +88,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_stream_write(switch_stream_handle
ret = -1;
} else {
ret = 0;
snprintf(end, remaining, data);
snprintf(end, remaining, "%s", data);
handle->data_len = strlen(buf);
handle->end = (uint8_t *)(handle->data) + handle->data_len;
}
......
......@@ -2456,8 +2456,8 @@ static void switch_core_standard_on_execute(switch_core_session_t *session)
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(session->channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", extension->current_application->application_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", extension->current_application->application_data);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "%s", extension->current_application->application_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", extension->current_application->application_data);
switch_event_fire(&event);
}
application_interface->application_function(session, extension->current_application->application_data);
......
......@@ -1372,7 +1372,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
msg.from = __FILE__;
switch_core_session_receive_message(session_a, &msg);
switch_channel_set_variable(chan_a, "BRIDGETO", NULL);
switch_channel_set_variable(chan_a, SWITCH_BRIDGE_VARIABLE, NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BRIDGE THREAD DONE [%s]\n", switch_channel_get_name(chan_a));
switch_channel_clear_flag(chan_a, CF_BRIDGED);
......@@ -1514,14 +1514,14 @@ static switch_status_t uuid_bridge_on_transmit(switch_core_session_t *session)
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(other_session));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(other_session));
switch_event_fire(&event);
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(other_channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(session));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(session));
switch_event_fire(&event);
}
......@@ -1912,7 +1912,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
endfor1:
if (session) {
if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
switch_codec_t *read_codec = NULL;
switch_channel_pre_answer(caller_channel);
......@@ -1946,7 +1946,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
check_channel_status(peer_channels, peer_sessions, argc, &idx, file, key) && ((time(NULL) - start) < (time_t)timelimit_sec)) {
/* read from the channel while we wait if the audio is up on it */
if (session && (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA))) {
if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA) &&
(switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA))) {
switch_status_t status = switch_core_session_read_frame(session, &read_frame, 1000, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
......@@ -1964,7 +1965,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
if (session) {
if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
switch_core_session_reset(session);
}
......@@ -1987,6 +1988,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
if (caller_channel && switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
char *val;
if (switch_channel_test_flag(peer_channel, CF_NOMEDIA) && (val = switch_channel_get_variable(peer_channel, SWITCH_R_SDP_VARIABLE))) {
switch_channel_set_variable(caller_channel, SWITCH_L_SDP_VARIABLE, val);
}
switch_channel_answer(caller_channel);
}
......@@ -2042,6 +2048,100 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session)
{
char *uuid;
switch_channel_t *channel = NULL;
switch_core_session_t *other_session;
switch_event_t *event;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if (switch_channel_test_flag(channel, CF_ORIGINATOR)) {
switch_channel_clear_flag(channel, CF_ORIGINATOR);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
}
}
if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
switch_channel_t *other_channel = NULL;
other_channel = switch_core_session_get_channel(other_session);
assert(other_channel != NULL);
switch_channel_hangup(other_channel, switch_channel_get_cause(channel));
switch_core_session_rwunlock(other_session);
}
return SWITCH_STATUS_SUCCESS;
}
static const switch_state_handler_table_t signal_bridge_state_handlers = {
/*.on_init */ NULL,
/*.on_ring */ NULL,
/*.on_execute */ NULL,
/*.on_hangup */ signal_bridge_on_hangup,
/*.on_loopback */ NULL,
/*.on_transmit */ NULL,
/*.on_hold */ NULL
};
SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *session, switch_core_session_t *peer_session)
{
switch_channel_t *caller_channel, *peer_channel;
switch_event_t *event;
caller_channel = switch_core_session_get_channel(session);
assert(caller_channel != NULL);
switch_channel_set_flag(caller_channel, CF_ORIGINATOR);
peer_channel = switch_core_session_get_channel(peer_session);
assert(peer_channel != NULL);
switch_channel_set_variable(caller_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session));
switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(session));
switch_channel_clear_state_handler(caller_channel, NULL);
switch_channel_clear_state_handler(peer_channel, NULL);
switch_channel_add_state_handler(caller_channel, &signal_bridge_state_handlers);
switch_channel_add_state_handler(peer_channel, &signal_bridge_state_handlers);
/* fire events that will change the data table from "show channels" */
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "signal_bridge");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(peer_session));
switch_event_fire(&event);
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(peer_channel, event);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "signal_bridge");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(session));
switch_event_fire(&event);
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
switch_event_fire(&event);
}
switch_channel_set_state(caller_channel, CS_TRANSMIT);
switch_channel_set_state(peer_channel, CS_TRANSMIT);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_session_t *session,
switch_core_session_t *peer_session,
switch_input_callback_function_t input_callback,
......@@ -2102,18 +2202,32 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
switch_event_fire(&event);
}
msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
msg.from = __FILE__;
msg.pointer_arg = session;
if (switch_core_session_read_lock(peer_session) == SWITCH_STATUS_SUCCESS) {
switch_channel_set_variable(caller_channel, SWITCH_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session));
switch_channel_set_variable(peer_channel, SWITCH_BRIDGE_VARIABLE, switch_core_session_get_uuid(session));
switch_core_session_receive_message(peer_session, &msg);
msg.pointer_arg = peer_session;
switch_core_session_receive_message(session, &msg);
msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
msg.from = __FILE__;
msg.pointer_arg = session;
if (switch_core_session_read_lock(peer_session) == SWITCH_STATUS_SUCCESS) {
switch_channel_set_variable(caller_channel, "BRIDGETO", switch_core_session_get_uuid(peer_session));
switch_channel_set_variable(peer_channel, "BRIDGETO", switch_core_session_get_uuid(session));
switch_core_session_receive_message(peer_session, &msg);
if (!msg.pointer_arg) {
status = SWITCH_STATUS_FALSE;
switch_core_session_rwunlock(peer_session);
goto done;
}
msg.pointer_arg = peer_session;
switch_core_session_receive_message(session, &msg);
if (!msg.pointer_arg) {
status = SWITCH_STATUS_FALSE;
switch_core_session_rwunlock(peer_session);
goto done;
}
switch_channel_set_private(peer_channel, "_bridge_", other_audio_thread);
switch_channel_set_state(peer_channel, CS_LOOPBACK);
audio_bridge_thread(NULL, (void *) this_audio_thread);
......@@ -2164,6 +2278,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER);
}
done:
return status;
}
......@@ -2219,6 +2334,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
{
switch_channel_t *channel;
switch_caller_profile_t *profile, *new_profile;
switch_core_session_message_t msg = {0};
assert(session != NULL);
assert(extension != NULL);
......@@ -2245,6 +2361,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
switch_channel_set_caller_profile(channel, new_profile);
switch_channel_set_flag(channel, CF_TRANSFER);
switch_channel_set_state(channel, CS_RING);
msg.message_id = SWITCH_MESSAGE_INDICATE_TRANSFER;
msg.from = __FILE__;
switch_core_session_receive_message(session, &msg);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Transfer %s to %s[%s@%s]\n",
switch_channel_get_name(channel), dialplan, extension, context);
return SWITCH_STATUS_SUCCESS;
......
......@@ -329,6 +329,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
return SWITCH_STATUS_SOCKERR;
}
if (switch_socket_opt_set(rtp_session->sock, SWITCH_SO_REUSEADDR, 1) != SWITCH_STATUS_SUCCESS) {
*err = "Socket Error!";
return SWITCH_STATUS_FALSE;
}
if (switch_socket_bind(rtp_session->sock, rtp_session->local_addr) != SWITCH_STATUS_SUCCESS) {
*err = "Bind Error!";
return SWITCH_STATUS_FALSE;
......
......@@ -72,6 +72,45 @@ SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key)
return '\0';
}
SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, char *delim, char esc)
{
char *data, *p, *d;
int count = 1, i = 0;
p = in;
while(*p) {
d = delim;
while (*d) {
if (*p == *d) {
count++;
}
d++;
}
p++;
}
if (count == 1) {
return in;
}
data = switch_core_alloc(pool, strlen(in) + count);
p = in;
while(*p) {
d = delim;
while (*d) {
if (*p == *d) {
data[i++] = esc;
}
d++;
}
data[i++] = *p;
p++;
}
return data;
}
SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen)
{
int argc;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论