From 60c783c6365b2815be286e117ef417969d8704b3 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 28 Nov 2007 19:56:25 +0000 Subject: [PATCH] rss feeds of your voicemail git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6417 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_apr.h | 2 + src/include/switch_console.h | 3 + src/include/switch_module_interfaces.h | 1 + src/include/switch_types.h | 1 + src/include/switch_utils.h | 2 +- .../mod_voicemail/mod_voicemail.c | 416 ++++++++++++++++++ .../mod_spidermonkey/mod_spidermonkey.c | 9 + src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c | 195 ++++++-- src/switch_apr.c | 22 + src/switch_console.c | 11 + src/switch_core.c | 3 + src/switch_xml.cpp | 16 +- 12 files changed, 639 insertions(+), 42 deletions(-) diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 3a24fa82fc..601fb74ff2 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -763,6 +763,8 @@ SWITCH_DECLARE(switch_size_t) switch_file_get_size(switch_file_t *thefile); SWITCH_DECLARE(switch_status_t) switch_file_exists(const char *filename, switch_memory_pool_t *pool); +SWITCH_DECLARE(switch_status_t) switch_directory_exists(const char *dirname, switch_memory_pool_t *pool); + SWITCH_DECLARE(switch_status_t) switch_dir_make(const char *path, switch_fileperms_t perm, switch_memory_pool_t *pool); SWITCH_DECLARE(switch_status_t) switch_dir_make_recursive(const char *path, switch_fileperms_t perm, diff --git a/src/include/switch_console.h b/src/include/switch_console.h index 48b6499543..7725a12050 100644 --- a/src/include/switch_console.h +++ b/src/include/switch_console.h @@ -49,6 +49,7 @@ SWITCH_BEGIN_EXTERN_C s.end = s.data; \ s.data_size = SWITCH_CMD_CHUNK_LEN; \ s.write_function = switch_console_stream_write; \ + s.raw_write_function = switch_console_stream_raw_write; \ s.alloc_len = SWITCH_CMD_CHUNK_LEN; \ s.alloc_chunk = SWITCH_CMD_CHUNK_LEN @@ -63,6 +64,8 @@ SWITCH_DECLARE(void) switch_console_loop(void); SWITCH_DECLARE(void) switch_console_printf(switch_text_channel_t channel, const char *file, const char *func, int line, const char *fmt, ...) PRINTF_FUNCTION(5, 6); +SWITCH_DECLARE(switch_status_t) switch_console_stream_raw_write(switch_stream_handle_t *handle, uint8_t *data, switch_size_t datalen); + /*! \brief A method akin to printf for dealing with api streams */ diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 4af805f116..48f6a809c4 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -81,6 +81,7 @@ struct switch_state_handler_table { struct switch_stream_handle { switch_stream_handle_write_function_t write_function; + switch_stream_handle_raw_write_function_t raw_write_function; void *data; void *end; switch_size_t data_size; diff --git a/src/include/switch_types.h b/src/include/switch_types.h index d9a8a30a5e..bdae1ee9e0 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1090,6 +1090,7 @@ typedef void (*switch_scheduler_func_t) (switch_scheduler_task_t *task); typedef switch_status_t (*switch_state_handler_t) (switch_core_session_t *); typedef struct switch_stream_handle switch_stream_handle_t; typedef switch_status_t (*switch_stream_handle_write_function_t) (switch_stream_handle_t *handle, const char *fmt, ...); +typedef switch_status_t (*switch_stream_handle_raw_write_function_t) (switch_stream_handle_t *handle, uint8_t *data, switch_size_t datalen); typedef switch_status_t (*switch_api_function_t) (const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream); diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index f79fb3eb3d..528aff9e35 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -132,7 +132,7 @@ SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key); */ #define is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119) - +#define end_of(_s) *(_s + strlen(_s) - 1) /*! \brief Test for the existance of a flag on an arbitary object \param obj the object to test diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c index 65d3244654..8ad3573c51 100644 --- a/src/mod/applications/mod_voicemail/mod_voicemail.c +++ b/src/mod/applications/mod_voicemail/mod_voicemail.c @@ -2119,9 +2119,423 @@ static void message_query_handler(switch_event_t *event) } +#define VOICEMAIL_SYNTAX "rss [ ]" + +struct holder { + vm_profile_t *profile; + switch_memory_pool_t *pool; + switch_stream_handle_t *stream; + switch_xml_t xml; + switch_xml_t x_item; + switch_xml_t x_channel; + int items; + char *user; + char *domain; + char *host; + char *port; + char *uri; +}; + + +static int del_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + if (argc > 8) { + unlink(argv[8]); + } + return 0; +} + +static int play_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + switch_file_t *fd; + struct holder *holder = (struct holder *) pArg; + char *fname, *ext; + switch_size_t flen; + uint8_t chunk[1024]; + const char *mime_type = "audio/inline", *new_type; + + if ((fname = strrchr(argv[8], '/'))) { + fname++; + } else { + fname = argv[8]; + } + + if ((ext = strrchr(fname, '.'))) { + ext++; + if ((new_type = switch_core_mime_ext2type(ext))) { + mime_type = new_type; + } + } + + if (switch_file_open(&fd, argv[8], SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, holder->pool) == SWITCH_STATUS_SUCCESS) { + flen = switch_file_get_size(fd); + holder->stream->write_function(holder->stream, "Content-type: %s\n", mime_type); + holder->stream->write_function(holder->stream, "Content-length: %ld\n\n", (long)flen); + for(;;) { + switch_status_t status; + + flen = sizeof(chunk); + status = switch_file_read(fd, chunk, &flen); + if (status != SWITCH_STATUS_SUCCESS || flen == 0) { + break; + } + + holder->stream->raw_write_function(holder->stream, chunk, flen); + + } + + switch_file_close(fd); + } + + return 0; +} + +static void do_play(vm_profile_t *profile, char *user, char *domain, char *file, switch_stream_handle_t *stream) +{ + char *sql; + struct holder holder; + + sql = switch_mprintf("update voicemail_data set read_epoch=%ld where user='%s' and domain='%s' and file_path like '%%%s'", + (long)time(NULL), user, domain, file); + + vm_execute_sql(profile, sql, profile->mutex); + free(sql); + + sql = switch_mprintf("select * from voicemail_data where user='%s' and domain='%s' and file_path like '%%%s'", user, domain, file); + memset(&holder, 0, sizeof(holder)); + holder.profile = profile; + holder.stream = stream; + switch_core_new_memory_pool(&holder.pool); + vm_execute_sql_callback(profile, profile->mutex, sql, play_callback, &holder); + switch_core_destroy_memory_pool(&holder.pool); + switch_safe_free(sql); + + +} + + +static void do_del(vm_profile_t *profile, char *user, char *domain, char *file, switch_stream_handle_t *stream) +{ + char *sql; + struct holder holder; + char *uri, *host, *port; + + host = port = uri = NULL; + + if (stream->event) { + host = switch_event_get_header(stream->event, "http-host"); + port = switch_event_get_header(stream->event, "http-port"); + uri = switch_event_get_header(stream->event, "http-uri"); + } + + sql = switch_mprintf("select * from voicemail_data where user='%s' and domain='%s' and file_path like '%%%s'", user, domain, file); + memset(&holder, 0, sizeof(holder)); + holder.profile = profile; + holder.stream = stream; + vm_execute_sql_callback(profile, profile->mutex, sql, del_callback, &holder); + + switch_safe_free(sql); + sql = switch_mprintf("delete from voicemail_data where user='%s' and domain='%s' and file_path like '%%%s'", user, domain, file); + vm_execute_sql(profile, sql, profile->mutex); + free(sql); + + if (host && port && uri) { + stream->write_function(stream,"Content-type: text/html\n\n

Message Deleted

\n" + "", host, port, uri); + } + +} + +static int rss_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct holder *holder = (struct holder *) pArg; + switch_xml_t x_tmp, x_link; + char *tmp, *del; + switch_time_exp_t tm; + char create_date[80] = ""; + char read_date[80] = ""; + char rss_date[80] = ""; + switch_size_t retsize; + const char *mime_type = "audio/inline", *new_type; + char *ext; + char *fname; + switch_size_t flen; + switch_file_t *fd; + long l_created = 0; + long l_read = 0; + long l_duration = 0; + switch_core_time_duration_t duration; + char duration_str[80]; + const char *fmt = "%a, %e %b %Y %T %z"; + char heard[80]; + + if (argc > 0) { + l_created = atol(argv[0]) * 1000000; + } + + if (argc > 1) { + l_read = atol(argv[1]) * 1000000; + } + + if (argc > 9) { + l_duration = atol(argv[9]) * 1000000; + } + + switch_core_measure_time(l_duration, &duration); + duration.day += duration.yr * 365; + duration.hr += duration.day * 24; + + snprintf(duration_str, sizeof(duration_str), "%.2u:%.2u:%.2u", + duration.hr, + duration.min, + duration.sec + ); + + if (l_created) { + switch_time_exp_lt(&tm, l_created); + switch_strftime(create_date, &retsize, sizeof(create_date), fmt, &tm); + switch_strftime(rss_date, &retsize, sizeof(create_date), fmt, &tm); + } + + if (l_read) { + switch_time_exp_lt(&tm, l_read); + switch_strftime(read_date, &retsize, sizeof(read_date), fmt, &tm); + } + + holder->x_item = switch_xml_add_child_d(holder->x_channel, "item", holder->items++); + + x_tmp = switch_xml_add_child_d(holder->x_item, "title", 0); + tmp = switch_mprintf("Message from %s %s on %s", argv[5], argv[6], create_date); + switch_xml_set_txt_d(x_tmp, tmp); + free(tmp); + + x_tmp = switch_xml_add_child_d(holder->x_item, "description", 0); + + snprintf(heard, sizeof(heard), switch_strlen_zero(read_date) ? "never" : read_date); + + if ((fname = strrchr(argv[8], '/'))) { + fname++; + } else { + fname = argv[8]; + } + + del = switch_mprintf("http://%s:%s%s/del/%s", holder->host, holder->port, holder->uri, fname); + x_link = switch_xml_add_child_d(holder->x_item, "fsvm:rmlink", 0); + switch_xml_set_txt_d(x_link, del); + + + tmp = switch_mprintf("Last Heard: %s
Duration: %s
Delete This Message]]>", + strcmp(argv[10], URGENT_FLAG_STRING) ? "normal" : "urgent", heard, duration_str, del); + + + switch_xml_set_txt_d(x_tmp, tmp); + free(tmp); + free(del); + + x_tmp = switch_xml_add_child_d(holder->x_item, "pubDate", 0); + switch_xml_set_txt_d(x_tmp, rss_date); + + x_tmp = switch_xml_add_child_d(holder->x_item, "itunes:duration", 0); + switch_xml_set_txt_d(x_tmp, duration_str); + + + tmp = switch_mprintf("http://%s:%s%s/get/%s", holder->host, holder->port, holder->uri, fname); + + x_tmp = switch_xml_add_child_d(holder->x_item, "guid", 0); + switch_xml_set_txt_d(x_tmp, tmp); + + x_link = switch_xml_add_child_d(holder->x_item, "link", 0); + switch_xml_set_txt_d(x_link, tmp); + + x_tmp = switch_xml_add_child_d(holder->x_item, "enclosure", 0); + switch_xml_set_attr_d(x_tmp, "url", tmp); + free(tmp); + + + + if (switch_file_open(&fd, argv[8], SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE, holder->pool) == SWITCH_STATUS_SUCCESS) { + flen = switch_file_get_size(fd); + tmp = switch_mprintf("%ld", (long) flen); + switch_xml_set_attr_d(x_tmp, "length", tmp); + free(tmp); + switch_file_close(fd); + } + + if ((ext = strrchr(fname, '.'))) { + ext++; + if ((new_type = switch_core_mime_ext2type(ext))) { + mime_type = new_type; + } + } + switch_xml_set_attr_d(x_tmp, "type", mime_type); + + return 0; +} + + +static void do_rss(vm_profile_t *profile, char *user, char *domain, char *host, char *port, char *uri, switch_stream_handle_t *stream) +{ + + struct holder holder; + switch_xml_t x_tmp; + char *sql, *xmlstr; + char *tmp = NULL; + + stream->write_function(stream, "Content-type: text/xml\n\n"); + memset(&holder, 0, sizeof(holder)); + holder.profile = profile; + holder.stream = stream; + holder.xml = switch_xml_new("rss"); + holder.user = user; + holder.domain = domain; + holder.host = host; + holder.port = port; + holder.uri = uri; + + switch_core_new_memory_pool(&holder.pool); + assert(holder.xml); + + switch_xml_set_attr_d(holder.xml, "xmlns:itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd"); + switch_xml_set_attr_d(holder.xml, "xmlns:fsvm", "http://www.freeswitch.org/dtd/fsvm.dtd"); + switch_xml_set_attr_d(holder.xml, "version", "2.0"); + holder.x_channel = switch_xml_add_child_d(holder.xml, "channel", 0); + + x_tmp = switch_xml_add_child_d(holder.x_channel, "title", 0); + tmp = switch_mprintf("FreeSWITCH Voicemail for %s@%s", user, domain); + switch_xml_set_txt_d(x_tmp, tmp); + free(tmp); + + x_tmp = switch_xml_add_child_d(holder.x_channel, "link", 0); + switch_xml_set_txt_d(x_tmp, "http://www.freeswitch.org"); + + x_tmp = switch_xml_add_child_d(holder.x_channel, "description", 0); + switch_xml_set_txt_d(x_tmp, "http://www.freeswitch.org"); + + x_tmp = switch_xml_add_child_d(holder.x_channel, "ttl", 0); + switch_xml_set_txt_d(x_tmp, "15"); + + + sql = switch_mprintf("select * from voicemail_data where user='%s' and domain='%s' order by read_flags", user, domain); + vm_execute_sql_callback(profile, profile->mutex, sql, rss_callback, &holder); + + xmlstr = switch_xml_toxml(holder.xml); + + stream->write_function(stream, "%s", xmlstr); + + switch_safe_free(sql); + switch_safe_free(xmlstr); + switch_xml_free(holder.xml); + switch_core_destroy_memory_pool(&holder.pool); +} + +SWITCH_STANDARD_API(voicemail_api_function) +{ + int argc = 0; + char *mydata = NULL, *argv[6]; + char *host = NULL, *port = NULL, *uri = NULL; + char *user = NULL, *domain = NULL; + int ct = 0; + vm_profile_t *profile = NULL; + char *path_info = NULL; + int rss = 0, xarg = 0; + + if (stream->event) { + host = switch_event_get_header(stream->event, "http-host"); + port = switch_event_get_header(stream->event, "http-port"); + uri = switch_event_get_header(stream->event, "http-uri"); + user = switch_event_get_header(stream->event, "freeswitch-user"); + domain = switch_event_get_header(stream->event, "freeswitch-domain"); + path_info = switch_event_get_header(stream->event, "http-path-info"); + } + + if (!switch_strlen_zero(cmd)) { + mydata = strdup(cmd); + assert(mydata); + argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } + + if (argc > 0) { + if (!strcasecmp(argv[0], "rss")) { + rss++; + xarg++; + } + } + + if (!host) { + if (argc - rss < 5) { + goto error; + } + host = argv[xarg++]; + port = argv[xarg++]; + uri = argv[xarg++]; + user = argv[xarg++]; + domain = argv[xarg++]; + } + + if (!(host && port && uri && user && domain)) { + goto error; + } + + profile = switch_core_hash_find(globals.profile_hash, domain); + + if (!profile) { + profile = switch_core_hash_find(globals.profile_hash, "default"); + } + + if (!profile) { + switch_hash_index_t *hi; + void *val; + + for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, NULL, NULL, &val); + profile = (vm_profile_t *) val; + break; + } + } + + if (!profile) { + stream->write_function(stream, "Can't find profile.\n"); + goto error; + } + + + if (path_info) { + if (!strncasecmp(path_info, "get/", 4)) { + do_play(profile, user, domain, path_info + 4, stream); + } else if (!strncasecmp(path_info, "del/", 4)) { + do_del(profile, user, domain, path_info + 4, stream); + } + } + + if (rss || (path_info && !strncasecmp(path_info, "rss", 3))) { + do_rss(profile, user, domain, host, port, uri, stream); + } + + goto done; + + error: + if (host) { + if (!ct) { + stream->write_function(stream, "Content-type: text/html\n\n

