diff options
author | qwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-12-30 22:30:21 +0000 |
---|---|---|
committer | qwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-12-30 22:30:21 +0000 |
commit | a83d55b29673bfd70c51d2dc316f99281d88e653 (patch) | |
tree | 72c68b814cbc7f01a3dad40a5fca5d00d1061223 /main/say.c | |
parent | 67e91a0f7cf02849ae25a6aaafc1822f7a46a94a (diff) |
Add app_voicemail and say.c support for Vietnamese.
Also add an XXX comment that I'm baffled nobody has ever complained about. We
say "first message", and then we go into language-specific stuff where we
proceed to say..."first message".
(closes issue #15053)
Reported by: dinhtrung
Patches:
vietnamese.ods uploaded by dinhtrung (license 776)
app_voicemail.c.diff uploaded by dinhtrung (license 776)
(closes issue #15626)
Reported by: dinhtrung
Patches:
say.c.diff uploaded by dinhtrung (license 776)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@237050 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main/say.c')
-rw-r--r-- | main/say.c | 336 |
1 files changed, 335 insertions, 1 deletions
diff --git a/main/say.c b/main/say.c index c3ca18565..89ff4f6bf 100644 --- a/main/say.c +++ b/main/say.c @@ -350,12 +350,14 @@ static int ast_say_number_full_ka(struct ast_channel *chan, int num, const char static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); static int ast_say_number_full_th(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); static int ast_say_number_full_ur(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); +static int ast_say_number_full_vi(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); /* Forward declarations of language specific variants of ast_say_enumeration_full */ static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); static int ast_say_enumeration_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); static int ast_say_enumeration_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd); +static int ast_say_enumeration_full_vi(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */ static int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang); @@ -383,6 +385,7 @@ static int ast_say_date_with_format_pt(struct ast_channel *chan, time_t t, const static int ast_say_date_with_format_zh(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_date_with_format_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_date_with_format_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); +static int ast_say_date_with_format_vi(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone); static int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang); static int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang); @@ -496,6 +499,8 @@ static int say_number_full(struct ast_channel *chan, int num, const char *ints, return ast_say_number_full_zh(chan, num, ints, language, audiofd, ctrlfd); } else if (!strncasecmp(language, "ur", 2)) { /* Urdu syntax */ return ast_say_number_full_ur(chan, num, ints, language, options, audiofd, ctrlfd); + } else if (!strncasecmp(language, "vi", 2)) { /* Vietnamese syntax */ + return ast_say_number_full_vi(chan, num, ints, language, audiofd, ctrlfd); } /* Default to english */ @@ -2612,6 +2617,101 @@ static int ast_say_number_full_th(struct ast_channel *chan, int num, const char return res; } +/*! \brief ast_say_number_full_vi: Vietnamese syntax */ +static int ast_say_number_full_vi(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) +{ + int res = 0; + int playh = 0; + int playoh = 0; + int playohz = 0; + int playz = 0; + int playl = 0; + char fn[256] = ""; + if (!num) + return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd); + while (!res && (num || playh)) { + if (num < 0) { + ast_copy_string(fn, "digits/minus", sizeof(fn)); + if ( num > INT_MIN ) { + num = -num; + } else { + num = 0; + } + } else if (playl) { + snprintf(fn, sizeof(fn), "digits/%da", num); + playl = 0; + num = 0; + } else if (playh) { + ast_copy_string(fn, "digits/hundred", sizeof(fn)); + playh = 0; + } else if (playz) { + ast_copy_string(fn, "digits/odd", sizeof(fn)); + playz = 0; + } else if (playoh) { + ast_copy_string(fn, "digits/0-hundred", sizeof(fn)); + playoh = 0; + } else if (playohz) { + ast_copy_string(fn, "digits/0-hundred-odd", sizeof(fn)); + playohz = 0; + } else if (num < 20) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else if (num < 100) { + snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); + num %= 10; + if ((num == 5) || (num == 4) || (num == 1)) playl++; + } else { + if (num < 1000) { + snprintf(fn, sizeof(fn), "digits/%d", (num/100)); + num %= 100; + if (num && (num < 10)) { + playz++; + playh++; + } else { + playh++; + } + } else { + if (num < 1000000) { /* 1,000,000 */ + res = ast_say_number_full_vi(chan, num / 1000, ints, language, audiofd, ctrlfd); + if (res) + return res; + num %= 1000; + snprintf(fn, sizeof(fn), "digits/thousand"); + if (num && (num < 10)) { + playohz++; + } else if (num && (num < 100)){ + playoh++; + } else { + playh = 0; + playohz = 0; + playoh = 0; + } + } else { + if (num < 1000000000) { /* 1,000,000,000 */ + res = ast_say_number_full_vi(chan, num / 1000000, ints, language, audiofd, ctrlfd); + if (res) + return res; + num %= 1000000; + ast_copy_string(fn, "digits/million", sizeof(fn)); + } else { + res = -1; + } + } + } + } + if (!res) { + if (!ast_streamfile(chan, fn, language)) { + if ((audiofd > -1) && (ctrlfd > -1)) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + } + } + return res; +} + /*! \brief ast_say_enumeration_full: call language-specific functions */ /* Called from AGI */ static int say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd) @@ -2624,6 +2724,8 @@ static int say_enumeration_full(struct ast_channel *chan, int num, const char *i return ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd); } else if (!strncasecmp(language, "he", 2)) { /* Hebrew syntax */ return ast_say_enumeration_full_he(chan, num, ints, language, options, audiofd, ctrlfd); + } else if (!strncasecmp(language, "vi", 2)) { /* Vietnamese syntax */ + return ast_say_enumeration_full_vi(chan, num, ints, language, audiofd, ctrlfd); } /* Default to english */ @@ -2729,6 +2831,25 @@ static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const return res; } +static int ast_say_enumeration_full_vi(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) +{ + int res = 0; + char fn[256] = ""; + ast_copy_string(fn, "digits/h", sizeof(fn)); + if (!res) { + if (!ast_streamfile(chan, fn, language)) { + if ((audiofd > -1) && (ctrlfd > -1)) { + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + } else { + res = ast_waitstream(chan, ints); + } + } + ast_stopstream(chan); + } + + return ast_say_number_full_vi(chan, num, ints, language, audiofd, ctrlfd); +} + /*! \brief ast_say_enumeration_full_da: Danish syntax */ static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd) { @@ -3534,6 +3655,8 @@ static int say_date_with_format(struct ast_channel *chan, time_t t, const char * return ast_say_date_with_format_zh(chan, t, ints, lang, format, tzone); } else if (!strncasecmp(lang, "zh", 2)) { /* Taiwanese / Chinese syntax */ return ast_say_date_with_format_zh(chan, t, ints, lang, format, tzone); + } else if (!strncasecmp(lang, "vi", 2)) { /* Vietnamese syntax */ + return ast_say_date_with_format_vi(chan, t, ints, lang, format, tzone); } /* Default to English */ @@ -7515,12 +7638,223 @@ static int ast_say_date_with_format_gr(struct ast_channel *chan, time_t t, const return res; } +/* Vietnamese syntax */ +int ast_say_date_with_format_vi(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone) +{ + struct timeval when = { t, 0 }; + struct ast_tm tm; + int res = 0, offset, sndoffset; + char sndfile[256], nextmsg[256]; + if (format == NULL) + format = "A 'digits/day' eB 'digits/year' Y 'digits/at' k 'hours' M 'minutes' p"; + ast_localtime(&when, &tm, tzone); -/*********************************** Georgian Support ***************************************/ + for (offset=0 ; format[offset] != '\0' ; offset++) { + ast_debug(1, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); + switch (format[offset]) { + /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ + case '\'': + /* Literal name of a sound file */ + sndoffset = 0; + for (sndoffset = 0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) + sndfile[sndoffset] = format[offset]; + sndfile[sndoffset] = '\0'; + res = wait_file(chan, ints, sndfile, lang); + break; + case 'A': + case 'a': + /* Sunday - Saturday */ + snprintf(nextmsg, sizeof(nextmsg), "digits/day-%d", tm.tm_wday); + res = wait_file(chan, ints, nextmsg, lang); + break; + case 'B': + case 'b': + case 'h': + /* January - December */ + snprintf(nextmsg, sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); + res = wait_file(chan, ints, nextmsg, lang); + break; + case 'm': + /* Month enumerated */ + res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, (char *) NULL); + break; + case 'd': + case 'e': + /* 1 - 31 */ + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); + break; + case 'Y': + /* Year */ + if (tm.tm_year > 99) { + res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); + } else if (tm.tm_year < 1) { + /* I'm not going to handle 1900 and prior */ + /* We'll just be silent on the year, instead of bombing out. */ + } else { + res = wait_file(chan, ints, "digits/19", lang); + if (!res) { + if (tm.tm_year <= 9) { + /* 1901 - 1909 */ + res = wait_file(chan, ints, "digits/odd", lang); + } + + res |= ast_say_number(chan, tm.tm_year, ints, lang, (char *) NULL); + } + } + break; + case 'I': + case 'l': + /* 12-Hour */ + if (tm.tm_hour == 0) + ast_copy_string(nextmsg, "digits/12", sizeof(nextmsg)); + else if (tm.tm_hour > 12) + snprintf(nextmsg, sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); + else + snprintf(nextmsg, sizeof(nextmsg), "digits/%d", tm.tm_hour); + res = wait_file(chan, ints, nextmsg, lang); + break; + case 'H': + case 'k': + /* 24-Hour */ + if (format[offset] == 'H') { + /* e.g. oh-eight */ + if (tm.tm_hour < 10) { + res = wait_file(chan, ints, "digits/0", lang); + } + } else { + /* e.g. eight */ + if (tm.tm_hour == 0) { + res = wait_file(chan, ints, "digits/0", lang); + } + } + if (!res) { + if (tm.tm_hour != 0) { + int remaining = tm.tm_hour; + if (tm.tm_hour > 20) { + res = wait_file(chan, ints, "digits/20", lang); + remaining -= 20; + } + if (!res) { + snprintf(nextmsg, sizeof(nextmsg), "digits/%d", remaining); + res = wait_file(chan, ints, nextmsg, lang); + } + } + } + break; + case 'M': + case 'N': + /* Minute */ + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); + break; + case 'P': + case 'p': + /* AM/PM */ + if (tm.tm_hour > 11) + ast_copy_string(nextmsg, "digits/p-m", sizeof(nextmsg)); + else + ast_copy_string(nextmsg, "digits/a-m", sizeof(nextmsg)); + res = wait_file(chan, ints, nextmsg, lang); + break; + case 'Q': + /* Shorthand for "Today", "Yesterday", or ABdY */ + /* XXX As emphasized elsewhere, this should the native way in your + * language to say the date, with changes in what you say, depending + * upon how recent the date is. XXX */ + { + struct timeval now = ast_tvnow(); + struct ast_tm tmnow; + time_t beg_today; + + gettimeofday(&now, NULL); + ast_localtime(&now, &tmnow, tzone); + /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ + /* In any case, it saves not having to do ast_mktime() */ + beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); + if (beg_today < t) { + /* Today */ + res = wait_file(chan, ints, "digits/today", lang); + } else if (beg_today - 86400 < t) { + /* Yesterday */ + res = wait_file(chan, ints, "digits/yesterday", lang); + } else if (beg_today - 86400 * 6 < t) { + /* Within the last week */ + res = ast_say_date_with_format_vi(chan, t, ints, lang, "A", tzone); + } else if (beg_today - 2628000 < t) { + /* Less than a month ago - "Chu nhat ngay 13 thang 2" */ + res = ast_say_date_with_format_vi(chan, t, ints, lang, "A 'digits/day' dB", tzone); + } else if (beg_today - 15768000 < t) { + /* Less than 6 months ago - "August seventh" */ + res = ast_say_date_with_format_vi(chan, t, ints, lang, "'digits/day' dB", tzone); + } else { + /* More than 6 months ago - "April nineteenth two thousand three" */ + res = ast_say_date_with_format_vi(chan, t, ints, lang, "'digits/day' dB 'digits/year' Y", tzone); + } + } + break; + case 'q': + /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ + /* XXX As emphasized elsewhere, this should the native way in your + * language to say the date, with changes in what you say, depending + * upon how recent the date is. XXX */ + { + struct timeval now; + struct ast_tm tmnow; + time_t beg_today; + now = ast_tvnow(); + ast_localtime(&now, &tmnow, tzone); + /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ + /* In any case, it saves not having to do ast_mktime() */ + beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); + if (beg_today < t) { + /* Today */ + } else if ((beg_today - 86400) < t) { + /* Yesterday */ + res = wait_file(chan, ints, "digits/yesterday", lang); + } else if (beg_today - 86400 * 6 < t) { + /* Within the last week */ + res = ast_say_date_with_format_en(chan, t, ints, lang, "A", tzone); + } else if (beg_today - 2628000 < t) { + /* Less than a month ago - "Chu nhat ngay 13 thang 2" */ + res = ast_say_date_with_format_vi(chan, t, ints, lang, "A 'digits/day' dB", tzone); + } else if (beg_today - 15768000 < t) { + /* Less than 6 months ago - "August seventh" */ + res = ast_say_date_with_format_vi(chan, t, ints, lang, "'digits/day' dB", tzone); + } else { + /* More than 6 months ago - "April nineteenth two thousand three" */ + res = ast_say_date_with_format_vi(chan, t, ints, lang, "'digits/day' dB 'digits/year' Y", tzone); + } + } + break; + case 'R': + res = ast_say_date_with_format_vi(chan, t, ints, lang, "HM", tzone); + break; + case 'S': + /* Seconds */ + res = ast_say_number(chan, tm.tm_sec, ints, lang, (char *) NULL); + break; + case 'T': + res = ast_say_date_with_format_vi(chan, t, ints, lang, "H 'hours' M 'minutes' S 'seconds'", tzone); + break; + case ' ': + case ' ': + /* Just ignore spaces and tabs */ + break; + default: + /* Unknown character */ + ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); + } + /* Jump out on DTMF */ + if (res) { + break; + } + } + return res; +} +/*********************************** Georgian Support ***************************************/ /* Convert a number into a semi-localized string. Only for Georgian. res must be of at least 256 bytes, preallocated. |