mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-24 13:12:03 +00:00
ENUM Support
mod_enum can be used as a dialplan app, an api call from the console or as a dialplan interface.
Dialplan Interface:
put enum as the dialplan parameter in an endpoint module
i.e. instead of "XML" set it to "enum" or "enum,XML" for fall through.
Dialplan App:
This example will do a lookup and set the a variable that is the proper
dialstring to call all of the possible routes in order of preference according to
the lookup and the order of the routes in the enum.conf section.
<extension name="tollfree">
<condition field="destination_number" expression="^(18(0{2}|8{2}|7{2}|6{2})\d{7})$">
<action application="enum" data="$1"/>
<action application="bridge" data="${enum_auto_route}"/>
</condition>
</extension>
You can also pick an alrernate root:
<action application="enum" data="$1 myroot.org"/>
API command:
at the console you can say:
enum <number> [<root>]
The root always defaults to the one in the enum.conf section.
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3494 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
@@ -86,6 +86,8 @@ SWITCH_BEGIN_EXTERN_C
|
||||
#define SWITCH_LOCAL_MEDIA_PORT_VARIABLE "_local_media_port_"
|
||||
#define SWITCH_REMOTE_MEDIA_IP_VARIABLE "_remote_media_ip_"
|
||||
#define SWITCH_REMOTE_MEDIA_PORT_VARIABLE "_remote_media_port_"
|
||||
#define SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE "hangup_after_bridge"
|
||||
|
||||
#define SWITCH_SPEECH_KEY "_speech_"
|
||||
#define SWITCH_UUID_BRIDGE "_uuid_bridge_"
|
||||
#define SWITCH_BITS_PER_BYTE 8
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#define SWITCH_UTILS_H
|
||||
|
||||
#include <switch.h>
|
||||
#include <pcre.h>
|
||||
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
|
||||
@@ -231,8 +232,15 @@ SWITCH_DECLARE(int) switch_socket_waitfor(switch_pollfd_t *poll, int ms);
|
||||
*/
|
||||
SWITCH_DECLARE(char *) switch_cut_path(char *in);
|
||||
|
||||
#define switch_clean_re(re) if (re) {\
|
||||
pcre_free(re);\
|
||||
re = NULL;\
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(char *) switch_string_replace(const char *string, const char *search, const char *replace);
|
||||
SWITCH_DECLARE(switch_status_t) switch_string_match(const char *string, size_t string_len, const char *search, size_t search_len);
|
||||
SWITCH_DECLARE(int) switch_perform_regex(char *field, char *expression, pcre **new_re, int *ovector, uint32_t olen);
|
||||
SWITCH_DECLARE(void) switch_perform_substitution(pcre *re, int match_count, char *data, char *field_data, char *substituted, uint32_t len, int *ovector);
|
||||
|
||||
#define SWITCH_READ_ACCEPTABLE(status) status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK
|
||||
SWITCH_DECLARE(size_t) switch_url_encode(char *url, char *buf, size_t len);
|
||||
|
||||
@@ -45,6 +45,10 @@ static void audio_bridge_function(switch_core_session_t *session, char *data)
|
||||
uint8_t no_media_bridge = 0;
|
||||
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
|
||||
|
||||
if (switch_strlen_zero(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
caller_channel = switch_core_session_get_channel(session);
|
||||
assert(caller_channel != NULL);
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ static switch_status_t switch_gsm_decode(switch_codec_t *codec, switch_codec_t *
|
||||
static const switch_codec_implementation_t gsm_8k_implementation = {
|
||||
/*.codec_type */ SWITCH_CODEC_TYPE_AUDIO,
|
||||
/*.ianacode */ 3,
|
||||
/*.iananame */ "gsm",
|
||||
/*.iananame */ "GSM",
|
||||
/*.fmtp */ NULL,
|
||||
/*.samples_per_second */ 8000,
|
||||
/*.bits_per_second */ 13200,
|
||||
|
||||
@@ -37,96 +37,8 @@
|
||||
|
||||
static const char modname[] = "mod_dialplan_xml";
|
||||
|
||||
#define cleanre(re) if (re) {\
|
||||
pcre_free(re);\
|
||||
re = NULL;\
|
||||
}
|
||||
|
||||
|
||||
static int perform_regex(switch_channel_t *channel, char *field, char *expression, pcre **new_re, int *ovector, uint32_t olen)
|
||||
{
|
||||
const char *error = NULL;
|
||||
int erroffset = 0;
|
||||
pcre *re = NULL;
|
||||
int match_count = 0;
|
||||
|
||||
if (!(field && expression)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
re = pcre_compile(expression, /* the pattern */
|
||||
0, /* default options */
|
||||
&error, /* for error message */
|
||||
&erroffset, /* for error offset */
|
||||
NULL); /* use default character tables */
|
||||
if (error) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "COMPILE ERROR: %d [%s]\n", erroffset, error);
|
||||
cleanre(re);
|
||||
return 0;
|
||||
}
|
||||
|
||||
match_count = pcre_exec(re, /* result of pcre_compile() */
|
||||
NULL, /* we didn't study the pattern */
|
||||
field, /* the subject string */
|
||||
(int) strlen(field), /* the length of the subject string */
|
||||
0, /* start at offset 0 in the subject */
|
||||
0, /* default options */
|
||||
ovector, /* vector of integers for substring information */
|
||||
olen); /* number of elements (NOT size in bytes) */
|
||||
|
||||
if (match_count <= 0) {
|
||||
cleanre(re);
|
||||
match_count = 0;
|
||||
}
|
||||
|
||||
*new_re = re;
|
||||
|
||||
return match_count;
|
||||
}
|
||||
|
||||
|
||||
static void perform_substitution(pcre *re, int match_count, char *data, char *field_data, char *substituted, uint32_t len, int *ovector)
|
||||
{
|
||||
char index[10] = "";
|
||||
char replace[1024] = "";
|
||||
uint32_t x, y = 0, z = 0, num = 0;
|
||||
|
||||
for (x = 0; x < (len-1) && x < strlen(data);) {
|
||||
if (data[x] == '$') {
|
||||
x++;
|
||||
|
||||
if (!(data[x] > 47 && data[x] < 58)) {
|
||||
substituted[y++] = data[x-1];
|
||||
continue;
|
||||
}
|
||||
|
||||
while (data[x] > 47 && data[x] < 58) {
|
||||
index[z++] = data[x];
|
||||
x++;
|
||||
}
|
||||
index[z++] = '\0';
|
||||
z = 0;
|
||||
num = atoi(index);
|
||||
|
||||
if (pcre_copy_substring(field_data,
|
||||
ovector,
|
||||
match_count,
|
||||
num,
|
||||
replace,
|
||||
sizeof(replace)) > 0) {
|
||||
unsigned int r;
|
||||
for (r = 0; r < strlen(replace); r++) {
|
||||
substituted[y++] = replace[r];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
substituted[y++] = data[x];
|
||||
x++;
|
||||
}
|
||||
}
|
||||
substituted[y++] = '\0';
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
BREAK_ON_TRUE,
|
||||
BREAK_ON_FALSE,
|
||||
@@ -197,7 +109,7 @@ static int parse_exten(switch_core_session_t *session, switch_xml_t xexten, swit
|
||||
field_data = "";
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "test conditions %s(%s) =~ /%s/\n", field, field_data, expression);
|
||||
if (!(proceed = perform_regex(channel, field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
if (!(proceed = switch_perform_regex(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Regex mismatch\n");
|
||||
|
||||
for (xaction = switch_xml_child(xcond, "anti-action"); xaction; xaction = xaction->next) {
|
||||
@@ -232,7 +144,7 @@ static int parse_exten(switch_core_session_t *session, switch_xml_t xexten, swit
|
||||
char *app_data = NULL;
|
||||
|
||||
if (field && strchr(expression, '(')) {
|
||||
perform_substitution(re, proceed, data, field_data, substituted, sizeof(substituted), ovector);
|
||||
switch_perform_substitution(re, proceed, data, field_data, substituted, sizeof(substituted), ovector);
|
||||
app_data = substituted;
|
||||
} else {
|
||||
app_data = data;
|
||||
@@ -249,7 +161,7 @@ static int parse_exten(switch_core_session_t *session, switch_xml_t xexten, swit
|
||||
switch_caller_extension_add_application(session, *extension, application, app_data);
|
||||
}
|
||||
|
||||
cleanre(re);
|
||||
switch_clean_re(re);
|
||||
|
||||
if (do_break_i == BREAK_ON_TRUE || do_break_i == BREAK_ALWAYS) {
|
||||
break;
|
||||
|
||||
+64
-63
@@ -137,7 +137,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session)
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_channel_t *channel;
|
||||
switch_frame_t *frame;
|
||||
int stream_id;
|
||||
int stream_id = 0;
|
||||
switch_event_t *event;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
@@ -152,19 +152,18 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session)
|
||||
|
||||
switch_channel_set_flag(channel, CF_CONTROLLED);
|
||||
while (switch_channel_ready(channel)) {
|
||||
for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
|
||||
if ((status = switch_core_session_read_frame(session, &frame, -1, stream_id)) == SWITCH_STATUS_SUCCESS) {
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (switch_core_session_dequeue_private_event(session, &event) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_ivr_parse_event(session, event);
|
||||
switch_event_destroy(&event);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ((status = switch_core_session_read_frame(session, &frame, -1, stream_id)) == SWITCH_STATUS_SUCCESS) {
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (switch_core_session_dequeue_private_event(session, &event) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_ivr_parse_event(session, event);
|
||||
switch_event_destroy(&event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
switch_channel_clear_flag(channel, CF_CONTROLLED);
|
||||
|
||||
@@ -966,7 +965,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
|
||||
switch_codec_t codec;
|
||||
switch_memory_pool_t *pool = switch_core_session_get_pool(session);
|
||||
char *codec_name;
|
||||
int stream_id;
|
||||
int stream_id = 0;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_file_handle_t lfh;
|
||||
switch_codec_t *read_codec = switch_core_session_get_read_codec(session);
|
||||
@@ -975,11 +974,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
|
||||
uint8_t asis = 0;
|
||||
char *ext;
|
||||
|
||||
if (fh->samples > 0) {
|
||||
sample_start = fh->samples;
|
||||
fh->samples = 0;
|
||||
}
|
||||
|
||||
if (file) {
|
||||
if ((ext = strrchr(file, '.'))) {
|
||||
ext++;
|
||||
@@ -1000,6 +994,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
|
||||
memset(fh, 0, sizeof(lfh));
|
||||
}
|
||||
|
||||
|
||||
if (fh->samples > 0) {
|
||||
sample_start = fh->samples;
|
||||
fh->samples = 0;
|
||||
}
|
||||
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
|
||||
@@ -1259,21 +1260,23 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
|
||||
if (!asis) {switch_swap_linear(write_frame.data, (int) write_frame.datalen / 2);}
|
||||
#endif
|
||||
#endif
|
||||
for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
|
||||
status = switch_core_session_write_frame(session, &write_frame, -1, stream_id);
|
||||
stream_id = 0;
|
||||
|
||||
if (status == SWITCH_STATUS_MORE_DATA) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
continue;
|
||||
} else if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
status = switch_core_session_write_frame(session, &write_frame, -1, stream_id);
|
||||
|
||||
if (status == SWITCH_STATUS_MORE_DATA) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
continue;
|
||||
} else if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (timer_name) {
|
||||
if (switch_core_timer_next(&timer) < 0) {
|
||||
@@ -1487,7 +1490,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
|
||||
switch_size_t ilen = 0;
|
||||
switch_frame_t write_frame = {0};
|
||||
int x;
|
||||
int stream_id;
|
||||
int stream_id = 0;
|
||||
int done = 0;
|
||||
int lead_in_out = 10;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
@@ -1522,13 +1525,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
|
||||
write_frame.codec = codec;
|
||||
|
||||
for( x = 0; !done && x < lead_in_out; x++) {
|
||||
for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
|
||||
if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ilen = len;
|
||||
@@ -1606,13 +1607,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
for( x = 0; !done && x < lead_in_out; x++) {
|
||||
for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
|
||||
if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (status == SWITCH_STATUS_BREAK) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
@@ -1627,17 +1626,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
|
||||
write_frame.datalen = (uint32_t)ilen;
|
||||
write_frame.samples = (uint32_t)(ilen / 2);
|
||||
|
||||
for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
|
||||
if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bad Write\n");
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (timer) {
|
||||
if ((x = switch_core_timer_next(timer)) < 0) {
|
||||
@@ -1686,7 +1683,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
|
||||
switch_codec_t codec;
|
||||
switch_memory_pool_t *pool = switch_core_session_get_pool(session);
|
||||
char *codec_name;
|
||||
int stream_id;
|
||||
int stream_id = 0;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_speech_handle_t sh;
|
||||
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
|
||||
@@ -3130,8 +3127,6 @@ static const switch_state_handler_table_t signal_bridge_state_handlers = {
|
||||
/*.on_hibernate*/ signal_bridge_on_hibernate
|
||||
};
|
||||
|
||||
|
||||
|
||||
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;
|
||||
@@ -3319,9 +3314,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
|
||||
switch_channel_get_name(peer_channel)
|
||||
);
|
||||
switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (switch_channel_get_state(caller_channel) < CS_HANGUP &&
|
||||
switch_true(switch_channel_get_variable(caller_channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE))) {
|
||||
switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_CLEARING);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,92 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
SWITCH_DECLARE(int) switch_perform_regex(char *field, char *expression, pcre **new_re, int *ovector, uint32_t olen)
|
||||
{
|
||||
const char *error = NULL;
|
||||
int erroffset = 0;
|
||||
pcre *re = NULL;
|
||||
int match_count = 0;
|
||||
|
||||
if (!(field && expression)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
re = pcre_compile(expression, /* the pattern */
|
||||
0, /* default options */
|
||||
&error, /* for error message */
|
||||
&erroffset, /* for error offset */
|
||||
NULL); /* use default character tables */
|
||||
if (error) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "COMPILE ERROR: %d [%s]\n", erroffset, error);
|
||||
switch_clean_re(re);
|
||||
return 0;
|
||||
}
|
||||
|
||||
match_count = pcre_exec(re, /* result of pcre_compile() */
|
||||
NULL, /* we didn't study the pattern */
|
||||
field, /* the subject string */
|
||||
(int) strlen(field), /* the length of the subject string */
|
||||
0, /* start at offset 0 in the subject */
|
||||
0, /* default options */
|
||||
ovector, /* vector of integers for substring information */
|
||||
olen); /* number of elements (NOT size in bytes) */
|
||||
|
||||
if (match_count <= 0) {
|
||||
switch_clean_re(re);
|
||||
match_count = 0;
|
||||
}
|
||||
|
||||
*new_re = re;
|
||||
|
||||
return match_count;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(void) switch_perform_substitution(pcre *re, int match_count, char *data, char *field_data, char *substituted, uint32_t len, int *ovector)
|
||||
{
|
||||
char index[10] = "";
|
||||
char replace[1024] = "";
|
||||
uint32_t x, y = 0, z = 0, num = 0;
|
||||
|
||||
for (x = 0; x < (len-1) && x < strlen(data);) {
|
||||
if (data[x] == '$') {
|
||||
x++;
|
||||
|
||||
if (!(data[x] > 47 && data[x] < 58)) {
|
||||
substituted[y++] = data[x-1];
|
||||
continue;
|
||||
}
|
||||
|
||||
while (data[x] > 47 && data[x] < 58) {
|
||||
index[z++] = data[x];
|
||||
x++;
|
||||
}
|
||||
index[z++] = '\0';
|
||||
z = 0;
|
||||
num = atoi(index);
|
||||
|
||||
if (pcre_copy_substring(field_data,
|
||||
ovector,
|
||||
match_count,
|
||||
num,
|
||||
replace,
|
||||
sizeof(replace)) > 0) {
|
||||
unsigned int r;
|
||||
for (r = 0; r < strlen(replace); r++) {
|
||||
substituted[y++] = replace[r];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
substituted[y++] = data[x];
|
||||
x++;
|
||||
}
|
||||
}
|
||||
substituted[y++] = '\0';
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(char *) switch_priority_name(switch_priority_t priority)
|
||||
{
|
||||
switch(priority) { /*lol*/
|
||||
|
||||
Reference in New Issue
Block a user