"); + } + } + stream->write_function(stream, "Error: %s\n", VOICEMAIL_SYNTAX); + + done: + + switch_safe_free(mydata); + + + return SWITCH_STATUS_SUCCESS; + + +} + + SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load) { switch_application_interface_t *app_interface; + switch_api_interface_t *commands_api_interface; switch_status_t status; if ((status = load_config()) != SWITCH_STATUS_SUCCESS) { @@ -2137,6 +2551,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_voicemail_load) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); return SWITCH_STATUS_GENERR; } + + SWITCH_ADD_API(commands_api_interface, "voicemail", "voicemail", voicemail_api_function, VOICEMAIL_SYNTAX); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_NOUNLOAD; diff --git a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c index fb811d7b9f..1c648365cb 100644 --- a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c +++ b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c @@ -3339,7 +3339,16 @@ static void js_thread_launch(const char *text) SWITCH_STANDARD_API(jsapi_function) { struct request_obj ro = {0}; + char *path_info = NULL; + if (stream->event) { + path_info = switch_event_get_header(stream->event, "http-path-info"); + } + + if (switch_strlen_zero(cmd) && path_info) { + cmd = path_info; + } + if (switch_strlen_zero(cmd)) { stream->write_function(stream, "USAGE: %s\n", jsapi_interface.syntax); return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c b/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c index a5104b3211..706825e56b 100644 --- a/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c +++ b/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c @@ -30,6 +30,7 @@ * */ #include +#include #ifdef _MSC_VER #pragma warning(disable:4142) #endif @@ -117,6 +118,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_xml_rpc_load) } +static switch_status_t http_stream_raw_write(switch_stream_handle_t *handle, uint8_t *data, switch_size_t datalen) +{ + TSession *r = handle->data; + + return HTTPWrite(r, (char *)data, (uint32_t) datalen) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; + +} + static switch_status_t http_stream_write(switch_stream_handle_t *handle, const char *fmt, ...) { va_list ap; @@ -146,7 +155,8 @@ static abyss_bool http_directory_auth(TSession *r, char *domain_name) char *pass; const char *mypass1 = NULL, *mypass2 = NULL; switch_xml_t x_domain, x_domain_root = NULL, x_user, x_params, x_param; - + const char *box; + p = RequestHeaderValue(r, "authorization"); if (p) { @@ -162,16 +172,21 @@ static abyss_bool http_directory_auth(TSession *r, char *domain_name) *pass++ = '\0'; } - if (switch_xml_locate_user(user, domain_name, NULL, &x_domain_root, &x_domain, &x_user, NULL) != SWITCH_STATUS_SUCCESS) { + if (switch_xml_locate_user(user, domain_name, NULL, &x_domain_root, &x_domain, &x_user, "mailbox=check") != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", user, domain_name); goto fail; } - + + ResponseAddField(r, "freeswitch-user", user); + ResponseAddField(r, "freeswitch-domain", domain_name); + + box = switch_xml_attr_soft(x_user, "mailbox"); + if (!(x_params = switch_xml_child(x_user, "params"))) { goto authed; } - + for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) { const char *var = switch_xml_attr_soft(x_param, "name"); const char *val = switch_xml_attr_soft(x_param, "value"); @@ -184,23 +199,53 @@ static abyss_bool http_directory_auth(TSession *r, char *domain_name) ResponseAddField(r, (char *)var, (char *)val); } } - - sprintf(z, "%s:%s", user, mypass1); - Base64Encode(z, t); - if (!strcmp(p, t)) { - r->user=strdup(user); + if (!(mypass1 && mypass2)) { + r->user=strdup(user); goto authed; - } + } else { + if (mypass1) { + sprintf(z, "%s:%s", user, mypass1); + Base64Encode(z, t); + + if (!strcmp(p, t)) { + r->user=strdup(user); + goto authed; + } + } - sprintf(z, "%s:%s", user, mypass2); - Base64Encode(z, t); + if (mypass2) { + sprintf(z, "%s:%s", user, mypass2); + Base64Encode(z, t); - if (!strcmp(p, t)) { - r->user=strdup(user); - goto authed; + if (!strcmp(p, t)) { + r->user=strdup(user); + goto authed; + } + } + + if (box) { + if (mypass1) { + sprintf(z, "%s:%s", box, mypass1); + Base64Encode(z, t); + + if (!strcmp(p, t)) { + r->user=strdup(box); + goto authed; + } + } + + if (mypass2) { + sprintf(z, "%s:%s", box, mypass2); + Base64Encode(z, t); + + if (!strcmp(p, t)) { + r->user=strdup(box); + goto authed; + } + } + } } - goto fail; @@ -242,15 +287,64 @@ abyss_bool auth_hook(TSession * r) *e++ = '\0'; } + if (!strcmp(domain_name, "this")) { + free(domain_name); + domain_name = strdup(r->host); + } + ret = !http_directory_auth(r, domain_name); free(domain_name); } else { - if (globals.realm) { - if (!RequestAuth(r, globals.realm, globals.user, globals.pass)) { - ret = TRUE; + char tmp[512]; + const char *list[2] = {"index.html", "index.txt"}; + int x; + + if (!strncmp(r->uri, "/pub", 4)) { + char *p = r->uri; + char *new_uri = p + 4; + if (!new_uri) { + new_uri = "/"; + } + + snprintf(tmp, sizeof(tmp), "%s%s", + SWITCH_GLOBAL_dirs.htdocs_dir, + new_uri + ); + + + if (switch_directory_exists(tmp, NULL) == SWITCH_STATUS_SUCCESS) { + for (x = 0; x < 2; x++) { + snprintf(tmp, sizeof(tmp), "%s%s%s%s", + SWITCH_GLOBAL_dirs.htdocs_dir, + new_uri, + end_of(new_uri) == *SWITCH_PATH_SEPARATOR ? "" : SWITCH_PATH_SEPARATOR, + list[x] + ); + + if (switch_file_exists(tmp, NULL) == SWITCH_STATUS_SUCCESS) { + snprintf(tmp, sizeof(tmp), "%s%s%s", + new_uri, + end_of(new_uri) == '/' ? "" : "/", + list[x] + ); + new_uri = tmp; + break; + } + } + } + + r->uri = strdup(new_uri); + free(p); + + } else { + if (globals.realm && strncmp(r->uri, "/pub", 4)) { + if (!RequestAuth(r, globals.realm, globals.user, globals.pass)) { + ret = TRUE; + } } } + } return ret; @@ -265,56 +359,71 @@ abyss_bool handler_hook(TSession * r) int i, j = 0; TTableItem *ti; char *dup = NULL; + int auth = 0; + char *fs_user = NULL, *fs_domain = NULL; + char *path_info = NULL; + abyss_bool ret = TRUE; stream.data = r; stream.write_function = http_stream_write; + stream.raw_write_function = http_stream_raw_write; if ((command = strstr(r->uri, "/api/"))) { command += 5; } else { - return FALSE; + ret = FALSE; + goto end; + } + + if ((path_info = strchr(command, '/'))) { + *path_info++ = '\0'; + } + + if (strncmp(r->uri, "/domains/", 9)) { + goto auth; } for (i=0;iresponse_headers.size;i++) { ti=&r->response_headers.item[i]; - if (!strcasecmp(ti->name, "http-allowed-api")) { + if (!strcasecmp(ti->name, "freeswitch-user")) { + fs_user = ti->value; + } else if (!strcasecmp(ti->name, "freeswitch-domain")) { + fs_domain = ti->value; + } else if (!strcasecmp(ti->name, "http-allowed-api")) { int argc, x; char *argv[256] = { 0 }; j++; if (!strcasecmp(ti->value, "any")) { - goto auth; - } - - if (!strcasecmp(ti->value, "none")) { - goto unauth; + auth++; } dup = strdup(ti->value); argc = switch_separate_string(dup, ',', argv, (sizeof(argv) / sizeof(argv[0]))); - + for (x = 0; x < argc; x++) { if (!strcasecmp(command, argv[x])) { - goto auth; + auth++; } } - - goto unauth; } } - if (r->user && !j) { - goto unauth; + if (!switch_strlen_zero(r->user) && !j) { + auth = 0; + } + + if (auth) { + goto auth; } - goto auth; - - unauth: + //unauth: ResponseStatus(r, 403); ResponseError(r); switch_safe_free(dup); - return TRUE; + ret = TRUE; + goto end; auth: @@ -322,7 +431,12 @@ abyss_bool handler_hook(TSession * r) if (switch_event_create(&stream.event, SWITCH_EVENT_API) == SWITCH_STATUS_SUCCESS) { const char * const content_length = RequestHeaderValue(r, "content-length"); - + if (fs_user) + switch_event_add_header(stream.event, SWITCH_STACK_BOTTOM, "FreeSWITCH-User", "%s", fs_user); + if (fs_domain) + switch_event_add_header(stream.event, SWITCH_STACK_BOTTOM, "FreeSWITCH-Domain", "%s", fs_domain); + if (path_info) + switch_event_add_header(stream.event, SWITCH_STACK_BOTTOM, "HTTP-Path-Info", "%s", path_info); if (r->uri) switch_event_add_header(stream.event, SWITCH_STACK_BOTTOM, "HTTP-URI", "%s", r->uri); if (r->query) @@ -434,7 +548,7 @@ abyss_bool handler_hook(TSession * r) } /* Generation of the server field */ - ResponseAddField(r,"Server", SERVER_HVERSION); + ResponseAddField(r,"Server", "FreeSWITCH-" SWITCH_VERSION_FULL "-mod_xml_rpc"); for (i=0;iresponse_headers.size;i++) { ti=&r->response_headers.item[i]; @@ -453,7 +567,10 @@ abyss_bool handler_hook(TSession * r) } //HTTPWriteEnd(r); - return TRUE; + + end: + + return ret; } diff --git a/src/switch_apr.c b/src/switch_apr.c index 6f02df7540..33ca647b25 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -364,6 +364,28 @@ SWITCH_DECLARE(switch_size_t) switch_file_get_size(switch_file_t *thefile) return apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile) == SWITCH_STATUS_SUCCESS ? (switch_size_t)finfo.size : 0; } +SWITCH_DECLARE(switch_status_t) switch_directory_exists(const char *dirname, switch_memory_pool_t *pool) +{ + apr_dir_t *dir_handle; + switch_memory_pool_t *our_pool = NULL; + switch_status_t status; + + if (!pool) { + switch_core_new_memory_pool(&our_pool); + pool = our_pool; + } + + if ((status = apr_dir_open(&dir_handle, dirname, pool)) == APR_SUCCESS) { + apr_dir_close(dir_handle); + } + + if (our_pool) { + switch_core_destroy_memory_pool(&our_pool); + } + + return status; +} + SWITCH_DECLARE(switch_status_t) switch_file_exists(const char *filename, switch_memory_pool_t *pool) { int32_t wanted = APR_FINFO_TYPE; diff --git a/src/switch_console.c b/src/switch_console.c index 28057b1cae..c03b5bc8c7 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -34,6 +34,17 @@ #include #define CMD_BUFLEN 1024; +SWITCH_DECLARE(switch_status_t) switch_console_stream_raw_write(switch_stream_handle_t *handle, uint8_t *data, switch_size_t datalen) +{ + FILE *out = switch_core_get_console(); + + if (out) { + fwrite(data, datalen, 1, out); + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} SWITCH_DECLARE(switch_status_t) switch_console_stream_write(switch_stream_handle_t *handle, const char *fmt, ...) { diff --git a/src/switch_core.c b/src/switch_core.c index 6e90c50bc4..7c27646f3a 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -551,6 +551,9 @@ SWITCH_DECLARE(void) switch_core_runtime_loop(int bg) SWITCH_DECLARE(const char *) switch_core_mime_ext2type(const char *ext) { + if (!ext) { + return NULL; + } return (const char *) switch_core_hash_find(runtime.mime_types, ext); } diff --git a/src/switch_xml.cpp b/src/switch_xml.cpp index 6e5cad4f70..47da443bfc 100644 --- a/src/switch_xml.cpp +++ b/src/switch_xml.cpp @@ -1457,7 +1457,8 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_cfg(const char *file_path, switch_x static char *switch_xml_ampencode(const char *s, switch_size_t len, char **dst, switch_size_t *dlen, switch_size_t *max, short a) { const char *e = NULL; - + int immune = 0; + if (len) { e = s + len; } @@ -1466,13 +1467,24 @@ static char *switch_xml_ampencode(const char *s, switch_size_t len, char **dst, while (*dlen + 10 > *max) *dst = (char *)realloc(*dst, *max += SWITCH_XML_BUFSIZE); - switch (*s) { + if (immune) { + if (*s == '\0') { + return *dst; + } + (*dst)[(*dlen)++] = *s; + } else + switch (*s) { case '\0': return *dst; case '&': *dlen += sprintf(*dst + *dlen, "&"); break; case '<': + if (*(s+1) == '!') { + (*dst)[(*dlen)++] = *s; + immune++; + break; + } *dlen += sprintf(*dst + *dlen, "<"); break; case '>':