diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 8886eaa552..696fbc22db 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -180,6 +180,13 @@ switch_mutex_unlock(obj->flag_mutex); #define switch_yield(ms) apr_sleep(ms); //apr_thread_yield(); #endif +/*! + \brief Converts a string representation of a date into a switch_time_t + \param in the string + \return the epoch time in usec +*/ +SWITCH_DECLARE(switch_time_t) switch_str_time(char *in); + /*! \brief Declares a function designed to set a dymaic global string \param fname the function name to declare diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index d2b3d97adc..506178b9e9 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -279,6 +279,20 @@ static void strftime_function(switch_core_session_t *session, char *data) } } + +static switch_status_t strepoch_api_function(char *data, switch_core_session_t *session, switch_stream_handle_t *stream) +{ + switch_time_t out; + + if (switch_strlen_zero(data)) { + out = switch_time_now(); + } else { + out = switch_str_time(data); + } + + stream->write_function(stream, "%d", (uint32_t)apr_time_sec(out)); +} + static switch_status_t strftime_api_function(char *fmt, switch_core_session_t *session, switch_stream_handle_t *stream) { @@ -288,7 +302,7 @@ static switch_status_t strftime_api_function(char *fmt, switch_core_session_t *s switch_time_exp_lt(&tm, switch_time_now()); switch_strftime(date, &retsize, sizeof(date), fmt ? fmt : "%Y-%m-%d %T", &tm); - stream->write_function(stream, date); + stream->write_function(stream, "%s", date); return SWITCH_STATUS_SUCCESS; } @@ -407,12 +421,20 @@ static void ivr_application_function(switch_core_session_t *session, char *data) } } +static switch_api_interface_t strepoch_api_interface = { + /*.interface_name */ "strepoch", + /*.desc */ "Convert a date string into epoch time", + /*.function */ strepoch_api_function, + /*.syntax */ "", + /*.next */ NULL +}; + static switch_api_interface_t chat_api_interface = { /*.interface_name */ "chat", /*.desc */ "chat", /*.function */ chat_api_function, /*.syntax */ "|||", - /*.next */ NULL + /*.next */ &strepoch_api_interface }; static switch_api_interface_t dptools_api_interface = { diff --git a/src/mod/say/mod_say_en/mod_say_en.c b/src/mod/say/mod_say_en/mod_say_en.c index bdae061e05..8d4d2b6efd 100644 --- a/src/mod/say/mod_say_en/mod_say_en.c +++ b/src/mod/say/mod_say_en/mod_say_en.c @@ -24,6 +24,7 @@ * Contributor(s): * * Anthony Minessale II + * Michael B. Murdock * * mod_say_en.c -- Say for English * @@ -133,6 +134,26 @@ static char *strip_commas(char *in, char *out, switch_size_t len) return ret; } +static char *strip_nonnumerics(char *in, char *out, switch_size_t len) +{ + char *p = in, *q = out; + char *ret = out; + switch_size_t x = 0; + // valid are 0 - 9, period (.), minus (-), and plus (+) - remove all others + for(;p && *p; p++) { + if ((*p > 47 && *p < 58) || *p == '.' || *p == '-' || *p == '+') { + *q++ = *p; + } + + if (++x > len) { + ret = NULL; + break; + } + } + + return ret; +} + static switch_status_t en_say_general_count(switch_core_session_t *session, char *tosay, switch_say_type_t type, @@ -155,40 +176,46 @@ static switch_status_t en_say_general_count(switch_core_session_t *session, } in = atoi(tosay); - - for(x = 8; x >= 0; x--) { - int num = (int)pow(10, x); - if ((places[x] = in / num)) { - in -= places[x] * num; - } - } - switch (method) { - case SSM_COUNTED: - case SSM_PRONOUNCED: - if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/million.wav", session, args)) != SWITCH_STATUS_SUCCESS) { - return status; - } - if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) { - return status; - } - if ((status = play_group(method, places[2], places[1], places[0], NULL, session, args)) != SWITCH_STATUS_SUCCESS) { - return status; - } - break; - case SSM_ITERATED: - { - char *p; - for (p = tosay; p && *p; p++) { - if (places[x] > -1) { - say_file("digits/%c.wav", *p); - } + if (in != 0) { + for(x = 8; x >= 0; x--) { + int num = (int)pow(10, x); + if ((places[x] = in / num)) { + in -= places[x] * num; } } - break; - default: - break; + + switch (method) { + case SSM_COUNTED: + case SSM_PRONOUNCED: + if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/million.wav", session, args)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(method, places[2], places[1], places[0], NULL, session, args)) != SWITCH_STATUS_SUCCESS) { + return status; + } + break; + case SSM_ITERATED: + { + char *p; + for (p = tosay; p && *p; p++) { + if (places[x] > -1) { + say_file("digits/%c.wav", *p); + } + } + } + break; + default: + break; + } } + else { + say_file("digits/0.wav"); + } + return SWITCH_STATUS_SUCCESS; } @@ -367,6 +394,67 @@ static switch_status_t en_say_time(switch_core_session_t *session, } +static switch_status_t en_say_money(switch_core_session_t *session, + char *tosay, + switch_say_type_t type, + switch_say_method_t method, + switch_input_args_t *args) +{ + switch_channel_t *channel; + + int x = 0; + char sbuf[16] = ""; // enuf for 999,999,999,999.99 (w/o the commas) + + double amt, dollars, cents; + + switch_status_t status; + + assert(session != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + if (!(tosay = strip_nonnumerics(tosay, sbuf, sizeof(sbuf))) || strlen(tosay) > 15) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + amt = atof(tosay); //convert to double + dollars = trunc(amt); // get whole dollars + cents = trunc(fabs((amt - dollars))*100.0); // get cents as whole integer (dropping sign) + dollars = fabs(dollars); // lose the sign + + // If negative say "negative" (or "minus") + if (amt < 0.0) { + say_file("negative.wav"); + // say_file("minus.wav"); + } + + // Say dollar amount + snprintf(sbuf, sizeof(sbuf), "%.0f", dollars); + en_say_general_count(session, sbuf, type, method, args); + if (dollars == 1.0) { + say_file("dollar.wav"); + } + else { + say_file("dollars.wav"); + } + + // Say "and" + say_file("and.wav"); + + // Say cents + snprintf(sbuf, sizeof(sbuf), "%.0f", cents); + en_say_general_count(session, sbuf, type, method, args); + if (cents == 1.0) { + say_file("cent.wav"); + } + else { + say_file("cents.wav"); + } + + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t en_say(switch_core_session_t *session, @@ -398,8 +486,11 @@ static switch_status_t en_say(switch_core_session_t *session, case SST_NAME_PHONETIC: say_cb = en_spell; break; + case SST_CURRENCY: + say_cb = en_say_money; + break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Finish ME!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", type); break; } @@ -439,4 +530,3 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_mod /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } - diff --git a/src/switch_utils.c b/src/switch_utils.c index baeed869eb..efcebc50b8 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -121,6 +121,54 @@ SWITCH_DECLARE(void) switch_perform_substitution(pcre *re, int match_count, char } + +SWITCH_DECLARE(switch_time_t) switch_str_time(char *in) +{ + switch_time_exp_t tm = {0}; + int proceed = 0, ovector[30]; + pcre *re = NULL; + char replace[1024] = ""; + switch_time_t ret = 0; + char *pattern = "^(\\d+)-(\\d+)-(\\d+)\\s*(\\d*):{0,1}(\\d*):{0,1}(\\d*)"; + + if ((proceed = switch_perform_regex(in, pattern, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { + printf("ASS %d\n", proceed); + pcre_copy_substring(in, ovector, proceed, 0, replace, sizeof(replace)); + tm.tm_year = atoi(replace) - 1900; + + if (proceed > 1) { + pcre_copy_substring(in, ovector, proceed, 1, replace, sizeof(replace)); + tm.tm_mon = atoi(replace); + } + + if (proceed > 2) { + pcre_copy_substring(in, ovector, proceed, 2, replace, sizeof(replace)); + tm.tm_mday = atoi(replace); + } + + if (proceed > 3) { + pcre_copy_substring(in, ovector, proceed, 3, replace, sizeof(replace)); + tm.tm_hour = atoi(replace); + } + + if (proceed > 4) { + pcre_copy_substring(in, ovector, proceed, 4, replace, sizeof(replace)); + tm.tm_min = atoi(replace); + } + + if (proceed > 5) { + pcre_copy_substring(in, ovector, proceed, 5, replace, sizeof(replace)); + tm.tm_sec = atoi(replace); + } + + apr_time_exp_get(&ret, &tm); + return ret; + } /* possible else with more patterns later */ + + return ret; + +} + SWITCH_DECLARE(char *) switch_priority_name(switch_priority_t priority) { switch(priority) { /*lol*/