--- say.c.orig 2004-05-02 18:54:37.000000000 +0100 +++ say.c 2004-05-02 18:54:26.000000000 +0100 @@ -106,11 +106,22 @@ For Portuguese, we're using m & f options to saynumber() to indicate if the gender is masculine or feminine. For Danish, we're using c & n options to saynumber() to indicate if the gender is commune or neutrum. This still needs to be implemented for French, Spanish & German. + + Date/Time functions currently have less languages supported than saynumber(). Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK See contrib/i18n.testsuite.conf for some examples of the different syntaxes + Portuguese sound files needed for Time/Date functions: + pt-ah + pt-ao + pt-de + pt-ora + pt-meianoite + pt-meiodia + pt-sss + OEJ 2004-04-25 FPB 2004-05-01 */ @@ -123,6 +134,30 @@ static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); +static int ast_say_date_en(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_date_nl(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_date_pt(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); +static int ast_say_date_with_format_nl(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); +static int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); +static int ast_say_time_en(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_time_nl(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_time_pt(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_datetime_en(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, char *ints, char *lang); +static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, char *ints, char *lang); + +static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang) +{ + int res; + if ((res = ast_streamfile(chan, file, lang))) + ast_log(LOG_WARNING, "Unable to play message %s\n", file); + if (!res) + res = ast_waitstream(chan, ints); + return res; +} /*--- ast_say_number_full: call language-specific functions */ /* Called from AGI */ @@ -647,7 +682,7 @@ compound, but with exceptions. For example 21 is not twenty-one, but is a single word in it. Idem for 28 (ie when a the 2nd part of a compund number - starts with a wovel) + starts with a vowel) There're exceptions also for hundred, thounsand and million. In english 100 = one hundred, 200 is two hundred. @@ -872,7 +907,7 @@ } /*--- ast_say_number_full_nl: dutch syntax */ -/* New files: ??? +/* New files: digits/nl-en */ static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) { @@ -948,6 +983,22 @@ int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang) { + if (!strcasecmp(lang,"en") ) { /* English syntax */ + return(ast_say_date_en(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ + return(ast_say_date_nl(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ + return(ast_say_date_pt(chan, t, ints, lang)); + } + + /* Default to English */ + return(ast_say_date_en(chan, t, ints, lang)); +} + + +/* English syntax */ +int ast_say_date_en(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ struct tm tm; char fn[256]; int res = 0; @@ -966,8 +1017,6 @@ } if (!res) res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); - /* Should portuguese add a gender here? Defaults to masculin */ - if (!res) res = ast_waitstream(chan, ints); if (!res) @@ -975,18 +1024,77 @@ return res; } -static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang) +/* Dutch syntax */ +int ast_say_date_nl(struct ast_channel *chan, time_t t, char *ints, char *lang) { - int res; - if ((res = ast_streamfile(chan, file, lang))) - ast_log(LOG_WARNING, "Unable to play message %s\n", file); + struct tm tm; + char fn[256]; + int res = 0; + ast_localtime(&t,&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_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); + 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) res = ast_waitstream(chan, ints); + if (!res) + res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); + return res; +} + +/* Portuguese syntax */ +int ast_say_date_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + struct tm tm; + char fn[256]; + int res = 0; + ast_localtime(&t,&tm,NULL); + localtime_r(&t,&tm); + snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); + if (!res) + res = wait_file(chan, ints, fn, lang); + if (!res) + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); + if (!res) + res = wait_file(chan, ints, "digits/pt-de", lang); + snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); + if (!res) + res = wait_file(chan, ints, fn, lang); + if (!res) + res = wait_file(chan, ints, "digits/pt-de", lang); + if (!res) + res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); + return res; } int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) { + if (!strcasecmp(lang, "en") ) { /* English syntax */ + return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone)); + } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ + return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone)); + } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ + return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone)); + } + + /* Default to English */ + return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone)); +} + +/* English syntax */ +int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) +{ struct tm tm; int res=0, offset, sndoffset; char sndfile[256], nextmsg[256]; @@ -1265,85 +1373,675 @@ return res; } -int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang) +/* Dutch syntax */ +int ast_say_date_with_format_nl(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) { struct tm tm; - int res = 0; - int hour, pm=0; - localtime_r(&t,&tm); - hour = tm.tm_hour; - if (!hour) - hour = 12; - else if (hour == 12) - pm = 1; - else if (hour > 12) { - hour -= 12; - pm = 1; - } - if (!res) - res = ast_say_number(chan, hour, ints, lang, (char *) NULL); + int res=0, offset, sndoffset; + char sndfile[256], nextmsg[256]; - if (tm.tm_min > 9) { - if (!res) - res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); - } else if (tm.tm_min) { - if (!res) - res = ast_streamfile(chan, "digits/oh", lang); /* This is very english ! */ - if (!res) - res = ast_waitstream(chan, ints); - if (!res) - res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); - } else { - if (!res) - res = ast_streamfile(chan, "digits/oclock", lang); /* This is very english ! */ - if (!res) - res = ast_waitstream(chan, ints); - } - if (pm) { - if (!res) - res = ast_streamfile(chan, "digits/p-m", lang); - } else { - if (!res) - res = ast_streamfile(chan, "digits/a-m", lang); - } - if (!res) - res = ast_waitstream(chan, ints); - return res; -} + ast_localtime(&time,&tm,timezone); -int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang) -{ - struct tm tm; - char fn[256]; - int res = 0; - int hour, pm=0; - localtime_r(&t,&tm); - 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) { - 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) - res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); + for (offset=0 ; format[offset] != '\0' ; offset++) { + ast_log(LOG_DEBUG, "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'; + snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile); + res = wait_file(chan,ints,nextmsg,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 'd': + case 'e': + /* First - Thirtyfirst */ + res = ast_say_number(chan, tm.tm_mday, ints, lang, NULL); + break; + case 'Y': + /* Year */ + if (tm.tm_year > 99) { + res = wait_file(chan,ints, "digits/2",lang); + if (!res) { + res = wait_file(chan,ints, "digits/thousand",lang); + } + if (tm.tm_year > 100) { + if (!res) { + /* This works until the end of 2020 */ + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); + res = wait_file(chan,ints,nextmsg,lang); + } + } + } 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/oh",lang); + if (!res) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); + res = wait_file(chan,ints,nextmsg,lang); + } + } else if (tm.tm_year <= 20) { + /* 1910 - 1920 */ + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); + res = wait_file(chan,ints,nextmsg,lang); + } else { + /* 1921 - 1999 */ + int ten, one; + ten = tm.tm_year / 10; + one = tm.tm_year % 10; + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); + res = wait_file(chan,ints,nextmsg,lang); + if (!res) { + if (one != 0) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); + res = wait_file(chan,ints,nextmsg,lang); + } + } + } + } + } + } + break; + case 'I': + case 'l': + /* 12-Hour */ + if (tm.tm_hour == 0) + snprintf(nextmsg,sizeof(nextmsg), "digits/12"); + 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 */ + res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL); + if (!res) { + res = wait_file(chan,ints, "digits/nl-uur",lang); + } + break; + case 'M': + /* 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) + snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); + else + snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); + res = wait_file(chan,ints,nextmsg,lang); + break; + case 'Q': + /* Shorthand for "Today", "Yesterday", or ABdY */ + { + struct timeval now; + struct tm tmnow; + time_t beg_today; - hour = tm.tm_hour; - if (!hour) - hour = 12; - else if (hour == 12) - pm = 1; - else if (hour > 12) { - hour -= 12; - pm = 1; - } - if (!res) - res = ast_say_number(chan, hour, ints, lang, (char *) NULL); + gettimeofday(&now,NULL); + ast_localtime(&now.tv_sec,&tmnow,timezone); + /* 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 < time) { + /* Today */ + res = wait_file(chan,ints, "digits/today",lang); + } else if (beg_today - 86400 < time) { + /* Yesterday */ + res = wait_file(chan,ints, "digits/yesterday",lang); + } else { + res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); + } + } + break; + case 'q': + /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ + { + struct timeval now; + struct tm tmnow; + time_t beg_today; + + gettimeofday(&now,NULL); + ast_localtime(&now.tv_sec,&tmnow,timezone); + /* 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 < time) { + /* Today */ + } else if ((beg_today - 86400) < time) { + /* Yesterday */ + res = wait_file(chan,ints, "digits/yesterday",lang); + } else if (beg_today - 86400 * 6 < time) { + /* Within the last week */ + res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); + } else { + res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); + } + } + break; + case 'R': + res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); + break; + case 'S': + /* Seconds */ + if (tm.tm_sec == 0) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); + res = wait_file(chan,ints,nextmsg,lang); + } else if (tm.tm_sec < 10) { + res = wait_file(chan,ints, "digits/oh",lang); + if (!res) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); + res = wait_file(chan,ints,nextmsg,lang); + } + } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); + res = wait_file(chan,ints,nextmsg,lang); + } else { + int ten, one; + ten = (tm.tm_sec / 10) * 10; + one = (tm.tm_sec % 10); + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); + res = wait_file(chan,ints,nextmsg,lang); + if (!res) { + /* Fifty, not fifty-zero */ + if (one != 0) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); + res = wait_file(chan,ints,nextmsg,lang); + } + } + } + break; + case 'T': + res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); + 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; +} + +/* Portuguese syntax */ +int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) +{ + struct tm tm; + int res=0, offset, sndoffset; + char sndfile[256], nextmsg[256]; + + ast_localtime(&time,&tm,timezone); + + for (offset=0 ; format[offset] != '\0' ; offset++) { + ast_log(LOG_DEBUG, "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'; + snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile); + res = wait_file(chan,ints,nextmsg,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 'd': + case 'e': + /* First - Thirtyfirst */ + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); + break; + case 'Y': + /* Year */ + res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); + break; + case 'I': + case 'l': + /* 12-Hour */ + if (tm.tm_hour == 0) { + if (format[offset] == 'I') + res = wait_file(chan, ints, "digits/pt-ah", lang); + if (!res) + res = wait_file(chan, ints, "digits/pt-meianoite", lang); + } + else if (tm.tm_hour == 12) { + if (format[offset] == 'I') + res = wait_file(chan, ints, "digits/pt-ao", lang); + if (!res) + res = wait_file(chan, ints, "digits/pt-meiodia", lang); + } + else { + if (format[offset] == 'I') { + res = wait_file(chan, ints, "digits/pt-ah", lang); + if ((tm.tm_hour % 12) != 1) + if (!res) + res = wait_file(chan, ints, "digits/pt-sss", lang); + } + if (!res) + res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f"); + } + break; + case 'H': + case 'k': + /* 24-Hour */ + res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL); + if (!res) { + if (tm.tm_hour != 0) { + int remainder = tm.tm_hour; + if (tm.tm_hour > 20) { + res = wait_file(chan,ints, "digits/20",lang); + remainder -= 20; + } + if (!res) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); + res = wait_file(chan,ints,nextmsg,lang); + } + } + } + break; + case 'M': + /* Minute */ + if (tm.tm_min == 0) { + res = wait_file(chan, ints, "digits/pt-hora", lang); + if (tm.tm_hour != 1) + if (!res) + res = wait_file(chan, ints, "digits/pt-sss", lang); } + else { + res = wait_file(chan,ints,"digits/pt-e",lang); + if (!res) + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); + } + break; + case 'P': + case 'p': + /* AM/PM */ + if (tm.tm_hour > 12) + res = wait_file(chan, ints, "digits/p-m", lang); + else if (tm.tm_hour && tm.tm_hour < 12) + res = wait_file(chan, ints, "digits/a-m", lang); + break; + case 'Q': + /* Shorthand for "Today", "Yesterday", or ABdY */ + { + struct timeval now; + struct tm tmnow; + time_t beg_today; + + gettimeofday(&now,NULL); + ast_localtime(&now.tv_sec,&tmnow,timezone); + /* 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 < time) { + /* Today */ + res = wait_file(chan,ints, "digits/today",lang); + } else if (beg_today - 86400 < time) { + /* Yesterday */ + res = wait_file(chan,ints, "digits/yesterday",lang); + } else { + res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone); + } + } + break; + case 'q': + /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ + { + struct timeval now; + struct tm tmnow; + time_t beg_today; + + gettimeofday(&now,NULL); + ast_localtime(&now.tv_sec,&tmnow,timezone); + /* 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 < time) { + /* Today */ + } else if ((beg_today - 86400) < time) { + /* Yesterday */ + res = wait_file(chan,ints, "digits/yesterday",lang); + } else if (beg_today - 86400 * 6 < time) { + /* Within the last week */ + res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); + } else { + res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone); + } + } + break; + case 'R': + res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/pt-e' M", timezone); + break; + case 'S': + /* Seconds */ + if (tm.tm_sec == 0) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); + res = wait_file(chan,ints,nextmsg,lang); + } else if (tm.tm_sec < 10) { + res = wait_file(chan,ints, "digits/oh",lang); + if (!res) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); + res = wait_file(chan,ints,nextmsg,lang); + } + } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); + res = wait_file(chan,ints,nextmsg,lang); + } else { + int ten, one; + ten = (tm.tm_sec / 10) * 10; + one = (tm.tm_sec % 10); + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); + res = wait_file(chan,ints,nextmsg,lang); + if (!res) { + /* Fifty, not fifty-zero */ + if (one != 0) { + snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); + res = wait_file(chan,ints,nextmsg,lang); + } + } + } + break; + case 'T': + res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); + 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; +} + +int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + if (!strcasecmp(lang, "en") ) { /* English syntax */ + return(ast_say_time_en(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ + return(ast_say_time_nl(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ + return(ast_say_time_pt(chan, t, ints, lang)); + } + + /* Default to English */ + return(ast_say_time_en(chan, t, ints, lang)); +} + +/* English syntax */ +int ast_say_time_en(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + struct tm tm; + int res = 0; + int hour, pm=0; + localtime_r(&t,&tm); + hour = tm.tm_hour; + if (!hour) + hour = 12; + else if (hour == 12) + pm = 1; + else if (hour > 12) { + hour -= 12; + pm = 1; + } + if (!res) + res = ast_say_number(chan, hour, ints, lang, (char *) NULL); + + if (tm.tm_min > 9) { + if (!res) + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); + } else if (tm.tm_min) { + if (!res) + res = ast_streamfile(chan, "digits/oh", lang); + if (!res) + res = ast_waitstream(chan, ints); + if (!res) + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); + } else { + if (!res) + res = ast_streamfile(chan, "digits/oclock", lang); + if (!res) + res = ast_waitstream(chan, ints); + } + if (pm) { + if (!res) + res = ast_streamfile(chan, "digits/p-m", lang); + } else { + if (!res) + res = ast_streamfile(chan, "digits/a-m", lang); + } + if (!res) + res = ast_waitstream(chan, ints); + return res; +} + +/* Dutch syntax */ +int ast_say_time_nl(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + struct tm tm; + int res = 0; + int hour; + localtime_r(&t,&tm); + hour = tm.tm_hour; + if (!res) + res = ast_say_number(chan, hour, ints, lang, (char *) NULL); + + if (!res) + res = ast_streamfile(chan, "digits/nl-uur", lang); + if (!res) + res = ast_waitstream(chan, ints); + if (!res) + if (tm.tm_min > 0) + res = ast_say_number(chan, tm.tm_min, ints, lang, NULL); + return res; +} + +/* Portuguese syntax */ +int ast_say_time_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + struct tm tm; + int res = 0; + int hour; + localtime_r(&t,&tm); + hour = tm.tm_hour; + if (!res) + res = ast_say_number(chan, hour, ints, lang, "f"); + if (tm.tm_min) { + if (!res) + res = wait_file(chan, ints, "digits/pt-e", lang); + if (!res) + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); + } + else { + if (!res) + res = wait_file(chan, ints, "digits/pt-hora", lang); + if (tm.tm_hour != 1) + if (!res) + res = wait_file(chan, ints, "digits/pt-sss", lang); + } + if (!res) + res = ast_say_number(chan, hour, ints, lang, (char *) NULL); + return res; +} + +int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + if (!strcasecmp(lang, "en") ) { /* English syntax */ + return(ast_say_datetime_en(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ + return(ast_say_datetime_nl(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ + return(ast_say_datetime_pt(chan, t, ints, lang)); + } + + /* Default to English */ + return(ast_say_datetime_en(chan, t, ints, lang)); +} + +/* English syntax */ +int ast_say_datetime_en(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + struct tm tm; + char fn[256]; + int res = 0; + int hour, pm=0; + localtime_r(&t,&tm); + 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) { + 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) + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); + + hour = tm.tm_hour; + if (!hour) + hour = 12; + else if (hour == 12) + pm = 1; + else if (hour > 12) { + hour -= 12; + pm = 1; + } + if (!res) + res = ast_say_number(chan, hour, ints, lang, (char *) NULL); + + if (tm.tm_min > 9) { + if (!res) + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); + } else if (tm.tm_min) { + if (!res) + res = ast_streamfile(chan, "digits/oh", lang); + if (!res) + res = ast_waitstream(chan, ints); + if (!res) + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); + } else { + if (!res) + res = ast_streamfile(chan, "digits/oclock", lang); + if (!res) + res = ast_waitstream(chan, ints); + } + if (pm) { + if (!res) + res = ast_streamfile(chan, "digits/p-m", lang); + } else { + if (!res) + res = ast_streamfile(chan, "digits/a-m", lang); + } + if (!res) + res = ast_waitstream(chan, ints); + if (!res) + res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); + return res; +} + +/* Dutch syntax */ +int ast_say_datetime_nl(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + struct tm tm; + int res = 0; + localtime_r(&t,&tm); + res = ast_say_date(chan, t, ints, lang); + if (!res) { + res = ast_streamfile(chan, "digits/nl-om", lang); + if (!res) + res = ast_waitstream(chan, ints); + } + if (!res) + ast_say_time(chan, t, ints, lang); + return res; +} + +/* Portuguese syntax */ +int ast_say_datetime_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + struct tm tm; + char fn[256]; + int res = 0; + int hour, pm=0; + localtime_r(&t,&tm); + 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) { + 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) + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); + + hour = tm.tm_hour; + if (!hour) + hour = 12; + else if (hour == 12) + pm = 1; + else if (hour > 12) { + hour -= 12; + pm = 1; + } + if (!res) + res = ast_say_number(chan, hour, ints, lang, (char *) NULL); if (tm.tm_min > 9) { if (!res) @@ -1377,6 +2075,19 @@ int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, char *lang) { + if (!strcasecmp(lang, "en") ) { /* English syntax */ + return(ast_say_datetime_from_now_en(chan, t, ints, lang)); + } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ + return(ast_say_datetime_from_now_pt(chan, t, ints, lang)); + } + + /* Default to English */ + return(ast_say_datetime_from_now_en(chan, t, ints, lang)); +} + +/* English syntax */ +int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ int res=0; time_t nowt; int daydiff; @@ -1414,3 +2125,45 @@ return res; } +/* Portuguese syntax */ +int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) +{ + int res=0; + time_t nowt; + int daydiff; + struct tm tm; + struct tm now; + char fn[256]; + + time(&nowt); + + localtime_r(&t,&tm); + localtime_r(&nowt,&now); + daydiff = now.tm_yday - tm.tm_yday; + if ((daydiff < 0) || (daydiff > 6)) { + /* Day of month and month */ + if (!res) + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); + if (!res) + res = wait_file(chan, ints, "digits/pt-de", lang); + snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); + if (!res) + res = wait_file(chan, ints, fn, lang); + + } + else if (daydiff) { + /* Just what day of the week */ + snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); + if (!res) + res = wait_file(chan, ints, fn, lang); + } /* Otherwise, it was today */ + snprintf(fn, sizeof(fn), "digits/pt-ah"); + if (!res) + res = wait_file(chan, ints, fn, lang); + if (tm.tm_hour != 1) + if (!res) + res = wait_file(chan, ints, "digits/pt-sss", lang); + if (!res) + res = ast_say_time(chan, t, ints, lang); + return res; +}