summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--apps/app_voicemail.c79
-rw-r--r--main/say.c573
3 files changed, 655 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
index 5efe3097d..1d5e0a83a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1028,6 +1028,8 @@ Say
language. The 'language' parameter in say.conf now recognizes a setting of
'ja', which will enable Japanese language specific mechanisms for playing
back numbers, dates, and other items.
+ * Counting, enumeration and dates now supports Icelandic grammar with the
+ 'language' parameter set to 'is'.
SayCountPL
------------------
@@ -5181,6 +5183,7 @@ Voicemail Changes
the message as urgent after he has recorded a voicemail by following the voice instructions.
When listening to voicemails using VoiceMailMain urgent messages will be presented before other
messages
+ * Added "is" language support
Queue changes
-------------
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index 1d5b2dcb3..586086c55 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -8527,6 +8527,8 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v
res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
} else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) { /* GREEK syntax */
res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q H 'digits/kai' M ", NULL);
+ } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
+ res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
} else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
} else if (!strcasecmp(ast_channel_language(chan),"ja")) { /* Japanese syntax */
@@ -8753,6 +8755,12 @@ static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struc
res = wait_file2(chan, vms, "vm-number");
res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
}
+ /* ICELANDIC syntax */
+ } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) {
+ res = wait_file2(chan, vms, "vm-message");
+ if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
+ res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "n");
+ }
/* VIETNAMESE syntax */
} else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
if (!vms->curmsg) {
@@ -9492,6 +9500,75 @@ static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
return res;
}
+/* ICELANDIC syntax */
+static int vm_intro_is(struct ast_channel *chan, struct vm_state *vms)
+{
+ int res;
+
+ /* Introduce messages they have */
+ res = ast_play_and_wait(chan, "vm-youhave");
+ if (!res) {
+ if (vms->urgentmessages) {
+ /* Digits 1-4 are spoken in neutral and plural when talking about messages,
+ however, feminine is used for 1 as it is the same as the neutral for plural,
+ and singular neutral is the same after 1. */
+ if (vms->urgentmessages < 5) {
+ char recname[16];
+ if (vms->urgentmessages == 1)
+ snprintf(recname, sizeof(recname), "digits/1kvk");
+ else
+ snprintf(recname, sizeof(recname), "digits/%dhk", vms->urgentmessages);
+ res = ast_play_and_wait(chan, recname);
+ } else if (!res)
+ res = ast_play_and_wait(chan, "vm-Urgent");
+ if ((vms->oldmessages || vms->newmessages) && !res) {
+ res = ast_play_and_wait(chan, "vm-and");
+ } else if (!res)
+ res = ast_play_and_wait(chan, "vm-messages");
+ }
+ if (vms->newmessages) {
+ if (vms->newmessages < 5) {
+ char recname[16];
+ if (vms->newmessages == 1)
+ snprintf(recname, sizeof(recname), "digits/1kvk");
+ else
+ snprintf(recname, sizeof(recname), "digits/%dhk", vms->newmessages);
+ res = ast_play_and_wait(chan, recname);
+ } else
+ res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
+ if (!res)
+ res = ast_play_and_wait(chan, "vm-INBOX");
+ if (vms->oldmessages && !res)
+ res = ast_play_and_wait(chan, "vm-and");
+ else if (!res)
+ res = ast_play_and_wait(chan, "vm-messages");
+ }
+ if (!res && vms->oldmessages) {
+ if (vms->oldmessages < 5) {
+ char recname[16];
+ if (vms->oldmessages == 1)
+ snprintf(recname, sizeof(recname), "digits/1kvk");
+ else
+ snprintf(recname, sizeof(recname), "digits/%dhk", vms->oldmessages);
+ res = ast_play_and_wait(chan, recname);
+ } else
+ res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
+ if (!res)
+ res = ast_play_and_wait(chan, "vm-Old");
+ if (!res)
+ res = ast_play_and_wait(chan, "vm-messages");
+ }
+ if (!res) {
+ if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
+ res = ast_play_and_wait(chan, "vm-no");
+ if (!res)
+ res = ast_play_and_wait(chan, "vm-messages");
+ }
+ }
+ }
+ return res;
+}
+
/* ITALIAN syntax */
static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
{
@@ -10156,6 +10233,8 @@ static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm
return vm_intro_gr(chan, vms);
} else if (!strncasecmp(ast_channel_language(chan), "he", 2)) { /* HEBREW syntax */
return vm_intro_he(chan, vms);
+ } else if (!strncasecmp(ast_channel_language(chan), "is", 2)) { /* ICELANDIC syntax */
+ return vm_intro_is(chan, vms);
} else if (!strncasecmp(ast_channel_language(chan), "it", 2)) { /* ITALIAN syntax */
return vm_intro_it(chan, vms);
} else if (!strncasecmp(ast_channel_language(chan), "ja", 2)) { /* JAPANESE syntax */
diff --git a/main/say.c b/main/say.c
index 957929326..6e51de201 100644
--- a/main/say.c
+++ b/main/say.c
@@ -317,6 +317,7 @@ static int say_digit_str_full(struct ast_channel *chan, const char *str, const c
\arg \b es - Spanish, Mexican
\arg \b fr - French
\arg \b he - Hebrew
+ \arg \b is - Icelandic
\arg \b it - Italian
\arg \b nl - Dutch
\arg \b no - Norwegian
@@ -373,6 +374,7 @@ static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const ch
static int ast_say_number_full_es(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_fr(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_he(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_is(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_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
static int ast_say_number_full_no(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
@@ -394,6 +396,7 @@ static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const
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_is(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 */
@@ -409,6 +412,7 @@ static int ast_say_date_ka(struct ast_channel *chan, time_t t, const char *ints,
static int ast_say_date_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
static int ast_say_date_th(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
static int ast_say_date_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
+static int ast_say_date_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
static int ast_say_date_with_format_en(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_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
@@ -416,6 +420,7 @@ static int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const
static int ast_say_date_with_format_es(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_he(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_fr(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_is(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_it(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_nl(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_pl(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone);
@@ -511,6 +516,8 @@ static int say_number_full(struct ast_channel *chan, int num, const char *ints,
return ast_say_number_full_he(chan, num, ints, language, options, audiofd, ctrlfd);
} else if (!strncasecmp(language, "hu", 2)) { /* Hungarian syntax */
return ast_say_number_full_hu(chan, num, ints, language, audiofd, ctrlfd);
+ } else if (!strncasecmp(language, "is", 2)) { /* Icelandic syntax */
+ return ast_say_number_full_is(chan, num, ints, language, options, audiofd, ctrlfd);
} else if (!strncasecmp(language, "it", 2)) { /* Italian syntax */
return ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd);
} else if (!strncasecmp(language, "ka", 2)) { /* Georgian syntax */
@@ -1518,6 +1525,129 @@ static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char
return res;
}
+/*! \brief ast_say_number_full_is: Icelandic syntax */
+/* New files:
+ In addition to American English, the following sounds are required: "hundreds", "millions", "1kvk", "1hk", "2kvk", "2hk", "3kvk", "3hk", "4kvk", "4hk"
+ */
+static int ast_say_number_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
+{
+ int res = 0;
+ int playh = 0;
+ int playa = 0;
+ int cn = 1; /* 1 = masc; 2 = fem; 3 = neut */
+ char fn[256] = "";
+
+ if (!num)
+ return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
+
+ if (options && !strncasecmp(options, "f", 1)) cn = 2;
+ if (options && !strncasecmp(options, "c", 1)) cn = 3;
+ /* It seems that sometimes people are using c and sometimes n. */
+ if (options && !strncasecmp(options, "n", 1)) cn = 3;
+
+ while (!res && (num || playh || playa )) {
+ if (num < 0) {
+ ast_copy_string(fn, "digits/minus", sizeof(fn));
+ if ( num > INT_MIN ) {
+ num = -num;
+ } else {
+ num = 0;
+ }
+ } else if (playh) {
+ if (playh > 1)
+ ast_copy_string(fn, "digits/hundreds", sizeof(fn));
+ else
+ ast_copy_string(fn, "digits/hundred", sizeof(fn));
+ playh = 0;
+ } else if (playa) {
+ ast_copy_string(fn, "digits/and", sizeof(fn));
+ playa = 0;
+ } else if (num < 5 && cn == 2) {
+ snprintf(fn, sizeof(fn), "digits/%dkvk", num);
+ num = 0;
+ } else if (num < 5 && cn == 3) {
+ snprintf(fn, sizeof(fn), "digits/%dhk", num);
+ num = 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)
+ playa++;
+ } else if (num < 1000) {
+ int hundreds = num / 100;
+ /* The number prepending hundreds are in neutral */
+ if (hundreds < 5)
+ snprintf(fn, sizeof(fn), "digits/%dhk", hundreds);
+ else
+ snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
+
+ playh = hundreds;
+ num -= 100 * hundreds;
+ if (num && num < 20)
+ playa++;
+ /* The 'and' moves forward on even tens. */
+ if (num && (num % 10) == 0)
+ playa++;
+ } else if (num < 1000000) {
+ res = ast_say_number_full_is(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
+ /* Play 'and' if it's an even hundred. */
+ if ((num % 100) == 0 && (num % 1000 != 0)) {
+ playa++;
+ }
+ if (res)
+ return res;
+ ast_copy_string(fn, "digits/thousand", sizeof(fn));
+ num %= 1000;
+ if (num && (num < 20 || (num % 10 == 0)))
+ playa++;
+ } else if (num < 1000000000) {
+ int millions = num / 1000000;
+ /* The number of millions is feminine */
+ res = ast_say_number_full_is(chan, millions, ints, language, "f", audiofd, ctrlfd);
+ if (res)
+ return res;
+ if (millions > 1)
+ ast_copy_string(fn, "digits/millions", sizeof(fn));
+ else
+ ast_copy_string(fn, "digits/million", sizeof(fn));
+ num %= 1000000;
+ if (num && num < 100)
+ playa++;
+ } else if (num < INT_MAX) {
+ int milliards = num / 1000000000;
+ /* The number of milliards is masculine */
+ res = ast_say_number_full_is(chan, milliards, ints, language, "m", audiofd, ctrlfd);
+ if (res)
+ return res;
+ if (milliards > 1)
+ ast_copy_string(fn, "digits/milliards", sizeof(fn));
+ else
+ ast_copy_string(fn, "digits/milliard", sizeof(fn));
+ num %= 1000000000;
+ if (num && num < 100)
+ playa++;
+ } else {
+ ast_debug(1, "Number '%d' is too big for me\n", num);
+ 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_number_full_it: Italian */
static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
{
@@ -2789,6 +2919,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, "is", 2)) { /* Icelandic syntax */
+ return ast_say_enumeration_full_is(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);
}
@@ -3329,6 +3461,182 @@ static int ast_say_enumeration_full_he(struct ast_channel *chan, int num, const
return res;
}
+/*! \brief ast_say_enumeration_full_is: Icelandic syntax */
+static int ast_say_enumeration_full_is(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
+{
+ /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
+ int res = 0, t = 0;
+ char fn[256] = "", fna[256] = "";
+ char *gender;
+
+ if (options && !strncasecmp(options, "f", 1)) {
+ gender = "F";
+ } else if (options && !strncasecmp(options, "n", 1)) {
+ gender = "N";
+ } else {
+ gender = "";
+ }
+
+ if (!num)
+ return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
+
+ while (!res && num) {
+ if (num < 0) {
+ ast_copy_string(fn, "digits/minus", sizeof(fn)); /* kind of senseless for enumerations, but our best effort for error checking */
+ if ( num > INT_MIN ) {
+ num = -num;
+ } else {
+ num = 0;
+ }
+ } else if (num < 100 && t) {
+ ast_copy_string(fn, "digits/and", sizeof(fn));
+ t = 0;
+ } else if (num < 20) {
+ snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
+ num = 0;
+ } else if (num < 100) {
+ int ones = num % 10;
+ if (ones) {
+ int tens = num - ones;
+ snprintf(fn, sizeof(fn), "digits/h-%d%s", tens, gender);
+ num = ones;
+ t++;
+ }
+ else if (t) {
+ snprintf(fn, sizeof(fn), "digits/and");
+ t = 0;
+ }
+ else {
+ snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
+ num = 0;
+ }
+
+ } else if (num == 100 && t == 0) {
+ snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
+ num = 0;
+ } else if (num < 1000) {
+ int hundreds = num / 100;
+ num = num % 100;
+ if (hundreds == 1) {
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ } else {
+ snprintf(fn, sizeof(fn), "digits/%d", hundreds);
+ }
+ if (num) {
+ ast_copy_string(fna, "digits/hundred", sizeof(fna));
+ } else {
+ snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
+ }
+ t = 1;
+ } else if (num < 1000000) {
+ int thousands = num / 1000;
+ num = num % 1000;
+ if (thousands == 1) {
+ if (num) {
+ /* Thousand is a neutral word, so use the neutral recording */
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ ast_copy_string(fna, "digits/thousand", sizeof(fna));
+ } else {
+ if (t) {
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
+ } else {
+ snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
+ }
+ }
+ } else {
+ res = ast_say_number_full_is(chan, thousands, ints, language, options, audiofd, ctrlfd);
+ if (res) {
+ return res;
+ }
+ if (num) {
+ ast_copy_string(fn, "digits/thousand", sizeof(fn));
+ } else {
+ snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
+ }
+ }
+ if (num)
+ t = 1;
+ } else if (num < 1000000000) {
+ int millions = num / 1000000;
+ num = num % 1000000;
+ if (millions == 1) {
+ if (num) {
+ /* Million is a feminine word, so use the female form */
+ ast_copy_string(fn, "digits/1kvk", sizeof(fn));
+ ast_copy_string(fna, "digits/million", sizeof(fna));
+ } else {
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
+ }
+ } else {
+ res = ast_say_number_full_is(chan, millions, ints, language, options, audiofd, ctrlfd);
+ if (res) {
+ return res;
+ }
+ if (num) {
+ ast_copy_string(fn, "digits/millions", sizeof(fn));
+ } else {
+ snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
+ }
+ }
+ if (num)
+ t = 1;
+ } else if (num < INT_MAX) {
+ int billions = num / 1000000000;
+ num = num % 1000000000;
+ if (billions == 1) {
+ if (num) {
+ ast_copy_string(fn, "digits/1", sizeof(fn));
+ ast_copy_string(fna, "digits/milliard", sizeof(fna));
+ } else {
+ ast_copy_string(fn, "digits/1hk", sizeof(fn));
+ snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
+ }
+ } else {
+ res = ast_say_number_full_is(chan, billions, ints, language, options, audiofd, ctrlfd);
+ if (res)
+ return res;
+ if (num) {
+ ast_copy_string(fn, "digits/milliards", sizeof(fna));
+ } else {
+ snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
+ }
+ }
+ if (num)
+ t = 1;
+ } else if (num == INT_MAX) {
+ snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
+ num = 0;
+ } else {
+ ast_debug(1, "Number '%d' is too big for me\n", num);
+ 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);
+ if (!res) {
+ if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
+ if ((audiofd > -1) && (ctrlfd > -1)) {
+ res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+ } else {
+ res = ast_waitstream(chan, ints);
+ }
+ }
+ ast_stopstream(chan);
+ strcpy(fna, "");
+ }
+ }
+ }
+ return res;
+}
+
static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
{
if (!strncasecmp(lang, "en", 2)) { /* English syntax */
@@ -3353,6 +3661,8 @@ static int say_date(struct ast_channel *chan, time_t t, const char *ints, const
return ast_say_date_he(chan, t, ints, lang);
} else if (!strncasecmp(lang, "hu", 2)) { /* Hungarian syntax */
return ast_say_date_hu(chan, t, ints, lang);
+ } else if (!strncasecmp(lang, "is", 2)) { /* Icelandic syntax */
+ return ast_say_date_is(chan, t, ints, lang);
} else if (!strncasecmp(lang, "ka", 2)) { /* Georgian syntax */
return ast_say_date_ka(chan, t, ints, lang);
} else if (!strncasecmp(lang, "nl", 2)) { /* Dutch syntax */
@@ -3682,6 +3992,55 @@ int ast_say_date_he(struct ast_channel *chan, time_t t, const char *ints, const
return res;
}
+/* Icelandic syntax */
+int ast_say_date_is(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
+{
+ struct timeval when = { t, 0 };
+ struct ast_tm tm;
+ char fn[256];
+ int res = 0;
+ ast_localtime(&when, &tm, NULL);
+ if (!res) {
+ snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
+ res = ast_streamfile(chan, fn, lang);
+ if (!res)
+ res = ast_waitstream(chan, ints);
+ }
+ if (!res)
+ res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
+ if (!res)
+ res = ast_waitstream(chan, ints);
+ if (!res) {
+ snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
+ res = ast_streamfile(chan, fn, lang);
+ if (!res)
+ res = ast_waitstream(chan, ints);
+ }
+ if (!res) {
+ /* Year */
+ int year = tm.tm_year + 1900;
+ if (year > 1999) { /* year 2000 and later */
+ res = ast_say_number(chan, year, ints, lang, (char *) NULL);
+ } else {
+ if (year < 1100) {
+ /* I'm not going to handle 1100 and prior */
+ /* We'll just be silent on the year, instead of bombing out. */
+ } else {
+ /* year 1100 to 1999. will anybody need this?!? */
+ snprintf(fn, sizeof(fn), "digits/%d", (year / 100));
+ res = wait_file(chan, ints, fn, lang);
+ if (!res) {
+ res = wait_file(chan, ints, "digits/hundred", lang);
+ if (!res && year % 100 != 0) {
+ res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);
+ }
+ }
+ }
+ }
+ }
+ return res;
+}
+
static int say_date_with_format(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *tzone)
{
if (!strncasecmp(lang, "en", 2)) { /* English syntax */
@@ -3698,6 +4057,8 @@ static int say_date_with_format(struct ast_channel *chan, time_t t, const char *
return ast_say_date_with_format_fr(chan, t, ints, lang, format, tzone);
} else if (!strncasecmp(lang, "gr", 2)) { /* Greek syntax */
return ast_say_date_with_format_gr(chan, t, ints, lang, format, tzone);
+ } else if (!strncasecmp(lang, "is", 2)) { /* Icelandic syntax */
+ return ast_say_date_with_format_is(chan, t, ints, lang, format, tzone);
} else if (!strncasecmp(lang, "ja", 2)) { /* Japanese syntax */
return ast_say_date_with_format_ja(chan, t, ints, lang, format, tzone);
} else if (!strncasecmp(lang, "it", 2)) { /* Italian syntax */
@@ -4384,6 +4745,218 @@ int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const char *
return res;
}
+/* Icelandic syntax */
+int ast_say_date_with_format_is(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)
+ format = "A dBY HMS";
+
+ ast_localtime(&when, &tm, tzone);
+
+ 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 */
+ for (sndoffset = 0; !strchr("\'\0", format[++offset]) && (sndoffset < sizeof(sndfile) - 1) ; 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, "m");
+ break;
+ case 'd':
+ case 'e':
+ /* First - Thirtyfirst */
+ res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, "m");
+ break;
+ case 'Y':
+ /* Year */
+ {
+ int year = tm.tm_year + 1900;
+ if (year > 1999) { /* year 2000 and later */
+ res = ast_say_number(chan, year, ints, lang, (char *) NULL);
+ } else {
+ if (year < 1100) {
+ /* I'm not going to handle 1100 and prior */
+ /* We'll just be silent on the year, instead of bombing out. */
+ } else {
+ /* year 1100 to 1999. will anybody need this?!? */
+ /* say 1967 as 'nineteen hundred seven and sixty' */
+ snprintf(nextmsg, sizeof(nextmsg), "digits/%d", (year / 100) );
+ res = wait_file(chan, ints, nextmsg, lang);
+ if (!res) {
+ res = wait_file(chan, ints, "digits/hundred", lang);
+ if (!res && year % 100 != 0) {
+ res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 'I':
+ case 'l':
+ /* 12-Hour */
+ res = wait_file(chan, ints, "digits/oclock", lang);
+ 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);
+ if (!res) {
+ res = wait_file(chan, ints, nextmsg, lang);
+ }
+ break;
+ case 'H':
+ /* 24-Hour, single digit hours preceeded by "oh" (0) */
+ if (tm.tm_hour < 10 && tm.tm_hour > 0) {
+ res = wait_file(chan, ints, "digits/0", lang);
+ }
+ /* FALLTRHU */
+ case 'k':
+ /* 24-Hour */
+ res = ast_say_number(chan, tm.tm_hour, ints, lang, "n");
+ break;
+ case 'M':
+ /* Minute */
+ if (tm.tm_min > 0 || next_item(&format[offset + 1]) == 'S') { /* zero 'digits/0' only if seconds follow */
+ if (tm.tm_min < 10)
+ res = wait_file(chan, ints, "digits/0", lang);
+ /* Gender depends on whether or not seconds follow */
+ if (next_item(&format[offset + 1]) == 'S')
+ res = ast_say_number(chan, tm.tm_min, ints, lang, "f");
+ else
+ res = ast_say_number(chan, tm.tm_min, ints, lang, "n");
+ }
+ if (!res && next_item(&format[offset + 1]) == 'S') { /* minutes only if seconds follow */
+ /* Say minute/minutes depending on whether minutes end in 1 */
+ if ((tm.tm_min % 10 == 1) && (tm.tm_min != 11)) {
+ res = wait_file(chan, ints, "digits/minute", lang);
+ } else {
+ res = wait_file(chan, ints, "digits/minutes", lang);
+ }
+ }
+ 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 AdBY */
+ /* 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;
+
+ 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 {
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "AdBY", tzone);
+ }
+ }
+ break;
+ case 'q':
+ /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */
+ /* 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;
+
+ 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_is(chan, t, ints, lang, "A", tzone);
+ } else {
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "AdBY", tzone);
+ }
+ }
+ break;
+ case 'R':
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "HM", tzone);
+ break;
+ case 'S':
+ /* Seconds */
+ res = wait_file(chan, ints, "digits/and", lang);
+ if (!res) {
+ res = ast_say_number(chan, tm.tm_sec, ints, lang, "f");
+ /* Say minute/minutes depending on whether seconds end in 1 */
+ if (!res && (tm.tm_sec % 10 == 1) && (tm.tm_sec != 11)) {
+ res = wait_file(chan, ints, "digits/second", lang);
+ } else {
+ res = wait_file(chan, ints, "digits/seconds", lang);
+ }
+ }
+ break;
+ case 'T':
+ res = ast_say_date_with_format_is(chan, t, ints, lang, "HMS", 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;
+}
+
/*! \brief Thai syntax */
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)
{