diff --git a/src/mod/say/mod_say_pl/Makefile b/src/mod/say/mod_say_pl/Makefile new file mode 100644 index 0000000000..67f6ea355b --- /dev/null +++ b/src/mod/say/mod_say_pl/Makefile @@ -0,0 +1,2 @@ +BASE=../../../freeswitch +include $(BASE)/build/modmake.rules diff --git a/src/mod/say/mod_say_pl/README b/src/mod/say/mod_say_pl/README new file mode 100644 index 0000000000..2a35b81794 --- /dev/null +++ b/src/mod/say/mod_say_pl/README @@ -0,0 +1,7 @@ +mod_say_pl - support for Polish language in FreeSWITCH +======================================================= + +Moduł bazuje na mod_say_en. Aktualnie nie jest jeszcze kompletny, +tym nie mniej pozwala na czytanie liczb czy dat/czasu. Liczę na +Wasze wsparcie w zakresie testowania modułu, sugestii, łat, etc. +na http://jira.freeswitch.org/. diff --git a/src/mod/say/mod_say_pl/conf/dialplan/default/test_say_pl.xml b/src/mod/say/mod_say_pl/conf/dialplan/default/test_say_pl.xml new file mode 100644 index 0000000000..a19bbe07cc --- /dev/null +++ b/src/mod/say/mod_say_pl/conf/dialplan/default/test_say_pl.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/say/mod_say_pl/conf/lang/pl/pl.xml b/src/mod/say/mod_say_pl/conf/lang/pl/pl.xml new file mode 100644 index 0000000000..92c4e16d2a --- /dev/null +++ b/src/mod/say/mod_say_pl/conf/lang/pl/pl.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/src/mod/say/mod_say_pl/create_sound_files.sh b/src/mod/say/mod_say_pl/create_sound_files.sh new file mode 100755 index 0000000000..0ee3855a67 --- /dev/null +++ b/src/mod/say/mod_say_pl/create_sound_files.sh @@ -0,0 +1,358 @@ +#!/bin/bash + +TTS=espeak +TTS_OPTS="-a90 -b1 -s130 -p77" + +###################### +# directories for voice files +###################### + +rm -rf pl/epeak +mkdir -p pl/espeak/digits/HD +mkdir -p pl/espeak/time/HD +mkdir -p pl/espeak/digits/16000 +mkdir -p pl/espeak/time/16000 +mkdir -p pl/espeak/digits/8000 +mkdir -p pl/espeak/time/8000 + +###################### +# create sound files +###################### + +function mksound { + local TYPE=$1; shift + local FILE=$1; shift + local TEXT=$* + + ${TTS} ${TTS_OPTS} -v pl -w pl/espeak/${TYPE}/HD/${FILE}.wav "${TEXT}" + sox pl/espeak/${TYPE}/HD/${FILE}.wav -r 16000 pl/espeak/${TYPE}/16000/${FILE}.wav + sox pl/espeak/${TYPE}/HD/${FILE}.wav -r 8000 pl/espeak/${TYPE}/8000/${FILE}.wav + + echo "${TYPE} ${FILE}... done." +} + +###################### +# IVR messages +###################### + +TYPE=digits + +while read FILE TEXT +do + if [ "${FILE}" != "#" ] + then + mksound ${TYPE} ${FILE} ${TEXT} + else + echo "Comment: ${TEXT}" + fi +done <<'EOT' +# l. główne, r.męski, mianownik +0 zero +1 jeden +2 dwa +3 trzy +4 cztery +5 pięć +6 sześć +7 siedem +8 osiem +9 dziewięć +10 dziesięć +11 jedenaście +12 dwanaście +13 trzynaście +14 czternaście +15 pietnaście +16 szesnaście +17 siedemnaście +18 osiemnaście +19 dziewiętnaście +20 dwadzieścia +30 trzydzieści +40 czterdzieści +50 pięćdziesiąt +60 sześćdziesiąt +70 siedemdziesiąt +80 osiemdziesiąc +90 dziewięćdziesiąt +100 sto +200 dwieście +300 trzysta +400 czterysta +500 pięćset +600 sześćset +700 siedemset +800 osiemset +900 dziewięćset +1000 tysiąc +1000a tysiące +1000s tysięcy +1000000 milion +1000000a miliony +1000000s milionów +# l. główne, r.żeński, mianownik +1_f jedna +2_f dwie +# l. główne, r.nijaki, mianownik +1_n jedno +2_n dwie +# l. porządowe, r.męski, mianownik +0_pm zerowy +1_pm pierwszy +2_pm drugi +3_pm trzeci +4_pm czwarty +5_pm piąty +6_pm szósty +7_pm siódmy +8_pm ósmy +9_pm dziewiąty +10_pm dziesiąty +11_pm jedenasty +12_pm dwunasty +13_pm trzynasty +14_pm czternasty +15_pm piętnasty +16_pm szesnasty +17_pm siedemnasty +18_pm osiemnasty +19_pm dziewiętnasty +20_pm dwudziesty +30_pm trzydziesty +40_pm czterdziesty +50_pm pięćdziesiąty +60_pm sześćdziesiąty +70_pm siedemdziesiąty +80_pm osiemdziesiąty +90_pm dziewięćdziesiąty +100_pm setny +200_pm dwusetny +300_pm trzysetny +400_pm czterysetny +500_pm pięćsetny +600_pm sześćsetny +700_pm siedemsetny +800_pm osiemsetny +900_pm dziewięćsetny +1000_pm tysięczny +# l. porządowe specjane - numery dni, r.męski, mianownik +01_pm pierwszy +02_pm drugi +03_pm trzeci +04_pm czwarty +05_pm piąty +06_pm szósty +07_pm siódmy +08_pm ósmy +09_pm dziewiąty +21_pm dwudziesty pierwszy +22_pm dwudziesty drugi +23_pm dwudziesty trzeci +24_pm dwudziesty czwarty +25_pm dwudziesty piąty +26_pm dwudziesty szósty +27_pm dwudziesty siódmy +28_pm dwudziesty ósmy +29_pm dwudziesty dziewiąty +31_pm trzydziesty pierwszy + +# l. porządowe, r.żeski, mianownik +0_pf zerowa +1_pf pierwsza +2_pf druga +3_pf trzecia +4_pf czwarta +5_pf piąta +6_pf szósta +7_pf siódma +8_pf ósma +9_pf dziewiąta +10_pf dziesiąta +11_pf jedenasta +12_pf dwunasta +13_pf trzynasta +14_pf czternasta +15_pf piętnasta +16_pf szesnasta +17_pf siedemnasta +18_pf osiemnasta +19_pf dziewiętnasta +20_pf dwudziesta +30_pf trzydziesta +40_pf czterdziesta +50_pf pięćdziesiąta +60_pf sześćdziesiąta +70_pf siedemdziesiąta +80_pf osiemdziesiąta +90_pf dziewięćdziesiąta +100_pf setna +200_pf dwusetna +300_pf trzysetna +400_pf czterysetna +500_pf pięćsetna +600_pf sześćsetna +700_pf siedemsetna +800_pf osiemsetna +900_pf dziewięćsetna +1000_pf tysięczna +# l. porządowe, r.męski, dopełniacz +0_pmD zerowego +1_pmD pierwszego +2_pmD drugiego +3_pmD trzeciego +4_pmD czwartego +5_pmD piątego +6_pmD szóstego +7_pmD siódmego +8_pmD ósmego +9_pmD dziewiątego +10_pmD dziesiątego +11_pmD jedenastego +12_pmD dwunastego +13_pmD trzynastego +14_pmD czternastego +15_pmD piętnastego +16_pmD szesnastego +17_pmD siedemnastego +18_pmD osiemnastego +19_pmD dziewiętnastego +20_pmD dwudziestego +30_pmD trzydziestego +40_pmD czterdziestego +50_pmD pięćdziesiątego +60_pmD sześćdziesiątego +70_pmD siedemdziesiątego +80_pmD osiemdziesiątego +90_pmD dziewięćdziesiątego +100_pmD setnego +200_pmD dwusetnego +300_pmD trzysetnego +400_pmD czterysetnego +500_pmD pięćsetnego +600_pmD sześćsetnego +700_pmD siedemsetnego +800_pmD osiemsetnego +900_pmD dziewięćsetnego +1000_pmD tysięcznego +# l. porządowe, r.żeski, dopełniacz +0_pfD zerowej +1_pfD pierwszej +2_pfD drugiej +3_pfD trzeciej +4_pfD czwartej +5_pfD piątej +6_pfD szóstej +7_pfD siódmej +8_pfD ósmej +9_pfD dziewiątej +10_pfD dziesiątej +11_pfD jedenastej +12_pfD dwunastej +13_pfD trzynastej +14_pfD czternastej +15_pfD piętnastej +16_pfD szesnastej +17_pfD siedemnastej +18_pfD osiemnastej +19_pfD dziewiętnastej +20_pfD dwudziestej +30_pfD trzydziestej +40_pfD czterdziestej +50_pfD pięćdziesiątej +60_pfD sześćdziesiątej +70_pfD siedemdziesiątej +80_pfD osiemdziesiątej +90_pfD dziewięćdziesiątej +100_pfD setnej +200_pfD dwusetnej +300_pfD trzysetnej +400_pfD czterysetnej +500_pfD pięćsetnej +600_pfD sześćsetnej +700_pfD siedemsetnej +800_pfD osiemsetnej +900_pfD dziewięćsetnej +1000_pfD tysięcznej +# dodatkowe +star gwiazdka +star_C gwiazdkę +pound krzyżyk +dot kropka +dot_C kropkę +coma przecinek +EOT + +TYPE=time + +while read FILE TEXT +do + if [ "${FILE}" != "#" ] + then + mksound ${TYPE} ${FILE} ${TEXT} + else + echo "Comment: ${TEXT}" + fi +done <<'EOT' +# l. jednostki czasu +t_sekunda sekunda +t_sekundy sekundy +t_sekund sekund +t_minuta minuta +t_minuty minuty +t_minut minut +t_godzina godzina +t_godziny godziny +t_godzin godzin +t_dzien dzień +t_dni dni +t_tydzien tydzień +t_tygodnie tygodnie +t_tygodni tygodni +t_miesiac miesiąc +t_miesiace miesiące +t_miesiecy miesięcy +t_rok rok +t_roku roku +t_lata lata +t_lat lat +# dni tygodnia, mianownik +day-0 niedziela +day-1 poniedziałek +day-2 wtorek +day-3 środa +day-4 czwartek +day-5 piątek +day-6 sobota +# miesiące, mianownik +mon-0 styczeń +mon-1 luty +mon-2 marzec +mon-3 kwiecień +mon-4 maj +mon-5 czerwiec +mon-6 lipiec +mon-7 sierpień +mon-8 wrzesień +mon-9 październik +mon-10 listopad +mon-11 grudzień +# miesiące, dopełniacz +mon-0_D stycznia +mon-1_D lutego +mon-2_D marca +mon-3_D kwietnia +mon-4_D maja +mon-5_D czerwieca +mon-6_D lipieca +mon-7_D sierpnia +mon-8_D września +mon-9_D października +mon-10_D listopada +mon-11_D grudnia +# dodatkowe +t_wczoraj wczoraj +t_dzisiaj dzisiaj +t_jutro jutro +EOT + +echo "ALL DONE." \ No newline at end of file diff --git a/src/mod/say/mod_say_pl/mod_say_pl.c b/src/mod/say/mod_say_pl/mod_say_pl.c new file mode 100644 index 0000000000..a5f7a7acd7 --- /dev/null +++ b/src/mod/say/mod_say_pl/mod_say_pl.c @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * Michael B. Murdock + * Mariusz Czułada + * + * mod_say_pl.c -- Say for Polish + * + */ + +#include +#include +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_pl_load); +SWITCH_MODULE_DEFINITION(mod_say_pl, mod_say_pl_load, NULL, NULL); + + +#define say_num(_sh, num, meth, gen) { \ + char tmp[80]; \ + switch_status_t tstatus; \ + switch_say_method_t smeth = say_args->method; \ + switch_say_type_t stype = say_args->type; \ + switch_say_gender_t sgen = say_args->gender; \ + say_args->type = SST_ITEMS; say_args->method = meth; \ + say_args->gender = gen; \ + switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num); \ + if ((tstatus = \ + pl_say_general_count(_sh, tmp, say_args)) \ + != SWITCH_STATUS_SUCCESS) { \ + return tstatus; \ + } \ + say_args->method = smeth; say_args->type = stype; \ + say_args->gender = sgen; \ + } \ + +static switch_status_t play_group(switch_say_method_t method, switch_say_gender_t gender, int a, int b, int c, char *what, switch_say_file_handle_t *sh) +{ + char tmp[80]; + + if (a) { + switch_say_file(sh, "digits/%d00", a); + } + + if (b) { + if (b > 1) { + if ((method == SSM_COUNTED)) { + if (gender == SSG_MASCULINE) + switch_say_file(sh, "digits/%d0_pm", b); + else if (gender == SSG_FEMININE) + switch_say_file(sh, "digits/%d0_pf", b); + else if (gender == SSG_NEUTER) + switch_say_file(sh, "digits/%d0_pn", b); + } else { + switch_say_file(sh, "digits/%d0", b); + } + } else { + if ((method == SSM_COUNTED)) { + if (gender == SSG_MASCULINE) + switch_say_file(sh, "digits/%d%d_pm", b, c); + else if (gender == SSG_FEMININE) + switch_say_file(sh, "digits/%d%d_pf", b, c); + else if (gender == SSG_NEUTER) + switch_say_file(sh, "digits/%d%d_pn", b, c); + } else { + switch_say_file(sh, "digits/%d%d", b, c); + } + c = 0; + } + } + + if (c) { + if (method == SSM_COUNTED) { + if (gender == SSG_MASCULINE && b != 1 && (c == 1 || c == 2)) { + switch_say_file(sh, "digits/%d_pm", c); + } else if (gender == SSG_FEMININE && b != 1 && (c == 1 || c == 2)) { + switch_say_file(sh, "digits/%d_pf", c); + } else { + switch_say_file(sh, "digits/%d_pn", c); + } + } else { + if (gender == SSG_FEMININE && b != 1 && (c == 1 || c == 2)) { + switch_say_file(sh, "digits/%d_f", c); + } else { + switch_say_file(sh, "digits/%d", c); + } + } + } + + if (what && (a || b || c)) { + if (!a && !b && c == 1) { + switch_snprintf(tmp, sizeof(tmp), "%s", what); + } else if (b != 1 && (c == 2 || c == 3 || c == 4)) { + switch_snprintf(tmp, sizeof(tmp), "%sa", what); + } else if (a*100+b*10+c > 4) { + switch_snprintf(tmp, sizeof(tmp), "%ss", what); + } + switch_say_file(sh, tmp); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t pl_say_general_count(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int in; + int x = 0; + int places[9] = { 0 }; + char sbuf[128] = ""; + switch_status_t status; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SAY: %s\n", tosay); + + if (say_args->method == SSM_ITERATED) { + if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1))) { + char *p; + for (p = tosay; p && *p; p++) { + switch_say_file(sh, "digits/%c", *p); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + return SWITCH_STATUS_SUCCESS; + } + + if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)-1)) || strlen(tosay) > 9) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + in = atoi(tosay); + + if (in != 0) { + for (x = 8; x >= 0; x--) { + int num = (int) pow(10, x); + if ((places[(uint32_t) x] = in / num)) { + in -= places[(uint32_t) x] * num; + } + } + + switch (say_args->method) { + case SSM_COUNTED: + case SSM_PRONOUNCED: + if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[8], places[7], places[6], "digits/1000000", sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(SSM_PRONOUNCED, say_args->gender, places[5], places[4], places[3], "digits/1000", sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(say_args->method, say_args->gender, places[2], places[1], places[0], NULL, sh)) != SWITCH_STATUS_SUCCESS) { + return status; + } + break; + default: + break; + } + } else { + switch_say_file(sh, "digits/0"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t pl_say_time(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + int32_t t; + switch_time_t target = 0, target_now = 0; + switch_time_exp_t tm, tm_now; + uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0; + const char *tz = NULL; + + tz = switch_say_file_handle_get_variable(sh, "timezone"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SAY: %s\n", tosay); + + if (say_args->type == SST_TIME_MEASUREMENT) { + int64_t hours = 0; + int64_t minutes = 0; + int64_t seconds = 0; + int64_t r = 0; + + if (strchr(tosay, ':')) { + char *tme = strdup(tosay); + char *p; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse time string!\n"); + if ((p = strrchr(tme, ':'))) { + *p++ = '\0'; + seconds = atoi(p); + if ((p = strchr(tme, ':'))) { + *p++ = '\0'; + minutes = atoi(p); + if (tme) { + hours = atoi(tme); + } + } else { + minutes = atoi(tme); + } + } + free(tme); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse time in seconds!\n"); + if ((seconds = atol(tosay)) <= 0) { + seconds = (int64_t) switch_epoch_time_now(NULL); + } + + if (seconds >= 60) { + minutes = seconds / 60; + r = seconds % 60; + seconds = r; + } + + if (minutes >= 60) { + hours = minutes / 60; + r = minutes % 60; + minutes = r; + } + } + + if (hours) { + int hd = 0, hj = 0; + say_num(sh, hours, SSM_PRONOUNCED, SSG_FEMININE); + hj = hours % 10; + hd = (hours/10) % 10; + if (hours == 1) { + switch_say_file(sh, "time/t_godzina"); + }else if (hd != 1 && ( hj == 2 || hj == 3 || hj == 4)) { + switch_say_file(sh, "time/t_godziny"); + } else { + switch_say_file(sh, "time/t_godzin"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/t_godzin"); + } + + if (minutes) { + int md = 0, mj = 0; + say_num(sh, minutes, SSM_PRONOUNCED, SSG_FEMININE); + mj = minutes % 10; + md = (minutes/10) % 10; + if (minutes == 1) { + switch_say_file(sh, "time/minuta"); + }else if (md != 1 && ( mj == 2 || mj == 3 || mj == 4)) { + switch_say_file(sh, "time/t_minuty"); + } else { + switch_say_file(sh, "time/t_minut"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/t_minut"); + } + + if (seconds) { + int sd = 0, sj = 0; + say_num(sh, seconds, SSM_PRONOUNCED, SSG_FEMININE); + sj = seconds % 10; + sd = (seconds/10) % 10; + if (seconds == 1) { + switch_say_file(sh, "time/t_sekunda"); + }else if (sd != 1 && ( sj == 2 || sj == 3 || sj == 4)) { + switch_say_file(sh, "time/t_sekundy"); + } else { + switch_say_file(sh, "time/t_sekund"); + } + } else { + switch_say_file(sh, "digits/0"); + switch_say_file(sh, "time/t_sekund"); + } + + return SWITCH_STATUS_SUCCESS; + } + + if ((t = atol(tosay)) > 0) { + target = switch_time_make(t, 0); + target_now = switch_micro_time_now(); + } else { + target = switch_micro_time_now(); + target_now = switch_micro_time_now(); + } + + if (tz) { + int check = atoi(tz); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz); + if (check) { + switch_time_exp_tz(&tm, target, check); + switch_time_exp_tz(&tm_now, target_now, check); + } else { + switch_time_exp_tz_name(tz, &tm, target); + switch_time_exp_tz_name(tz, &tm_now, target_now); + } + } else { + switch_time_exp_lt(&tm, target); + switch_time_exp_lt(&tm_now, target_now); + } + + switch (say_args->type) { + case SST_CURRENT_DATE_TIME: + say_date = say_time = 1; + break; + case SST_CURRENT_DATE: + say_date = 1; + break; + case SST_CURRENT_TIME: + say_time = 1; + break; + case SST_SHORT_DATE_TIME: + say_time = 1; + if (tm.tm_year != tm_now.tm_year) { + say_date = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday) { + say_today = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday - 1) { + say_yesterday = 1; + break; + } + if (tm.tm_yday >= tm_now.tm_yday - 5) { + say_dow = 1; + break; + } + if (tm.tm_mon != tm_now.tm_mon) { + say_month = say_day = say_dow = 1; + break; + } + + say_month = say_day = say_dow = 1; + + break; + default: + break; + } + + if (say_today) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SAY: today\n"); + switch_say_file(sh, "time/t_dzisiaj"); + } + if (say_yesterday) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SAY: yesterday\n"); + switch_say_file(sh, "time/t_wczoraj"); + } + if (say_dow) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SAY: dow\n"); + switch_say_file(sh, "time/day-%d", tm.tm_wday); + } + + if (say_date) { + say_year = say_month = say_day = say_dow = 1; + say_today = say_yesterday = 0; + } + + if (say_day) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SAY: day\n"); + //say_num(sh, tm.tm_mday, SSM_COUNTED, SSG_MASCULINE); + switch_say_file(sh, "digits/%02d_pm", tm.tm_mday); + } + if (say_month) { + switch_say_file(sh, "time/mon-%d_D", tm.tm_mon); + } + if (say_year) { + say_num(sh, tm.tm_year + 1900, SSM_COUNTED, SSG_MASCULINE); + //switch_say_file(sh, "time/t_roku"); + } + + if (say_time) { + switch_say_file(sh, "time/t_godzina"); + say_num(sh, tm.tm_hour, SSM_COUNTED, SSG_FEMININE); + //switch_say_file(sh, "digits/%da", tm.tm_hour); + + say_num(sh, tm.tm_min, SSM_PRONOUNCED, SSG_FEMININE); + /* switch_say_file(sh, "digits/t_minut");*/ + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t pl_say_money(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + char sbuf[16] = ""; /* enough for 999,999,999,999.99 (w/o the commas or leading $) */ + char *dollars = NULL; + char *cents = NULL; + + if (strlen(tosay) > 15 || !(tosay = switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)-1))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + dollars = sbuf; + + if ((cents = strchr(sbuf, '.'))) { + *cents++ = '\0'; + if (strlen(cents) > 2) { + cents[2] = '\0'; + } + } + + /* If positive sign - skip over" */ + if (sbuf[0] == '+') { + dollars++; + } + + /* If negative say "negative" */ + if (sbuf[0] == '-') { + switch_say_file(sh, "currency/negative"); + dollars++; + } + + /* Say dollar amount */ + pl_say_general_count(sh, dollars, say_args); + if (atoi(dollars) == 1) { + switch_say_file(sh, "currency/dollar"); + } else { + switch_say_file(sh, "currency/dollars"); + } + + /* Say cents */ + if (cents) { + /* Say "and" */ + switch_say_file(sh, "currency/and"); + + pl_say_general_count(sh, cents, say_args); + if (atoi(cents) == 1) { + switch_say_file(sh, "currency/cent"); + } else { + switch_say_file(sh, "currency/cents"); + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t pl_say_ip(switch_say_file_handle_t *sh, + char *tosay, + switch_say_args_t *say_args) + +{ + char *a, *b, *c, *d; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!(a = strdup(tosay))) { + abort(); + } + + if (!(b = strchr(a, '.'))) { + goto end; + } + + *b++ = '\0'; + + if (!(c = strchr(b, '.'))) { + goto end; + } + + *c++ = '\0'; + + if (!(d = strchr(c, '.'))) { + goto end; + } + + *d++ = '\0'; + + say_num(sh, atoi(a), say_args->method, SSG_MASCULINE); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(b), say_args->method, SSG_MASCULINE); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(c), say_args->method, SSG_MASCULINE); + switch_say_file(sh, "digits/dot"); + say_num(sh, atoi(d), say_args->method, SSG_MASCULINE); + + end: + + free(a); + + return status; +} + + +static switch_status_t pl_say_spell(switch_say_file_handle_t *sh, char *tosay, switch_say_args_t *say_args) +{ + char *p; + + for (p = tosay; p && *p; p++) { + int a = tolower((int) *p); + if (a >= '0' && a <= '9') { + switch_say_file(sh, "digits/%c", a); + } else { + if (say_args->type == SST_NAME_SPELLED) { + switch_say_file(sh, "ascii/%d", a); + } else if (say_args->type == SST_NAME_PHONETIC) { + switch_say_file(sh, "phonetic-ascii/%d", a); + } + } + } + + return SWITCH_STATUS_SUCCESS; +} + + +/* pl */ +static switch_new_say_callback_t choose_callback(switch_say_args_t *say_args) +{ + switch_new_say_callback_t say_cb = NULL; + + switch (say_args->type) { + case SST_NUMBER: + case SST_ITEMS: + case SST_PERSONS: + case SST_MESSAGES: + say_cb = pl_say_general_count; + break; + case SST_TIME_MEASUREMENT: + case SST_CURRENT_DATE: + case SST_CURRENT_TIME: + case SST_CURRENT_DATE_TIME: + case SST_SHORT_DATE_TIME: + say_cb = pl_say_time; + break; + case SST_IP_ADDRESS: + say_cb = pl_say_ip; + break; + case SST_NAME_SPELLED: + case SST_NAME_PHONETIC: + say_cb = pl_say_spell; + break; + case SST_CURRENCY: + say_cb = pl_say_money; + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type); + break; + } + + return say_cb; +} + + +static switch_status_t run_callback(switch_new_say_callback_t say_cb, char *tosay, switch_say_args_t *say_args, switch_core_session_t *session, char **rstr) +{ + switch_say_file_handle_t *sh; + switch_status_t status = SWITCH_STATUS_FALSE; + switch_event_t *var_event = NULL; + + if (session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_get_variables(channel, &var_event); + } + + switch_say_file_handle_create(&sh, say_args->ext, &var_event); + + status = say_cb(sh, tosay, say_args); + + if ((*rstr = switch_say_file_handle_detach_path(sh))) { + status = SWITCH_STATUS_SUCCESS; + } + + switch_say_file_handle_destroy(&sh); + + return status; +} + +/* PL */ +static switch_status_t pl_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + + switch_new_say_callback_t say_cb = NULL; + char *string = NULL; + + switch_status_t status = SWITCH_STATUS_FALSE; + + say_cb = choose_callback(say_args); + + if (say_cb) { + status = run_callback(say_cb, tosay, say_args, session, &string); + if (session && string) { + status = switch_ivr_play_file(session, NULL, string, args); + } + + switch_safe_free(string); + } + + return status; +} + + +/* PL */ +static switch_status_t pl_say_string(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, char **rstr) +{ + + switch_new_say_callback_t say_cb = NULL; + char *string = NULL; + + switch_status_t status = SWITCH_STATUS_FALSE; + + say_cb = choose_callback(say_args); + + if (say_cb) { + status = run_callback(say_cb, tosay, say_args, session, &string); + if (string) { + status = SWITCH_STATUS_SUCCESS; + *rstr = string; + } + } + + return status; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_pl_load) +{ + switch_say_interface_t *say_interface; + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE); + say_interface->interface_name = "pl"; + say_interface->say_function = pl_say; + say_interface->say_string_function = pl_say_string; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */