2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
7 * George Konstantoulakis <gkon@inaccessnetworks.com>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
22 * \brief Say numbers and dates (maybe words one day too)
24 * \author Mark Spencer <markster@digium.com>
26 * \note 12-16-2004 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr) George Konstantoulakis <gkon@inaccessnetworks.com>
28 * \note 2007-02-08 : Support for Georgian added by Alexander Shaduri <ashaduri@gmail.com>,
29 * Next Generation Networks (NGN).
34 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include <sys/types.h>
39 #include <netinet/in.h>
46 #include <iso/limits_iso.h>
49 #include "asterisk/file.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/logger.h"
52 #include "asterisk/options.h"
53 #include "asterisk/say.h"
54 #include "asterisk/lock.h"
55 #include "asterisk/localtime.h"
56 #include "asterisk/utils.h"
58 /* Forward declaration */
59 static int wait_file(struct ast_channel
*chan
, const char *ints
, const char *file
, const char *lang
);
62 static int say_character_str_full(struct ast_channel
*chan
, const char *str
, const char *ints
, const char *lang
, int audiofd
, int ctrlfd
)
70 while (str
[num
] && !res
) {
80 fn
= "letters/exclaimation-point";
86 fn
= "letters/dollar";
95 fn
= "letters/equals";
101 fn
= "letters/slash";
104 fn
= "letters/space";
116 strcpy(fnbuf
, "digits/X");
122 if ('A' <= ltr
&& ltr
<= 'Z') ltr
+= 'a' - 'A'; /* file names are all lower-case */
123 strcpy(fnbuf
, "letters/X");
127 if (fn
&& ast_fileexists(fn
, NULL
, lang
) > 0) {
128 res
= ast_streamfile(chan
, fn
, lang
);
130 if ((audiofd
> -1) && (ctrlfd
> -1))
131 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
133 res
= ast_waitstream(chan
, ints
);
135 ast_stopstream(chan
);
143 static int say_phonetic_str_full(struct ast_channel
*chan
, const char *str
, const char *ints
, const char *lang
, int audiofd
, int ctrlfd
)
151 while (str
[num
] && !res
) {
161 fn
= "letters/exclaimation-point";
167 fn
= "letters/dollar";
176 fn
= "letters/equals";
182 fn
= "letters/slash";
185 fn
= "letters/space";
196 strcpy(fnbuf
, "digits/X");
200 default: /* '9' falls here... */
202 if ('A' <= ltr
&& ltr
<= 'Z') ltr
+= 'a' - 'A'; /* file names are all lower-case */
203 strcpy(fnbuf
, "phonetic/X_p");
207 if (fn
&& ast_fileexists(fn
, NULL
, lang
) > 0) {
208 res
= ast_streamfile(chan
, fn
, lang
);
210 if ((audiofd
> -1) && (ctrlfd
> -1))
211 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
213 res
= ast_waitstream(chan
, ints
);
215 ast_stopstream(chan
);
223 static int say_digit_str_full(struct ast_channel
*chan
, const char *str
, const char *ints
, const char *lang
, int audiofd
, int ctrlfd
)
230 while (str
[num
] && !res
) {
252 strcpy(fnbuf
, "digits/X");
257 if (fn
&& ast_fileexists(fn
, NULL
, lang
) > 0) {
258 res
= ast_streamfile(chan
, fn
, lang
);
260 if ((audiofd
> -1) && (ctrlfd
> -1))
261 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
263 res
= ast_waitstream(chan
, ints
);
265 ast_stopstream(chan
);
273 /* Forward declarations */
274 /*! \page Def_syntaxlang Asterisk Language Syntaxes supported
275 \note Not really language codes.
276 For these language codes, Asterisk will change the syntax when
277 saying numbers (and in some cases dates and voicemail messages
281 \arg \b en - English (US)
282 \arg \b en_GB - English (British)
283 \arg \b es - Spanish, Mexican
288 \arg \b no - Norwegian
290 \arg \b pt - Portuguese
291 \arg \b pt_BR - Portuguese (Brazil)
293 \arg \b tw - Taiwanese / Chinese
295 \arg \b ge - Georgian
298 For Some languages the numbers differ for gender and plural.
299 \arg Use the option argument 'f' for female, 'm' for male and 'n' for neuter in languages like Portuguese, French, Spanish and German.
300 \arg use the option argument 'c' is for commune and 'n' for neuter gender in nordic languages like Danish, Swedish and Norwegian.
301 use the option argument 'p' for plural enumerations like in German
303 Date/Time functions currently have less languages supported than saynumber().
305 \todo Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
307 See contrib/i18n.testsuite.conf for some examples of the different syntaxes
310 Portuguese sound files needed for Time/Date functions:
321 Spanish sound files needed for Time/Date functions:
326 Italian sound files needed for Time/Date functions:
332 /* Forward declarations of language specific variants of ast_say_number_full */
333 static int ast_say_number_full_en(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
);
334 static int ast_say_number_full_cz(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
);
335 static int ast_say_number_full_da(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
);
336 static int ast_say_number_full_de(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
);
337 static int ast_say_number_full_en_GB(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
);
338 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
);
339 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
);
340 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
);
341 static int ast_say_number_full_it(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
);
342 static int ast_say_number_full_nl(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
);
343 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
);
344 static int ast_say_number_full_pl(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
);
345 static int ast_say_number_full_pt(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
);
346 static int ast_say_number_full_se(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
);
347 static int ast_say_number_full_tw(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
);
348 static int ast_say_number_full_gr(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
);
349 static int ast_say_number_full_ru(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
);
350 static int ast_say_number_full_ge(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
);
352 /* Forward declarations of language specific variants of ast_say_enumeration_full */
353 static int ast_say_enumeration_full_en(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
);
354 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
);
355 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
);
356 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
);
358 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */
359 static int ast_say_date_en(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
360 static int ast_say_date_da(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
361 static int ast_say_date_de(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
362 static int ast_say_date_fr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
363 static int ast_say_date_nl(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
364 static int ast_say_date_pt(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
365 static int ast_say_date_gr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
366 static int ast_say_date_ge(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
367 static int ast_say_date_he(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
369 static int ast_say_date_with_format_en(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
370 static int ast_say_date_with_format_da(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
371 static int ast_say_date_with_format_de(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
372 static int ast_say_date_with_format_es(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
373 static int ast_say_date_with_format_he(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
374 static int ast_say_date_with_format_fr(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
375 static int ast_say_date_with_format_it(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
376 static int ast_say_date_with_format_nl(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
377 static int ast_say_date_with_format_pl(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
378 static int ast_say_date_with_format_pt(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
379 static int ast_say_date_with_format_tw(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
380 static int ast_say_date_with_format_gr(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
);
382 static int ast_say_time_en(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
383 static int ast_say_time_de(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
384 static int ast_say_time_fr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
385 static int ast_say_time_nl(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
386 static int ast_say_time_pt(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
387 static int ast_say_time_pt_BR(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
388 static int ast_say_time_tw(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
389 static int ast_say_time_gr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
390 static int ast_say_time_ge(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
391 static int ast_say_time_he(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
393 static int ast_say_datetime_en(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
394 static int ast_say_datetime_de(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
395 static int ast_say_datetime_fr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
396 static int ast_say_datetime_nl(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
397 static int ast_say_datetime_pt(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
398 static int ast_say_datetime_pt_BR(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
399 static int ast_say_datetime_tw(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
400 static int ast_say_datetime_gr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
401 static int ast_say_datetime_ge(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
402 static int ast_say_datetime_he(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
404 static int ast_say_datetime_from_now_en(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
405 static int ast_say_datetime_from_now_fr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
406 static int ast_say_datetime_from_now_pt(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
407 static int ast_say_datetime_from_now_ge(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
408 static int ast_say_datetime_from_now_he(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
);
410 static int wait_file(struct ast_channel
*chan
, const char *ints
, const char *file
, const char *lang
)
413 if ((res
= ast_streamfile(chan
, file
, lang
)))
414 ast_log(LOG_WARNING
, "Unable to play message %s\n", file
);
416 res
= ast_waitstream(chan
, ints
);
420 /*! \brief ast_say_number_full: call language-specific functions */
421 /* Called from AGI */
422 static int say_number_full(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
424 if (!strcasecmp(language
,"en") ) { /* English syntax */
425 return(ast_say_number_full_en(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
426 } else if (!strcasecmp(language
, "cz") ) { /* Czech syntax */
427 return(ast_say_number_full_cz(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
428 } else if (!strcasecmp(language
, "da") ) { /* Danish syntax */
429 return(ast_say_number_full_da(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
430 } else if (!strcasecmp(language
, "de") ) { /* German syntax */
431 return(ast_say_number_full_de(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
432 } else if (!strcasecmp(language
, "en_GB") ) { /* British syntax */
433 return(ast_say_number_full_en_GB(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
434 } else if (!strcasecmp(language
, "no") ) { /* Norwegian syntax */
435 return(ast_say_number_full_no(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
436 } else if (!strcasecmp(language
, "es") || !strcasecmp(language
, "mx")) { /* Spanish syntax */
437 return(ast_say_number_full_es(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
438 } else if (!strcasecmp(language
, "fr") ) { /* French syntax */
439 return(ast_say_number_full_fr(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
440 } else if (!strcasecmp(language
, "he") ) { /* Hebrew syntax */
441 return(ast_say_number_full_he(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
442 } else if (!strcasecmp(language
, "it") ) { /* Italian syntax */
443 return(ast_say_number_full_it(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
444 } else if (!strcasecmp(language
, "nl") ) { /* Dutch syntax */
445 return(ast_say_number_full_nl(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
446 } else if (!strcasecmp(language
, "pl") ) { /* Polish syntax */
447 return(ast_say_number_full_pl(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
448 } else if (!strcasecmp(language
, "pt") || !strcasecmp(language
, "pt_BR")) { /* Portuguese syntax */
449 return(ast_say_number_full_pt(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
450 } else if (!strcasecmp(language
, "se") ) { /* Swedish syntax */
451 return(ast_say_number_full_se(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
452 } else if (!strcasecmp(language
, "tw") || !strcasecmp(language
, "zh") ) { /* Taiwanese / Chinese syntax */
453 return(ast_say_number_full_tw(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
454 } else if (!strcasecmp(language
, "gr") ) { /* Greek syntax */
455 return(ast_say_number_full_gr(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
456 } else if (!strcasecmp(language
, "ru") ) { /* Russian syntax */
457 return(ast_say_number_full_ru(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
458 } else if (!strcasecmp(language
, "ge") ) { /* Georgian syntax */
459 return(ast_say_number_full_ge(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
462 /* Default to english */
463 return(ast_say_number_full_en(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
466 /*! \brief ast_say_number_full_en: English syntax */
467 /* This is the default syntax, if no other syntax defined in this file is used */
468 static int ast_say_number_full_en(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
)
474 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
476 while (!res
&& (num
|| playh
)) {
478 snprintf(fn
, sizeof(fn
), "digits/minus");
479 if ( num
> INT_MIN
) {
485 snprintf(fn
, sizeof(fn
), "digits/hundred");
487 } else if (num
< 20) {
488 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
490 } else if (num
< 100) {
491 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10) * 10);
492 num
-= ((num
/ 10) * 10);
495 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/100));
497 num
-= ((num
/ 100) * 100);
499 if (num
< 1000000) { /* 1,000,000 */
500 res
= ast_say_number_full_en(chan
, num
/ 1000, ints
, language
, audiofd
, ctrlfd
);
504 snprintf(fn
, sizeof(fn
), "digits/thousand");
506 if (num
< 1000000000) { /* 1,000,000,000 */
507 res
= ast_say_number_full_en(chan
, num
/ 1000000, ints
, language
, audiofd
, ctrlfd
);
511 snprintf(fn
, sizeof(fn
), "digits/million");
513 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
520 if (!ast_streamfile(chan
, fn
, language
)) {
521 if ((audiofd
> -1) && (ctrlfd
> -1))
522 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
524 res
= ast_waitstream(chan
, ints
);
526 ast_stopstream(chan
);
532 static int exp10_int(int power
)
535 for (x
=0;x
<power
;x
++)
540 /*! \brief ast_say_number_full_cz: Czech syntax */
542 * 1m,2m - gender male
543 * 1w,2w - gender female
547 * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set
549 * for each number 10^(3n + 3) exist 3 files represented as:
550 * 1 tousand = jeden tisic = 1_E3
551 * 2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3
552 * 5,6,... tousands = pet,sest,... tisic = 5_E3
558 * tousand, milion are gender male, so 1 and 2 is 1m 2m
559 * miliard is gender female, so 1 and 2 is 1w 2w
561 static int ast_say_number_full_cz(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
571 /* options - w = woman, m = man, n = neutral. Defaultl is woman */
576 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
578 while (!res
&& (num
|| playh
)) {
580 snprintf(fn
, sizeof(fn
), "digits/minus");
581 if ( num
> INT_MIN
) {
586 } else if (num
< 3 ) {
587 snprintf(fn
, sizeof(fn
), "digits/%d%c",num
,options
[0]);
590 } else if (num
< 20) {
591 snprintf(fn
, sizeof(fn
), "digits/%d",num
);
594 } else if (num
< 100) {
595 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10) * 10);
596 num
-= ((num
/ 10) * 10);
597 } else if (num
< 1000) {
598 hundered
= num
/ 100;
599 if ( hundered
== 1 ) {
600 snprintf(fn
, sizeof(fn
), "digits/1sto");
601 } else if ( hundered
== 2 ) {
602 snprintf(fn
, sizeof(fn
), "digits/2ste");
604 res
= ast_say_number_full_cz(chan
,hundered
,ints
,language
,options
,audiofd
,ctrlfd
);
607 if (hundered
== 3 || hundered
== 4) {
608 snprintf(fn
, sizeof(fn
), "digits/sta");
609 } else if ( hundered
> 4 ) {
610 snprintf(fn
, sizeof(fn
), "digits/set");
613 num
-= (hundered
* 100);
614 } else { /* num > 1000 */
615 length
= (int)log10(num
)+1;
616 while ( (length
% 3 ) != 1 ) {
619 left
= num
/ (exp10_int(length
-1));
622 case 9: options
= "w"; /* 1,000,000,000 gender female */
624 default : options
= "m"; /* others are male */
627 if ( left
> 1 ) { /* we dont say "one thousand" but only thousand */
628 res
= ast_say_number_full_cz(chan
,left
,ints
,language
,options
,audiofd
,ctrlfd
);
632 if ( left
>= 5 ) { /* >= 5 have the same declesion */
633 snprintf(fn
, sizeof(fn
), "digits/5_E%d",length
-1);
634 } else if ( left
>= 2 && left
<= 4 ) {
635 snprintf(fn
, sizeof(fn
), "digits/2-4_E%d",length
-1);
636 } else { /* left == 1 */
637 snprintf(fn
, sizeof(fn
), "digits/1_E%d",length
-1);
639 num
-= left
* (exp10_int(length
-1));
642 if (!ast_streamfile(chan
, fn
, language
)) {
643 if ((audiofd
> -1) && (ctrlfd
> -1)) {
644 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
646 res
= ast_waitstream(chan
, ints
);
649 ast_stopstream(chan
);
655 /*! \brief ast_say_number_full_da: Danish syntax */
657 In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and"
659 static int ast_say_number_full_da(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
664 int cn
= 1; /* +1 = commune; -1 = neuter */
667 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
669 if (options
&& !strncasecmp(options
, "n",1)) cn
= -1;
671 while (!res
&& (num
|| playh
|| playa
)) {
672 /* The grammar for Danish numbers is the same as for English except
674 * - 1 exists in both commune ("en", file "1N") and neuter ("et", file "1")
675 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
676 * "one-and twenty" and 68 is "eight-and sixty".
677 * - "million" is different in singular and plural form
678 * - numbers > 1000 with zero as the third digit from last have an
679 * "and" before the last two digits, i.e. 2034 is "two thousand and
680 * four-and thirty" and 1000012 is "one million and twelve".
683 snprintf(fn
, sizeof(fn
), "digits/minus");
684 if ( num
> INT_MIN
) {
690 snprintf(fn
, sizeof(fn
), "digits/hundred");
693 snprintf(fn
, sizeof(fn
), "digits/and");
695 } else if (num
== 1 && cn
== -1) {
696 snprintf(fn
, sizeof(fn
), "digits/1N");
698 } else if (num
< 20) {
699 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
701 } else if (num
< 100) {
704 snprintf(fn
, sizeof(fn
), "digits/%d-and", ones
);
707 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
712 int hundreds
= num
/ 100;
714 snprintf(fn
, sizeof(fn
), "digits/1N");
716 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 100));
719 num
-= 100 * hundreds
;
725 res
= ast_say_number_full_da(chan
, num
/ 1000, ints
, language
, "n", audiofd
, ctrlfd
);
729 snprintf(fn
, sizeof(fn
), "digits/thousand");
731 if (num
< 1000000000) {
732 int millions
= num
/ 1000000;
733 res
= ast_say_number_full_da(chan
, millions
, ints
, language
, "c", audiofd
, ctrlfd
);
737 snprintf(fn
, sizeof(fn
), "digits/million");
739 snprintf(fn
, sizeof(fn
), "digits/millions");
742 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
746 if (num
&& num
< 100)
751 if (!ast_streamfile(chan
, fn
, language
)) {
752 if ((audiofd
> -1) && (ctrlfd
> -1))
753 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
755 res
= ast_waitstream(chan
, ints
);
757 ast_stopstream(chan
);
763 /*! \brief ast_say_number_full_de: German syntax */
765 In addition to English, the following sounds are required:
767 "1-and" through "9-and"
770 NB "1" is recorded as 'eins'
772 static int ast_say_number_full_de(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
775 int mf
= 1; /* +1 = male and neuter; -1 = female */
779 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
781 if (options
&& (!strncasecmp(options
, "f",1)))
784 while (!res
&& num
) {
785 /* The grammar for German numbers is the same as for English except
787 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
788 * "one-and twenty" and 68 is "eight-and sixty".
789 * - "one" varies according to gender
790 * - 100 is 'hundert', however all other instances are 'ein hundert'
791 * - 1000 is 'tausend', however all other instances are 'ein tausend'
792 * - 1000000 is always 'eine million'
793 * - "million" is different in singular and plural form
796 snprintf(fn
, sizeof(fn
), "digits/minus");
797 if ( num
> INT_MIN
) {
802 } else if (num
< 100 && t
) {
803 snprintf(fn
, sizeof(fn
), "digits/and");
805 } else if (num
== 1 && mf
== -1) {
806 snprintf(fn
, sizeof(fn
), "digits/%dF", num
);
808 } else if (num
< 20) {
809 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
811 } else if (num
< 100) {
814 snprintf(fn
, sizeof(fn
), "digits/%d-and", ones
);
817 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
820 } else if (num
== 100 && t
== 0) {
821 snprintf(fn
, sizeof(fn
), "digits/hundred");
823 } else if (num
< 1000) {
824 int hundreds
= num
/ 100;
827 snprintf(fn
, sizeof(fn
), "digits/1N");
829 snprintf(fn
, sizeof(fn
), "digits/%d", hundreds
);
831 snprintf(fna
, sizeof(fna
), "digits/hundred");
833 } else if (num
== 1000 && t
== 0) {
834 snprintf(fn
, sizeof(fn
), "digits/thousand");
836 } else if (num
< 1000000) {
837 int thousands
= num
/ 1000;
840 if (thousands
== 1) {
841 snprintf(fn
, sizeof(fn
), "digits/1N");
842 snprintf(fna
, sizeof(fna
), "digits/thousand");
844 res
= ast_say_number_full_de(chan
, thousands
, ints
, language
, options
, audiofd
, ctrlfd
);
847 snprintf(fn
, sizeof(fn
), "digits/thousand");
849 } else if (num
< 1000000000) {
850 int millions
= num
/ 1000000;
854 snprintf(fn
, sizeof(fn
), "digits/1F");
855 snprintf(fna
, sizeof(fna
), "digits/million");
857 res
= ast_say_number_full_de(chan
, millions
, ints
, language
, options
, audiofd
, ctrlfd
);
860 snprintf(fn
, sizeof(fn
), "digits/millions");
862 } else if (num
<= INT_MAX
) {
863 int billions
= num
/ 1000000000;
864 num
= num
% 1000000000;
867 snprintf(fn
, sizeof(fn
), "digits/1F");
868 snprintf(fna
, sizeof(fna
), "digits/milliard");
870 res
= ast_say_number_full_de(chan
, billions
, ints
, language
, options
, audiofd
, ctrlfd
);
874 snprintf(fn
, sizeof(fn
), "digits/milliards");
877 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
881 if (!ast_streamfile(chan
, fn
, language
)) {
882 if ((audiofd
> -1) && (ctrlfd
> -1))
883 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
885 res
= ast_waitstream(chan
, ints
);
887 ast_stopstream(chan
);
889 if (strlen(fna
) != 0 && !ast_streamfile(chan
, fna
, language
)) {
890 if ((audiofd
> -1) && (ctrlfd
> -1))
891 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
893 res
= ast_waitstream(chan
, ints
);
895 ast_stopstream(chan
);
903 /*! \brief ast_say_number_full_en_GB: British and Norwegian syntax */
905 In addition to American English, the following sounds are required: "and"
907 static int ast_say_number_full_en_GB(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
)
914 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
916 while (!res
&& (num
|| playh
|| playa
)) {
918 snprintf(fn
, sizeof(fn
), "digits/minus");
919 if ( num
> INT_MIN
) {
925 snprintf(fn
, sizeof(fn
), "digits/hundred");
928 snprintf(fn
, sizeof(fn
), "digits/and");
930 } else if (num
< 20) {
931 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
933 } else if (num
< 100) {
934 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10) * 10);
935 num
-= ((num
/ 10) * 10);
936 } else if (num
< 1000) {
937 int hundreds
= num
/ 100;
938 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 100));
941 num
-= 100 * hundreds
;
944 } else if (num
< 1000000) {
945 res
= ast_say_number_full_en_GB(chan
, num
/ 1000, ints
, language
, audiofd
, ctrlfd
);
948 snprintf(fn
, sizeof(fn
), "digits/thousand");
950 if (num
&& num
< 100)
952 } else if (num
< 1000000000) {
953 int millions
= num
/ 1000000;
954 res
= ast_say_number_full_en_GB(chan
, millions
, ints
, language
, audiofd
, ctrlfd
);
957 snprintf(fn
, sizeof(fn
), "digits/million");
959 if (num
&& num
< 100)
962 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
967 if (!ast_streamfile(chan
, fn
, language
)) {
968 if ((audiofd
> -1) && (ctrlfd
> -1))
969 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
971 res
= ast_waitstream(chan
, ints
);
973 ast_stopstream(chan
);
979 /*! \brief ast_say_number_full_es: Spanish syntax */
981 Requires a few new audios:
982 1F.gsm: feminine 'una'
983 21.gsm thru 29.gsm, cien.gsm, mil.gsm, millon.gsm, millones.gsm, 100.gsm, 200.gsm, 300.gsm, 400.gsm, 500.gsm, 600.gsm, 700.gsm, 800.gsm, 900.gsm, y.gsm
985 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
)
989 int mf
= 0; /* +1 = male; -1 = female */
992 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
995 if (!strncasecmp(options
, "f",1))
997 else if (!strncasecmp(options
, "m", 1))
1001 while (!res
&& num
) {
1003 snprintf(fn
, sizeof(fn
), "digits/minus");
1004 if ( num
> INT_MIN
) {
1010 snprintf(fn
, sizeof(fn
), "digits/and");
1012 } else if (num
== 1) {
1014 snprintf(fn
, sizeof(fn
), "digits/%dF", num
);
1016 snprintf(fn
, sizeof(fn
), "digits/%dM", num
);
1018 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1020 } else if (num
< 31) {
1021 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1023 } else if (num
< 100) {
1024 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10)*10);
1025 num
-= ((num
/10)*10);
1028 } else if (num
== 100) {
1029 snprintf(fn
, sizeof(fn
), "digits/100");
1031 } else if (num
< 200) {
1032 snprintf(fn
, sizeof(fn
), "digits/100-and");
1036 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/100)*100);
1037 num
-= ((num
/100)*100);
1038 } else if (num
< 2000) {
1040 snprintf(fn
, sizeof(fn
), "digits/thousand");
1042 if (num
< 1000000) {
1043 res
= ast_say_number_full_es(chan
, num
/ 1000, ints
, language
, options
, audiofd
, ctrlfd
);
1047 snprintf(fn
, sizeof(fn
), "digits/thousand");
1049 if (num
< 2147483640) {
1050 if ((num
/1000000) == 1) {
1051 res
= ast_say_number_full_es(chan
, num
/ 1000000, ints
, language
, "M", audiofd
, ctrlfd
);
1054 snprintf(fn
, sizeof(fn
), "digits/million");
1056 res
= ast_say_number_full_es(chan
, num
/ 1000000, ints
, language
, options
, audiofd
, ctrlfd
);
1059 snprintf(fn
, sizeof(fn
), "digits/millions");
1061 num
= num
% 1000000;
1063 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
1071 if (!ast_streamfile(chan
, fn
, language
)) {
1072 if ((audiofd
> -1) && (ctrlfd
> -1))
1073 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
1075 res
= ast_waitstream(chan
, ints
);
1077 ast_stopstream(chan
);
1085 /*! \brief ast_say_number_full_fr: French syntax */
1086 /* Extra sounds needed:
1089 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
)
1094 int mf
= 1; /* +1 = male; -1 = female */
1097 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
1099 if (options
&& !strncasecmp(options
, "f",1))
1102 while (!res
&& (num
|| playh
|| playa
)) {
1104 snprintf(fn
, sizeof(fn
), "digits/minus");
1105 if ( num
> INT_MIN
) {
1111 snprintf(fn
, sizeof(fn
), "digits/hundred");
1114 snprintf(fn
, sizeof(fn
), "digits/et");
1116 } else if (num
== 1) {
1118 snprintf(fn
, sizeof(fn
), "digits/%dF", num
);
1120 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1122 } else if (num
< 21) {
1123 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1125 } else if (num
< 70) {
1126 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10)*10);
1127 if ((num
% 10) == 1) playa
++;
1129 } else if (num
< 80) {
1130 snprintf(fn
, sizeof(fn
), "digits/60");
1131 if ((num
% 10) == 1) playa
++;
1133 } else if (num
< 100) {
1134 snprintf(fn
, sizeof(fn
), "digits/80");
1136 } else if (num
< 200) {
1137 snprintf(fn
, sizeof(fn
), "digits/hundred");
1139 } else if (num
< 1000) {
1140 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/100));
1143 } else if (num
< 2000) {
1144 snprintf(fn
, sizeof(fn
), "digits/thousand");
1146 } else if (num
< 1000000) {
1147 res
= ast_say_number_full_fr(chan
, num
/ 1000, ints
, language
, options
, audiofd
, ctrlfd
);
1150 snprintf(fn
, sizeof(fn
), "digits/thousand");
1152 } else if (num
< 1000000000) {
1153 res
= ast_say_number_full_fr(chan
, num
/ 1000000, ints
, language
, options
, audiofd
, ctrlfd
);
1156 snprintf(fn
, sizeof(fn
), "digits/million");
1157 num
= num
% 1000000;
1159 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
1163 if (!ast_streamfile(chan
, fn
, language
)) {
1164 if ((audiofd
> -1) && (ctrlfd
> -1))
1165 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
1167 res
= ast_waitstream(chan
, ints
);
1169 ast_stopstream(chan
);
1178 /* Check doc/lang/hebrew-digits.txt for information about the various
1179 * recordings required to make this translation work properly */
1180 #define SAY_NUM_BUF_SIZE 256
1181 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
)
1184 int state
= 0; /* no need to save anything */
1185 int mf
= -1; /* +1 = Masculin; -1 = Feminin */
1188 char fn
[SAY_NUM_BUF_SIZE
] = "";
1190 ast_verbose(VERBOSE_PREFIX_3
"ast_say_digits_full: started. num: %d, options=\"%s\"\n", num
, options
);
1193 return ast_say_digits_full(chan
, 0, ints
, language
, audiofd
, ctrlfd
);
1195 if (options
&& !strncasecmp(options
, "m", 1)) {
1198 ast_verbose(VERBOSE_PREFIX_3
"ast_say_digits_full: num: %d, state=%d, options=\"%s\", mf=%d\n", num
, state
, options
, mf
);
1200 /* Do we have work to do? */
1201 while (!res
&& (num
|| (state
> 0))) {
1202 /* first type of work: play a second sound. In this loop
1203 * we can only play one sound file at a time. Thus playing
1204 * a second one requires repeating the loop just for the
1205 * second file. The variable 'state' remembers where we were.
1206 * state==0 is the normal mode and it means that we continue
1207 * to check if the number num has yet anything left.
1209 ast_verbose(VERBOSE_PREFIX_3
"ast_say_digits_full: num: %d, state=%d, options=\"%s\", mf=%d, tmpnum=%d\n", num
, state
, options
, mf
, tmpnum
);
1213 } else if (state
== 2) {
1214 if ((num
>= 11) && (num
< 21)) {
1216 snprintf(fn
, sizeof(fn
), "digits/ve");
1218 snprintf(fn
, sizeof(fn
), "digits/uu");
1223 snprintf(fn
, sizeof(fn
), "digits/ve");
1226 snprintf(fn
, sizeof(fn
), "digits/uu");
1230 snprintf(fn
, sizeof(fn
), "digits/ve");
1232 snprintf(fn
, sizeof(fn
), "digits/uu");
1236 snprintf(fn
, sizeof(fn
), "digits/ve");
1239 snprintf(fn
, sizeof(fn
), "digits/ve");
1242 snprintf(fn
, sizeof(fn
), "digits/ve");
1245 snprintf(fn
, sizeof(fn
), "digits/ve");
1248 snprintf(fn
, sizeof(fn
), "digits/uu");
1251 snprintf(fn
, sizeof(fn
), "digits/ve");
1254 snprintf(fn
, sizeof(fn
), "digits/ve");
1259 } else if (state
== 3) {
1260 snprintf(fn
, sizeof(fn
), "digits/1k");
1262 } else if (num
< 0) {
1263 snprintf(fn
, sizeof(fn
), "digits/minus");
1265 } else if (num
< 20) {
1267 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1269 snprintf(fn
, sizeof(fn
), "digits/%dm", num
);
1272 } else if ((num
< 100) && (num
>= 20)) {
1273 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 10) * 10);
1278 } else if ((num
>= 100) && (num
< 1000)) {
1280 snprintf(fn
, sizeof(fn
), "digits/%d00", tmpnum
);
1281 num
= num
- (tmpnum
* 100);
1282 if ((num
> 0) && (num
< 11)) {
1285 } else if ((num
>= 1000) && (num
< 10000)) {
1286 tmpnum
= num
/ 1000;
1287 snprintf(fn
, sizeof(fn
), "digits/%dk", tmpnum
);
1288 num
= num
- (tmpnum
* 1000);
1289 if ((num
> 0) && (num
< 11)) {
1292 } else if (num
< 20000) {
1293 snprintf(fn
, sizeof(fn
), "digits/%dm", (num
/ 1000));
1296 } else if (num
< 1000000) {
1297 res
= ast_say_number_full_he(chan
, num
/ 1000, ints
, language
, "m", audiofd
, ctrlfd
);
1301 snprintf(fn
, sizeof(fn
), "digits/1k");
1303 if ((num
> 0) && (num
< 11)) {
1306 } else if (num
< 2000000) {
1307 snprintf(fn
, sizeof(fn
), "digits/million");
1308 num
= num
% 1000000;
1309 if ((num
> 0) && (num
< 11)) {
1312 } else if (num
< 3000000) {
1313 snprintf(fn
, sizeof(fn
), "digits/twomillion");
1314 num
= num
- 2000000;
1315 if ((num
> 0) && (num
< 11)) {
1318 } else if (num
< 1000000000) {
1319 res
= ast_say_number_full_he(chan
, num
/ 1000000, ints
, language
, "m", audiofd
, ctrlfd
);
1323 snprintf(fn
, sizeof(fn
), "digits/million");
1324 num
= num
% 1000000;
1325 if ((num
> 0) && (num
< 11)) {
1329 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
1334 if (!ast_streamfile(chan
, fn
, language
)) {
1335 if ((audiofd
> -1) && (ctrlfd
> -1)) {
1336 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
1338 res
= ast_waitstream(chan
, ints
);
1341 ast_stopstream(chan
);
1347 /*! \brief ast_say_number_full_it: Italian */
1348 static int ast_say_number_full_it(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
)
1356 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
1361 Like english, numbers up to 20 are a single 'word', and others
1362 compound, but with exceptions.
1363 For example 21 is not twenty-one, but there is a single word in 'it'.
1364 Idem for 28 (ie when a the 2nd part of a compund number
1365 starts with a vowel)
1367 There are exceptions also for hundred, thousand and million.
1368 In english 100 = one hundred, 200 is two hundred.
1369 In italian 100 = cento , like to say hundred (without one),
1370 200 and more are like english.
1372 Same applies for thousand:
1373 1000 is one thousand in en, 2000 is two thousand.
1374 In it we have 1000 = mille , 2000 = 2 mila
1376 For million(s) we use the plural, if more than one
1377 Also, one million is abbreviated in it, like on-million,
1378 or 'un milione', not 'uno milione'.
1379 So the right file is provided.
1382 while (!res
&& (num
|| playh
)) {
1384 snprintf(fn
, sizeof(fn
), "digits/minus");
1385 if ( num
> INT_MIN
) {
1391 snprintf(fn
, sizeof(fn
), "digits/hundred");
1393 } else if (num
< 20) {
1394 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1396 } else if (num
== 21) {
1397 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1399 } else if (num
== 28) {
1400 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1402 } else if (num
== 31) {
1403 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1405 } else if (num
== 38) {
1406 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1408 } else if (num
== 41) {
1409 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1411 } else if (num
== 48) {
1412 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1414 } else if (num
== 51) {
1415 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1417 } else if (num
== 58) {
1418 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1420 } else if (num
== 61) {
1421 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1423 } else if (num
== 68) {
1424 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1426 } else if (num
== 71) {
1427 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1429 } else if (num
== 78) {
1430 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1432 } else if (num
== 81) {
1433 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1435 } else if (num
== 88) {
1436 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1438 } else if (num
== 91) {
1439 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1441 } else if (num
== 98) {
1442 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1444 } else if (num
< 100) {
1445 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10) * 10);
1446 num
-= ((num
/ 10) * 10);
1449 if ((num
/ 100) > 1) {
1450 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/100));
1453 snprintf(fn
, sizeof(fn
), "digits/hundred");
1455 num
-= ((num
/ 100) * 100);
1457 if (num
< 1000000) { /* 1,000,000 */
1459 res
= ast_say_number_full_it(chan
, num
/ 1000, ints
, language
, audiofd
, ctrlfd
);
1464 if ((tempnum
/ 1000) < 2)
1465 snprintf(fn
, sizeof(fn
), "digits/thousand");
1466 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1467 snprintf(fn
, sizeof(fn
), "digits/thousands");
1469 if (num
< 1000000000) { /* 1,000,000,000 */
1470 if ((num
/ 1000000) > 1)
1471 res
= ast_say_number_full_it(chan
, num
/ 1000000, ints
, language
, audiofd
, ctrlfd
);
1475 num
= num
% 1000000;
1476 if ((tempnum
/ 1000000) < 2)
1477 snprintf(fn
, sizeof(fn
), "digits/million");
1479 snprintf(fn
, sizeof(fn
), "digits/millions");
1481 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
1488 if (!ast_streamfile(chan
, fn
, language
)) {
1489 if ((audiofd
> -1) && (ctrlfd
> -1))
1490 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
1492 res
= ast_waitstream(chan
, ints
);
1494 ast_stopstream(chan
);
1500 /*! \brief ast_say_number_full_nl: dutch syntax */
1501 /* New files: digits/nl-en
1503 static int ast_say_number_full_nl(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
)
1510 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
1511 while (!res
&& (num
|| playh
)) {
1513 snprintf(fn
, sizeof(fn
), "digits/minus");
1514 if ( num
> INT_MIN
) {
1520 snprintf(fn
, sizeof(fn
), "digits/hundred");
1522 } else if (num
< 20) {
1523 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1525 } else if (num
< 100) {
1528 res
= ast_say_number_full_nl(chan
, units
, ints
, language
, audiofd
, ctrlfd
);
1532 snprintf(fn
, sizeof(fn
), "digits/nl-en");
1534 snprintf(fn
, sizeof(fn
), "digits/%d", num
- units
);
1537 } else if (num
< 200) {
1538 /* hundred, not one-hundred */
1539 ast_copy_string(fn
, "digits/hundred", sizeof(fn
));
1540 num
-= ((num
/ 100) * 100);
1541 } else if (num
< 1000) {
1542 snprintf(fn
, sizeof(fn
), "digits/%d", num
/ 100);
1544 num
-= ((num
/ 100) * 100);
1547 /* thousand, not one-thousand */
1549 ast_copy_string(fn
, "digits/thousand", sizeof(fn
));
1550 } else if (num
< 10000) { /* 1,100 to 9,9999 */
1551 res
= ast_say_number_full_nl(chan
, num
/ 100, ints
, language
, audiofd
, ctrlfd
);
1555 ast_copy_string(fn
, "digits/hundred", sizeof(fn
));
1557 if (num
< 1000000) { /* 1,000,000 */
1558 res
= ast_say_number_full_nl(chan
, num
/ 1000, ints
, language
, audiofd
, ctrlfd
);
1562 snprintf(fn
, sizeof(fn
), "digits/thousand");
1564 if (num
< 1000000000) { /* 1,000,000,000 */
1565 res
= ast_say_number_full_nl(chan
, num
/ 1000000, ints
, language
, audiofd
, ctrlfd
);
1568 num
= num
% 1000000;
1569 snprintf(fn
, sizeof(fn
), "digits/million");
1571 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
1579 if (!ast_streamfile(chan
, fn
, language
)) {
1580 if ((audiofd
> -1) && (ctrlfd
> -1))
1581 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
1583 res
= ast_waitstream(chan
, ints
);
1585 ast_stopstream(chan
);
1591 /*! \brief ast_say_number_full_no: Norwegian syntax */
1593 In addition to American English, the following sounds are required: "and", "1N"
1595 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
)
1600 int cn
= 1; /* +1 = commune; -1 = neuter */
1604 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
1606 if (options
&& !strncasecmp(options
, "n",1)) cn
= -1;
1608 while (!res
&& (num
|| playh
|| playa
)) {
1609 /* The grammar for Norwegian numbers is the same as for English except
1610 * for the following:
1611 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1612 * "and" before the last two digits, i.e. 2034 is "two thousand and
1613 * thirty-four" and 1000012 is "one million and twelve".
1616 snprintf(fn
, sizeof(fn
), "digits/minus");
1617 if ( num
> INT_MIN
) {
1623 snprintf(fn
, sizeof(fn
), "digits/hundred");
1626 snprintf(fn
, sizeof(fn
), "digits/and");
1628 } else if (num
== 1 && cn
== -1) {
1629 snprintf(fn
, sizeof(fn
), "digits/1N");
1631 } else if (num
< 20) {
1632 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
1634 } else if (num
< 100) {
1635 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10) * 10);
1636 num
-= ((num
/ 10) * 10);
1637 } else if (num
< 1000) {
1638 int hundreds
= num
/ 100;
1640 snprintf(fn
, sizeof(fn
), "digits/1N");
1642 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 100));
1645 num
-= 100 * hundreds
;
1648 } else if (num
< 1000000) {
1649 res
= ast_say_number_full_no(chan
, num
/ 1000, ints
, language
, "n", audiofd
, ctrlfd
);
1652 snprintf(fn
, sizeof(fn
), "digits/thousand");
1654 if (num
&& num
< 100)
1656 } else if (num
< 1000000000) {
1657 int millions
= num
/ 1000000;
1658 res
= ast_say_number_full_no(chan
, millions
, ints
, language
, "c", audiofd
, ctrlfd
);
1661 snprintf(fn
, sizeof(fn
), "digits/million");
1662 num
= num
% 1000000;
1663 if (num
&& num
< 100)
1666 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
1671 if (!ast_streamfile(chan
, fn
, language
)) {
1672 if ((audiofd
> -1) && (ctrlfd
> -1))
1673 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
1675 res
= ast_waitstream(chan
, ints
);
1677 ast_stopstream(chan
);
1684 char *separator_dziesiatek
;
1688 char *dziesiatki
[10];
1693 static char *pl_rzad_na_tekst(odmiana
*odm
, int i
, int rzad
)
1699 return odm
->rzedy
[rzad
- 1][0];
1700 if ((i
> 21 || i
< 11) && i
%10 > 1 && i
%10 < 5)
1701 return odm
->rzedy
[rzad
- 1][1];
1703 return odm
->rzedy
[rzad
- 1][2];
1706 static char* pl_append(char* buffer
, char* str
)
1708 strcpy(buffer
, str
);
1709 buffer
+= strlen(str
);
1713 static void pl_odtworz_plik(struct ast_channel
*chan
, const char *language
, int audiofd
, int ctrlfd
, const char *ints
, char *fn
)
1715 char file_name
[255] = "digits/";
1716 strcat(file_name
, fn
);
1717 ast_log(LOG_DEBUG
, "Trying to play: %s\n", file_name
);
1718 if (!ast_streamfile(chan
, file_name
, language
)) {
1719 if ((audiofd
> -1) && (ctrlfd
> -1))
1720 ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
1722 ast_waitstream(chan
, ints
);
1724 ast_stopstream(chan
);
1727 static void powiedz(struct ast_channel
*chan
, const char *language
, int audiofd
, int ctrlfd
, const char *ints
, odmiana
*odm
, int rzad
, int i
)
1729 /* Initialise variables to allow compilation on Debian-stable, etc */
1739 if (i
== 0 && rzad
> 0) {
1743 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, odm
->cyfry
[0]);
1747 m1000E6
= i
% 1000000000;
1748 i1000E6
= i
/ 1000000000;
1750 powiedz(chan
, language
, audiofd
, ctrlfd
, ints
, odm
, rzad
+3, i1000E6
);
1752 m1000E3
= m1000E6
% 1000000;
1753 i1000E3
= m1000E6
/ 1000000;
1755 powiedz(chan
, language
, audiofd
, ctrlfd
, ints
, odm
, rzad
+2, i1000E3
);
1757 m1000
= m1000E3
% 1000;
1758 i1000
= m1000E3
/ 1000;
1760 powiedz(chan
, language
, audiofd
, ctrlfd
, ints
, odm
, rzad
+1, i1000
);
1766 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, odm
->setki
[i100
]);
1768 if ( m100
> 0 && m100
<=9 ) {
1770 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, odm
->cyfry2
[m100
]);
1772 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, odm
->cyfry
[m100
]);
1773 } else if (m100
% 10 == 0) {
1774 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, odm
->dziesiatki
[m100
/ 10]);
1775 } else if (m100
<= 19 ) {
1776 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, odm
->nastki
[m100
% 10]);
1777 } else if (m100
!= 0) {
1778 if (odm
->separator_dziesiatek
[0]==' ') {
1779 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, odm
->dziesiatki
[m100
/ 10]);
1780 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, odm
->cyfry2
[m100
% 10]);
1784 b
= pl_append(b
, odm
->dziesiatki
[m100
/ 10]);
1785 b
= pl_append(b
, odm
->separator_dziesiatek
);
1786 b
= pl_append(b
, odm
->cyfry2
[m100
% 10]);
1787 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, buf
);
1792 pl_odtworz_plik(chan
, language
, audiofd
, ctrlfd
, ints
, pl_rzad_na_tekst(odm
, i
, rzad
));
1796 /* ast_say_number_full_pl: Polish syntax */
1797 static int ast_say_number_full_pl(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
1807 1000000000.2 miliardy
1808 1000000000.5 miliardow
1872 70m siedemdziesieciu
1884 90m dziewiedziesieciu
1886 and combinations of eg.: 20_1, 30m_3m, etc...
1890 char *zenski_cyfry
[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1892 char *zenski_cyfry2
[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1894 char *meski_cyfry
[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m", /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1896 char *meski_cyfry2
[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1898 char *meski_setki
[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1900 char *meski_dziesiatki
[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1902 char *meski_nastki
[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1904 char *nijaki_cyfry
[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1906 char *nijaki_cyfry2
[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1908 char *nijaki_setki
[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1910 char *nijaki_dziesiatki
[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1912 char *nijaki_nastki
[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1914 char *rzedy
[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}};
1916 /* Initialise variables to allow compilation on Debian-stable, etc */
1919 static odmiana
*odmiana_nieosobowa
= NULL
;
1920 static odmiana
*odmiana_meska
= NULL
;
1921 static odmiana
*odmiana_zenska
= NULL
;
1923 if (odmiana_nieosobowa
== NULL
) {
1924 odmiana_nieosobowa
= (odmiana
*) malloc(sizeof(odmiana
));
1926 odmiana_nieosobowa
->separator_dziesiatek
= " ";
1928 memcpy(odmiana_nieosobowa
->cyfry
, nijaki_cyfry
, sizeof(odmiana_nieosobowa
->cyfry
));
1929 memcpy(odmiana_nieosobowa
->cyfry2
, nijaki_cyfry2
, sizeof(odmiana_nieosobowa
->cyfry
));
1930 memcpy(odmiana_nieosobowa
->setki
, nijaki_setki
, sizeof(odmiana_nieosobowa
->setki
));
1931 memcpy(odmiana_nieosobowa
->dziesiatki
, nijaki_dziesiatki
, sizeof(odmiana_nieosobowa
->dziesiatki
));
1932 memcpy(odmiana_nieosobowa
->nastki
, nijaki_nastki
, sizeof(odmiana_nieosobowa
->nastki
));
1933 memcpy(odmiana_nieosobowa
->rzedy
, rzedy
, sizeof(odmiana_nieosobowa
->rzedy
));
1936 if (odmiana_zenska
== NULL
) {
1937 odmiana_zenska
= (odmiana
*) malloc(sizeof(odmiana
));
1939 odmiana_zenska
->separator_dziesiatek
= " ";
1941 memcpy(odmiana_zenska
->cyfry
, zenski_cyfry
, sizeof(odmiana_zenska
->cyfry
));
1942 memcpy(odmiana_zenska
->cyfry2
, zenski_cyfry2
, sizeof(odmiana_zenska
->cyfry
));
1943 memcpy(odmiana_zenska
->setki
, nijaki_setki
, sizeof(odmiana_zenska
->setki
));
1944 memcpy(odmiana_zenska
->dziesiatki
, nijaki_dziesiatki
, sizeof(odmiana_zenska
->dziesiatki
));
1945 memcpy(odmiana_zenska
->nastki
, nijaki_nastki
, sizeof(odmiana_zenska
->nastki
));
1946 memcpy(odmiana_zenska
->rzedy
, rzedy
, sizeof(odmiana_zenska
->rzedy
));
1949 if (odmiana_meska
== NULL
) {
1950 odmiana_meska
= (odmiana
*) malloc(sizeof(odmiana
));
1952 odmiana_meska
->separator_dziesiatek
= " ";
1954 memcpy(odmiana_meska
->cyfry
, meski_cyfry
, sizeof(odmiana_meska
->cyfry
));
1955 memcpy(odmiana_meska
->cyfry2
, meski_cyfry2
, sizeof(odmiana_meska
->cyfry
));
1956 memcpy(odmiana_meska
->setki
, meski_setki
, sizeof(odmiana_meska
->setki
));
1957 memcpy(odmiana_meska
->dziesiatki
, meski_dziesiatki
, sizeof(odmiana_meska
->dziesiatki
));
1958 memcpy(odmiana_meska
->nastki
, meski_nastki
, sizeof(odmiana_meska
->nastki
));
1959 memcpy(odmiana_meska
->rzedy
, rzedy
, sizeof(odmiana_meska
->rzedy
));
1963 if (strncasecmp(options
, "f", 1) == 0)
1965 else if (strncasecmp(options
, "m", 1) == 0)
1968 o
= odmiana_nieosobowa
;
1970 o
= odmiana_nieosobowa
;
1972 powiedz(chan
, language
, audiofd
, ctrlfd
, ints
, o
, 0, num
);
1976 /* ast_say_number_full_pt: Portuguese syntax */
1977 /* Extra sounds needed: */
1978 /* For feminin all sound files end with F */
1979 /* 100E for 100+ something */
1980 /* 1000000S for plural */
1981 /* pt-e for 'and' */
1982 static int ast_say_number_full_pt(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
1986 int mf
= 1; /* +1 = male; -1 = female */
1990 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
1992 if (options
&& !strncasecmp(options
, "f",1))
1995 while (!res
&& num
) {
1997 snprintf(fn
, sizeof(fn
), "digits/minus");
1998 if ( num
> INT_MIN
) {
2003 } else if (num
< 20) {
2004 if ((num
== 1 || num
== 2) && (mf
< 0))
2005 snprintf(fn
, sizeof(fn
), "digits/%dF", num
);
2007 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
2009 } else if (num
< 100) {
2010 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 10) * 10);
2014 } else if (num
< 1000) {
2016 snprintf(fn
, sizeof(fn
), "digits/100");
2018 snprintf(fn
, sizeof(fn
), "digits/100E");
2020 if (mf
< 0 && num
> 199)
2021 snprintf(fn
, sizeof(fn
), "digits/%dF", (num
/ 100) * 100);
2023 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 100) * 100);
2028 } else if (num
< 1000000) {
2030 res
= ast_say_number_full_pt(chan
, (num
/ 1000) * mf
, ints
, language
, options
, audiofd
, ctrlfd
);
2034 snprintf(fn
, sizeof(fn
), "digits/1000");
2035 if ((num
% 1000) && ((num
% 1000) < 100 || !(num
% 100)))
2038 } else if (num
< 1000000000) {
2039 res
= ast_say_number_full_pt(chan
, (num
/ 1000000), ints
, language
, options
, audiofd
, ctrlfd
);
2043 snprintf(fn
, sizeof(fn
), "digits/1000000");
2045 snprintf(fn
, sizeof(fn
), "digits/1000000S");
2047 if ((num
% 1000000) &&
2049 ((!((num
/ 1000) % 1000) && ((num
% 1000) < 100 || !(num
% 100))) ||
2050 /* no hundreds and below */
2051 (!(num
% 1000) && (((num
/ 1000) % 1000) < 100 || !((num
/ 1000) % 100))) ) )
2053 num
= num
% 1000000;
2055 /* number is too big */
2056 ast_log(LOG_WARNING
, "Number '%d' is too big to say.", num
);
2060 if (!ast_streamfile(chan
, fn
, language
)) {
2061 if ((audiofd
> -1) && (ctrlfd
> -1))
2062 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2064 res
= ast_waitstream(chan
, ints
);
2066 ast_stopstream(chan
);
2068 if (!res
&& playh
) {
2069 res
= wait_file(chan
, ints
, "digits/pt-e", language
);
2070 ast_stopstream(chan
);
2077 /*! \brief ast_say_number_full_se: Swedish syntax */
2078 static int ast_say_number_full_se(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
2083 int cn
= 1; /* +1 = commune; -1 = neuter */
2085 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
2086 if (options
&& !strncasecmp(options
, "n",1)) cn
= -1;
2088 while (!res
&& (num
|| playh
)) {
2090 snprintf(fn
, sizeof(fn
), "digits/minus");
2091 if ( num
> INT_MIN
) {
2097 snprintf(fn
, sizeof(fn
), "digits/hundred");
2099 } else if (num
< 20) {
2100 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
2102 } else if (num
< 100) {
2103 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10) * 10);
2104 num
-= ((num
/ 10) * 10);
2105 } else if (num
== 1 && cn
== -1) { /* En eller ett? */
2106 snprintf(fn
, sizeof(fn
), "digits/1N");
2110 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/100));
2112 num
-= ((num
/ 100) * 100);
2114 if (num
< 1000000) { /* 1,000,000 */
2115 res
= ast_say_number_full_se(chan
, num
/ 1000, ints
, language
, options
, audiofd
, ctrlfd
);
2120 snprintf(fn
, sizeof(fn
), "digits/thousand");
2122 if (num
< 1000000000) { /* 1,000,000,000 */
2123 res
= ast_say_number_full_se(chan
, num
/ 1000000, ints
, language
, options
, audiofd
, ctrlfd
);
2127 num
= num
% 1000000;
2128 snprintf(fn
, sizeof(fn
), "digits/million");
2130 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
2137 if (!ast_streamfile(chan
, fn
, language
)) {
2138 if ((audiofd
> -1) && (ctrlfd
> -1))
2139 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2141 res
= ast_waitstream(chan
, ints
);
2142 ast_stopstream(chan
);
2149 /*! \brief ast_say_number_full_tw: Taiwanese / Chinese syntax */
2150 static int ast_say_number_full_tw(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
)
2156 int last_length
= 0;
2160 return ast_say_digits_full(chan
, 0, ints
, language
, audiofd
, ctrlfd
);
2162 while (!res
&& (num
|| playh
|| playt
|| playz
)) {
2164 snprintf(fn
, sizeof(fn
), "digits/minus");
2165 if ( num
> INT_MIN
) {
2171 snprintf(fn
, sizeof(fn
), "digits/0");
2175 snprintf(fn
, sizeof(fn
), "digits/hundred");
2178 snprintf(fn
, sizeof(fn
), "digits/thousand");
2180 } else if (num
< 10) {
2181 snprintf(buf
, 10, "%d", num
);
2182 if (last_length
- strlen(buf
) > 1 && last_length
!= 0) {
2183 last_length
= strlen(buf
);
2187 if (strcasecmp(language
,"twz") == 0)
2188 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
2190 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
2192 } else if (num
< 100) {
2193 snprintf(buf
, 10, "%d", num
);
2194 if (last_length
- strlen(buf
) > 1 && last_length
!= 0) {
2195 last_length
= strlen(buf
);
2199 last_length
= strlen(buf
);
2200 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 10) * 10);
2201 num
-= ((num
/ 10) * 10);
2204 snprintf(buf
, 10, "%d", num
);
2205 if (last_length
- strlen(buf
) > 1 && last_length
!= 0) {
2206 last_length
= strlen(buf
);
2210 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 100));
2212 snprintf(buf
, 10, "%d", num
);
2213 ast_log(LOG_DEBUG
, "Number '%d' %d %d\n", num
, (int)strlen(buf
), last_length
);
2214 last_length
= strlen(buf
);
2215 num
-= ((num
/ 100) * 100);
2216 } else if (num
< 10000){
2217 snprintf(buf
, 10, "%d", num
);
2218 if (last_length
- strlen(buf
) > 1 && last_length
!= 0 && last_length
% strlen(buf
) > 0) {
2219 last_length
= strlen(buf
);
2223 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 1000));
2225 snprintf(buf
, 10, "%d", num
);
2226 ast_log(LOG_DEBUG
, "Number '%d' %d %d\n", num
, (int)strlen(buf
), last_length
);
2227 last_length
= strlen(buf
);
2228 num
-= ((num
/ 1000) * 1000);
2229 } else if (num
< 100000000) { /* 100,000,000 */
2230 res
= ast_say_number_full_tw(chan
, num
/ 10000, ints
, language
, audiofd
, ctrlfd
);
2233 if (((num
/ 10000) % (num
/100000)) == 0)
2236 snprintf(buf
, 10, "%d", num
);
2237 ast_log(LOG_DEBUG
, "Number '%d' %d %d\n", num
, (int)strlen(buf
), last_length
);
2238 num
-= ((num
/ 10000) * 10000);
2239 last_length
= strlen(buf
);
2240 snprintf(fn
, sizeof(fn
), "digits/wan");
2242 if (num
< 1000000000) { /* 1000,000,000 */
2243 res
= ast_say_number_full_tw(chan
, num
/ 100000000, ints
, language
, audiofd
, ctrlfd
);
2246 snprintf(buf
, 10, "%d", num
);
2247 ast_log(LOG_DEBUG
, "Number '%d' %d %d\n", num
, (int)strlen(buf
), last_length
);
2248 last_length
= strlen(buf
);
2249 num
-= ((num
/ 100000000) * 100000000);
2250 snprintf(fn
, sizeof(fn
), "digits/yi");
2252 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
2258 if (!ast_streamfile(chan
, fn
, language
)) {
2259 if ((audiofd
> -1) && (ctrlfd
> -1))
2260 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2262 res
= ast_waitstream(chan
, ints
);
2264 ast_stopstream(chan
);
2271 /*! \brief determine last digits for thousands/millions (ru) */
2272 static int get_lastdigits_ru(int num
) {
2275 } else if (num
< 100) {
2276 return get_lastdigits_ru(num
% 10);
2277 } else if (num
< 1000) {
2278 return get_lastdigits_ru(num
% 100);
2280 return 0; /* number too big */
2284 /*! \brief ast_say_number_full_ru: Russian syntax */
2285 /*! \brief additional files:
2286 n00.gsm (one hundred, two hundred, ...)
2289 thousands-i.gsm (tisyachi)
2290 million-a.gsm (milliona)
2296 where 'n' from 1 to 9
2298 static int ast_say_number_full_ru(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
2304 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
2306 while (!res
&& (num
)) {
2308 snprintf(fn
, sizeof(fn
), "digits/minus");
2309 if ( num
> INT_MIN
) {
2314 } else if (num
< 20) {
2315 if (options
&& strlen(options
) == 1 && num
< 3) {
2316 snprintf(fn
, sizeof(fn
), "digits/%d%s", num
, options
);
2318 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
2321 } else if (num
< 100) {
2322 snprintf(fn
, sizeof(fn
), "digits/%d", num
- (num
% 10));
2324 } else if (num
< 1000){
2325 snprintf(fn
, sizeof(fn
), "digits/%d", num
- (num
% 100));
2327 } else if (num
< 1000000) { /* 1,000,000 */
2328 lastdigits
= get_lastdigits_ru(num
/ 1000);
2330 if (lastdigits
< 3) {
2331 res
= ast_say_number_full_ru(chan
, num
/ 1000, ints
, language
, "f", audiofd
, ctrlfd
);
2333 res
= ast_say_number_full_ru(chan
, num
/ 1000, ints
, language
, NULL
, audiofd
, ctrlfd
);
2337 if (lastdigits
== 1) {
2338 snprintf(fn
, sizeof(fn
), "digits/thousand");
2339 } else if (lastdigits
> 1 && lastdigits
< 5) {
2340 snprintf(fn
, sizeof(fn
), "digits/thousands-i");
2342 snprintf(fn
, sizeof(fn
), "digits/thousands");
2345 } else if (num
< 1000000000) { /* 1,000,000,000 */
2346 lastdigits
= get_lastdigits_ru(num
/ 1000000);
2348 res
= ast_say_number_full_ru(chan
, num
/ 1000000, ints
, language
, NULL
, audiofd
, ctrlfd
);
2351 if (lastdigits
== 1) {
2352 snprintf(fn
, sizeof(fn
), "digits/million");
2353 } else if (lastdigits
> 1 && lastdigits
< 5) {
2354 snprintf(fn
, sizeof(fn
), "digits/million-a");
2356 snprintf(fn
, sizeof(fn
), "digits/millions");
2360 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
2364 if (!ast_streamfile(chan
, fn
, language
)) {
2365 if ((audiofd
> -1) && (ctrlfd
> -1))
2366 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2368 res
= ast_waitstream(chan
, ints
);
2370 ast_stopstream(chan
);
2377 /*! \brief ast_say_enumeration_full: call language-specific functions */
2378 /* Called from AGI */
2379 static int say_enumeration_full(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
2381 if (!strcasecmp(language
,"en") ) { /* English syntax */
2382 return(ast_say_enumeration_full_en(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
2383 } else if (!strcasecmp(language
, "da") ) { /* Danish syntax */
2384 return(ast_say_enumeration_full_da(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
2385 } else if (!strcasecmp(language
, "de") ) { /* German syntax */
2386 return(ast_say_enumeration_full_de(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
2387 } else if (!strcasecmp(language
, "he")) { /* Hebrew syntax */
2388 return (ast_say_enumeration_full_he(chan
, num
, ints
, language
, options
, audiofd
, ctrlfd
));
2391 /* Default to english */
2392 return(ast_say_enumeration_full_en(chan
, num
, ints
, language
, audiofd
, ctrlfd
));
2395 /*! \brief ast_say_enumeration_full_en: English syntax */
2396 /* This is the default syntax, if no other syntax defined in this file is used */
2397 static int ast_say_enumeration_full_en(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, int audiofd
, int ctrlfd
)
2402 while (!res
&& num
) {
2404 snprintf(fn
, sizeof(fn
), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2405 if ( num
> INT_MIN
) {
2410 } else if (num
< 20) {
2411 snprintf(fn
, sizeof(fn
), "digits/h-%d", num
);
2413 } else if (num
< 100) {
2414 int tens
= num
/ 10;
2417 snprintf(fn
, sizeof(fn
), "digits/h-%d", (tens
* 10));
2419 snprintf(fn
, sizeof(fn
), "digits/%d", (tens
* 10));
2421 } else if (num
< 1000) {
2422 int hundreds
= num
/ 100;
2424 if (hundreds
> 1 || t
== 1) {
2425 res
= ast_say_number_full_en(chan
, hundreds
, ints
, language
, audiofd
, ctrlfd
);
2430 snprintf(fn
, sizeof(fn
), "digits/hundred");
2432 snprintf(fn
, sizeof(fn
), "digits/h-hundred");
2434 } else if (num
< 1000000) {
2435 int thousands
= num
/ 1000;
2437 if (thousands
> 1 || t
== 1) {
2438 res
= ast_say_number_full_en(chan
, thousands
, ints
, language
, audiofd
, ctrlfd
);
2443 snprintf(fn
, sizeof(fn
), "digits/thousand");
2445 snprintf(fn
, sizeof(fn
), "digits/h-thousand");
2448 } else if (num
< 1000000000) {
2449 int millions
= num
/ 1000000;
2450 num
= num
% 1000000;
2452 res
= ast_say_number_full_en(chan
, millions
, ints
, language
, audiofd
, ctrlfd
);
2456 snprintf(fn
, sizeof(fn
), "digits/million");
2458 snprintf(fn
, sizeof(fn
), "digits/h-million");
2460 } else if (num
< INT_MAX
) {
2461 int billions
= num
/ 1000000000;
2462 num
= num
% 1000000000;
2464 res
= ast_say_number_full_en(chan
, billions
, ints
, language
, audiofd
, ctrlfd
);
2468 snprintf(fn
, sizeof(fn
), "digits/billion");
2470 snprintf(fn
, sizeof(fn
), "digits/h-billion");
2472 } else if (num
== INT_MAX
) {
2473 snprintf(fn
, sizeof(fn
), "digits/h-last");
2476 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
2481 if (!ast_streamfile(chan
, fn
, language
)) {
2482 if ((audiofd
> -1) && (ctrlfd
> -1)) {
2483 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2485 res
= ast_waitstream(chan
, ints
);
2488 ast_stopstream(chan
);
2494 /*! \brief ast_say_enumeration_full_da: Danish syntax */
2495 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
)
2497 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2499 char fn
[256] = "", fna
[256] = "";
2502 if (options
&& !strncasecmp(options
, "f",1)) {
2504 } else if (options
&& !strncasecmp(options
, "n",1)) {
2511 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
2513 while (!res
&& num
) {
2515 snprintf(fn
, sizeof(fn
), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2516 if ( num
> INT_MIN
) {
2521 } else if (num
< 100 && t
) {
2522 snprintf(fn
, sizeof(fn
), "digits/and");
2524 } else if (num
< 20) {
2525 snprintf(fn
, sizeof(fn
), "digits/h-%d%s", num
, gender
);
2527 } else if (num
< 100) {
2528 int ones
= num
% 10;
2530 snprintf(fn
, sizeof(fn
), "digits/%d-and", ones
);
2533 snprintf(fn
, sizeof(fn
), "digits/h-%d%s", num
, gender
);
2536 } else if (num
== 100 && t
== 0) {
2537 snprintf(fn
, sizeof(fn
), "digits/h-hundred%s", gender
);
2539 } else if (num
< 1000) {
2540 int hundreds
= num
/ 100;
2542 if (hundreds
== 1) {
2543 snprintf(fn
, sizeof(fn
), "digits/1N");
2545 snprintf(fn
, sizeof(fn
), "digits/%d", hundreds
);
2548 snprintf(fna
, sizeof(fna
), "digits/hundred");
2550 snprintf(fna
, sizeof(fna
), "digits/h-hundred%s", gender
);
2553 } else if (num
< 1000000) {
2554 int thousands
= num
/ 1000;
2556 if (thousands
== 1) {
2558 snprintf(fn
, sizeof(fn
), "digits/1N");
2559 snprintf(fna
, sizeof(fna
), "digits/thousand");
2562 snprintf(fn
, sizeof(fn
), "digits/1N");
2563 snprintf(fna
, sizeof(fna
), "digits/h-thousand%s", gender
);
2565 snprintf(fn
, sizeof(fn
), "digits/h-thousand%s", gender
);
2569 res
= ast_say_number_full_de(chan
, thousands
, ints
, language
, options
, audiofd
, ctrlfd
);
2574 snprintf(fn
, sizeof(fn
), "digits/thousand");
2576 snprintf(fn
, sizeof(fn
), "digits/h-thousand%s", gender
);
2580 } else if (num
< 1000000000) {
2581 int millions
= num
/ 1000000;
2582 num
= num
% 1000000;
2583 if (millions
== 1) {
2585 snprintf(fn
, sizeof(fn
), "digits/1F");
2586 snprintf(fna
, sizeof(fna
), "digits/million");
2588 snprintf(fn
, sizeof(fn
), "digits/1N");
2589 snprintf(fna
, sizeof(fna
), "digits/h-million%s", gender
);
2592 res
= ast_say_number_full_de(chan
, millions
, ints
, language
, options
, audiofd
, ctrlfd
);
2597 snprintf(fn
, sizeof(fn
), "digits/millions");
2599 snprintf(fn
, sizeof(fn
), "digits/h-million%s", gender
);
2603 } else if (num
< INT_MAX
) {
2604 int billions
= num
/ 1000000000;
2605 num
= num
% 1000000000;
2606 if (billions
== 1) {
2608 snprintf(fn
, sizeof(fn
), "digits/1F");
2609 snprintf(fna
, sizeof(fna
), "digits/milliard");
2611 snprintf(fn
, sizeof(fn
), "digits/1N");
2612 snprintf(fna
, sizeof(fna
), "digits/h-milliard%s", gender
);
2615 res
= ast_say_number_full_de(chan
, billions
, ints
, language
, options
, audiofd
, ctrlfd
);
2619 snprintf(fn
, sizeof(fna
), "digits/milliards");
2621 snprintf(fn
, sizeof(fna
), "digits/h-milliard%s", gender
);
2625 } else if (num
== INT_MAX
) {
2626 snprintf(fn
, sizeof(fn
), "digits/h-last%s", gender
);
2629 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
2634 if (!ast_streamfile(chan
, fn
, language
)) {
2635 if ((audiofd
> -1) && (ctrlfd
> -1))
2636 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2638 res
= ast_waitstream(chan
, ints
);
2640 ast_stopstream(chan
);
2642 if (strlen(fna
) != 0 && !ast_streamfile(chan
, fna
, language
)) {
2643 if ((audiofd
> -1) && (ctrlfd
> -1)) {
2644 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2646 res
= ast_waitstream(chan
, ints
);
2649 ast_stopstream(chan
);
2657 /*! \brief ast_say_enumeration_full_de: German syntax */
2658 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
)
2660 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2662 char fn
[256] = "", fna
[256] = "";
2665 if (options
&& !strncasecmp(options
, "f",1)) {
2667 } else if (options
&& !strncasecmp(options
, "n",1)) {
2674 return ast_say_digits_full(chan
, 0,ints
, language
, audiofd
, ctrlfd
);
2676 while (!res
&& num
) {
2678 snprintf(fn
, sizeof(fn
), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2679 if ( num
> INT_MIN
) {
2684 } else if (num
< 100 && t
) {
2685 snprintf(fn
, sizeof(fn
), "digits/and");
2687 } else if (num
< 20) {
2688 snprintf(fn
, sizeof(fn
), "digits/h-%d%s", num
, gender
);
2690 } else if (num
< 100) {
2691 int ones
= num
% 10;
2693 snprintf(fn
, sizeof(fn
), "digits/%d-and", ones
);
2696 snprintf(fn
, sizeof(fn
), "digits/h-%d%s", num
, gender
);
2699 } else if (num
== 100 && t
== 0) {
2700 snprintf(fn
, sizeof(fn
), "digits/h-hundred%s", gender
);
2702 } else if (num
< 1000) {
2703 int hundreds
= num
/ 100;
2705 if (hundreds
== 1) {
2706 snprintf(fn
, sizeof(fn
), "digits/1N");
2708 snprintf(fn
, sizeof(fn
), "digits/%d", hundreds
);
2711 snprintf(fna
, sizeof(fna
), "digits/hundred");
2713 snprintf(fna
, sizeof(fna
), "digits/h-hundred%s", gender
);
2716 } else if (num
< 1000000) {
2717 int thousands
= num
/ 1000;
2719 if (thousands
== 1) {
2721 snprintf(fn
, sizeof(fn
), "digits/1N");
2722 snprintf(fna
, sizeof(fna
), "digits/thousand");
2725 snprintf(fn
, sizeof(fn
), "digits/1N");
2726 snprintf(fna
, sizeof(fna
), "digits/h-thousand%s", gender
);
2728 snprintf(fn
, sizeof(fn
), "digits/h-thousand%s", gender
);
2732 res
= ast_say_number_full_de(chan
, thousands
, ints
, language
, options
, audiofd
, ctrlfd
);
2737 snprintf(fn
, sizeof(fn
), "digits/thousand");
2739 snprintf(fn
, sizeof(fn
), "digits/h-thousand%s", gender
);
2743 } else if (num
< 1000000000) {
2744 int millions
= num
/ 1000000;
2745 num
= num
% 1000000;
2746 if (millions
== 1) {
2748 snprintf(fn
, sizeof(fn
), "digits/1F");
2749 snprintf(fna
, sizeof(fna
), "digits/million");
2751 snprintf(fn
, sizeof(fn
), "digits/1N");
2752 snprintf(fna
, sizeof(fna
), "digits/h-million%s", gender
);
2755 res
= ast_say_number_full_de(chan
, millions
, ints
, language
, options
, audiofd
, ctrlfd
);
2760 snprintf(fn
, sizeof(fn
), "digits/millions");
2762 snprintf(fn
, sizeof(fn
), "digits/h-million%s", gender
);
2766 } else if (num
< INT_MAX
) {
2767 int billions
= num
/ 1000000000;
2768 num
= num
% 1000000000;
2769 if (billions
== 1) {
2771 snprintf(fn
, sizeof(fn
), "digits/1F");
2772 snprintf(fna
, sizeof(fna
), "digits/milliard");
2774 snprintf(fn
, sizeof(fn
), "digits/1N");
2775 snprintf(fna
, sizeof(fna
), "digits/h-milliard%s", gender
);
2778 res
= ast_say_number_full_de(chan
, billions
, ints
, language
, options
, audiofd
, ctrlfd
);
2782 snprintf(fn
, sizeof(fna
), "digits/milliards");
2784 snprintf(fn
, sizeof(fna
), "digits/h-milliard%s", gender
);
2788 } else if (num
== INT_MAX
) {
2789 snprintf(fn
, sizeof(fn
), "digits/h-last%s", gender
);
2792 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
2797 if (!ast_streamfile(chan
, fn
, language
)) {
2798 if ((audiofd
> -1) && (ctrlfd
> -1))
2799 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2801 res
= ast_waitstream(chan
, ints
);
2803 ast_stopstream(chan
);
2805 if (strlen(fna
) != 0 && !ast_streamfile(chan
, fna
, language
)) {
2806 if ((audiofd
> -1) && (ctrlfd
> -1)) {
2807 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2809 res
= ast_waitstream(chan
, ints
);
2812 ast_stopstream(chan
);
2820 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
)
2824 int mf
= -1; /* +1 = Masculin; -1 = Feminin */
2825 ast_verbose(VERBOSE_PREFIX_3
"ast_say_digits_full: started. num: %d, options=\"%s\"\n", num
, options
);
2827 if (options
&& !strncasecmp(options
, "m", 1)) {
2831 ast_verbose(VERBOSE_PREFIX_3
"ast_say_digits_full: num: %d, options=\"%s\", mf=%d\n", num
, options
, mf
);
2833 while (!res
&& num
) {
2835 snprintf(fn
, sizeof(fn
), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2836 if (num
> INT_MIN
) {
2841 } else if (num
< 21) {
2844 snprintf(fn
, sizeof(fn
), "digits/f-0%d", num
);
2846 snprintf(fn
, sizeof(fn
), "digits/f-%d", num
);
2850 snprintf(fn
, sizeof(fn
), "digits/m-0%d", num
);
2852 snprintf(fn
, sizeof(fn
), "digits/m-%d", num
);
2856 } else if ((num
< 100) && num
>= 20) {
2857 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/ 10) * 10);
2859 } else if ((num
>= 100) && (num
< 1000)) {
2860 int tmpnum
= num
/ 100;
2861 snprintf(fn
, sizeof(fn
), "digits/%d00", tmpnum
);
2862 num
= num
- (tmpnum
* 100);
2863 } else if ((num
>= 1000) && (num
< 10000)) {
2864 int tmpnum
= num
/ 1000;
2865 snprintf(fn
, sizeof(fn
), "digits/%dk", tmpnum
);
2866 num
= num
- (tmpnum
* 1000);
2867 } else if (num
< 20000) {
2868 snprintf(fn
, sizeof(fn
), "digits/m-%d", (num
/ 1000));
2870 } else if (num
< 1000000) {
2871 res
= ast_say_number_full_he(chan
, num
/ 1000, ints
, language
, "m", audiofd
, ctrlfd
);
2875 snprintf(fn
, sizeof(fn
), "digits/1k");
2877 } else if (num
< 2000000) {
2878 snprintf(fn
, sizeof(fn
), "digits/1m");
2879 num
= num
% 1000000;
2880 } else if (num
< 3000000) {
2881 snprintf(fn
, sizeof(fn
), "digits/2m");
2882 num
= num
- 2000000;
2883 } else if (num
< 1000000000) {
2884 res
= ast_say_number_full_he(chan
, num
/ 1000000, ints
, language
, "m", audiofd
, ctrlfd
);
2888 snprintf(fn
, sizeof(fn
), "digits/1m");
2889 num
= num
% 1000000;
2891 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
2895 if (!ast_streamfile(chan
, fn
, language
)) {
2896 if ((audiofd
> -1) && (ctrlfd
> -1)) {
2897 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
2899 res
= ast_waitstream(chan
, ints
);
2902 ast_stopstream(chan
);
2908 static int say_date(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
2910 if (!strcasecmp(lang
, "en") ) { /* English syntax */
2911 return(ast_say_date_en(chan
, t
, ints
, lang
));
2912 } else if (!strcasecmp(lang
, "da") ) { /* Danish syntax */
2913 return(ast_say_date_da(chan
, t
, ints
, lang
));
2914 } else if (!strcasecmp(lang
, "de") ) { /* German syntax */
2915 return(ast_say_date_de(chan
, t
, ints
, lang
));
2916 } else if (!strcasecmp(lang
, "fr") ) { /* French syntax */
2917 return(ast_say_date_fr(chan
, t
, ints
, lang
));
2918 } else if (!strcasecmp(lang
, "nl") ) { /* Dutch syntax */
2919 return(ast_say_date_nl(chan
, t
, ints
, lang
));
2920 } else if (!strcasecmp(lang
, "pt") || !strcasecmp(lang
, "pt_BR")) { /* Portuguese syntax */
2921 return(ast_say_date_pt(chan
, t
, ints
, lang
));
2922 } else if (!strcasecmp(lang
, "gr") ) { /* Greek syntax */
2923 return(ast_say_date_gr(chan
, t
, ints
, lang
));
2924 } else if (!strcasecmp(lang
, "ge") ) { /* Georgian syntax */
2925 return(ast_say_date_ge(chan
, t
, ints
, lang
));
2926 } else if (!strcasecmp(lang
, "he")) { /* Hebrew syntax */
2927 return (ast_say_date_he(chan
, t
, ints
, lang
));
2930 /* Default to English */
2931 return(ast_say_date_en(chan
, t
, ints
, lang
));
2934 /* English syntax */
2935 int ast_say_date_en(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
2940 ast_localtime(&t
,&tm
,NULL
);
2942 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
2943 res
= ast_streamfile(chan
, fn
, lang
);
2945 res
= ast_waitstream(chan
, ints
);
2948 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
2949 res
= ast_streamfile(chan
, fn
, lang
);
2951 res
= ast_waitstream(chan
, ints
);
2954 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char * ) NULL
);
2956 res
= ast_waitstream(chan
, ints
);
2958 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
2963 int ast_say_date_da(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
2968 ast_localtime(&t
,&tm
,NULL
);
2970 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
2971 res
= ast_streamfile(chan
, fn
, lang
);
2973 res
= ast_waitstream(chan
, ints
);
2976 res
= ast_say_enumeration(chan
, tm
.tm_mday
, ints
, lang
, (char * ) NULL
);
2978 res
= ast_waitstream(chan
, ints
);
2980 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
2981 res
= ast_streamfile(chan
, fn
, lang
);
2983 res
= ast_waitstream(chan
, ints
);
2987 int year
= tm
.tm_year
+ 1900;
2988 if (year
> 1999) { /* year 2000 and later */
2989 res
= ast_say_number(chan
, year
, ints
, lang
, (char *) NULL
);
2992 /* I'm not going to handle 1100 and prior */
2993 /* We'll just be silent on the year, instead of bombing out. */
2995 /* year 1100 to 1999. will anybody need this?!? */
2996 snprintf(fn
,sizeof(fn
), "digits/%d", (year
/ 100) );
2997 res
= wait_file(chan
, ints
, fn
, lang
);
2999 res
= wait_file(chan
,ints
, "digits/hundred", lang
);
3000 if (!res
&& year
% 100 != 0) {
3001 res
= ast_say_number(chan
, (year
% 100), ints
, lang
, (char *) NULL
);
3011 int ast_say_date_de(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
3016 ast_localtime(&t
,&tm
,NULL
);
3018 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
3019 res
= ast_streamfile(chan
, fn
, lang
);
3021 res
= ast_waitstream(chan
, ints
);
3024 res
= ast_say_enumeration(chan
, tm
.tm_mday
, ints
, lang
, (char * ) NULL
);
3026 res
= ast_waitstream(chan
, ints
);
3028 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
3029 res
= ast_streamfile(chan
, fn
, lang
);
3031 res
= ast_waitstream(chan
, ints
);
3035 int year
= tm
.tm_year
+ 1900;
3036 if (year
> 1999) { /* year 2000 and later */
3037 res
= ast_say_number(chan
, year
, ints
, lang
, (char *) NULL
);
3040 /* I'm not going to handle 1100 and prior */
3041 /* We'll just be silent on the year, instead of bombing out. */
3043 /* year 1100 to 1999. will anybody need this?!? */
3044 /* say 1967 as 'neunzehn hundert sieben und sechzig' */
3045 snprintf(fn
,sizeof(fn
), "digits/%d", (year
/ 100) );
3046 res
= wait_file(chan
, ints
, fn
, lang
);
3048 res
= wait_file(chan
,ints
, "digits/hundred", lang
);
3049 if (!res
&& year
% 100 != 0) {
3050 res
= ast_say_number(chan
, (year
% 100), ints
, lang
, (char *) NULL
);
3060 int ast_say_date_fr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
3065 ast_localtime(&t
,&tm
,NULL
);
3067 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
3068 res
= ast_streamfile(chan
, fn
, lang
);
3070 res
= ast_waitstream(chan
, ints
);
3073 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char * ) NULL
);
3075 res
= ast_waitstream(chan
, ints
);
3077 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
3078 res
= ast_streamfile(chan
, fn
, lang
);
3080 res
= ast_waitstream(chan
, ints
);
3083 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
3088 int ast_say_date_nl(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
3093 ast_localtime(&t
,&tm
,NULL
);
3095 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
3096 res
= ast_streamfile(chan
, fn
, lang
);
3098 res
= ast_waitstream(chan
, ints
);
3101 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char * ) NULL
);
3103 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
3104 res
= ast_streamfile(chan
, fn
, lang
);
3106 res
= ast_waitstream(chan
, ints
);
3109 res
= ast_waitstream(chan
, ints
);
3111 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
3115 /* Portuguese syntax */
3116 int ast_say_date_pt(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
3122 ast_localtime(&t
, &tm
, NULL
);
3123 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
3125 res
= wait_file(chan
, ints
, fn
, lang
);
3127 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
3129 res
= wait_file(chan
, ints
, "digits/pt-de", lang
);
3130 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
3132 res
= wait_file(chan
, ints
, fn
, lang
);
3134 res
= wait_file(chan
, ints
, "digits/pt-de", lang
);
3136 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
3142 int ast_say_date_he(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
3147 ast_localtime(&t
, &tm
, NULL
);
3149 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
3150 res
= ast_streamfile(chan
, fn
, lang
);
3152 res
= ast_waitstream(chan
, ints
);
3156 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
3157 res
= ast_streamfile(chan
, fn
, lang
);
3159 res
= ast_waitstream(chan
, ints
);
3163 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, "m");
3166 res
= ast_waitstream(chan
, ints
);
3169 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, "m");
3174 static int say_date_with_format(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
3176 if (!strcasecmp(lang
, "en") ) { /* English syntax */
3177 return(ast_say_date_with_format_en(chan
, time
, ints
, lang
, format
, timezone
));
3178 } else if (!strcasecmp(lang
, "da") ) { /* Danish syntax */
3179 return(ast_say_date_with_format_da(chan
, time
, ints
, lang
, format
, timezone
));
3180 } else if (!strcasecmp(lang
, "de") ) { /* German syntax */
3181 return(ast_say_date_with_format_de(chan
, time
, ints
, lang
, format
, timezone
));
3182 } else if (!strcasecmp(lang
, "es") || !strcasecmp(lang
, "mx")) { /* Spanish syntax */
3183 return (ast_say_date_with_format_es(chan
, time
, ints
, lang
, format
, timezone
));
3184 } else if (!strcasecmp(lang
, "he")) { /* Hebrew syntax */
3185 return (ast_say_date_with_format_he(chan
, time
, ints
, lang
, format
, timezone
));
3186 } else if (!strcasecmp(lang
, "fr")) { /* French syntax */
3187 return (ast_say_date_with_format_fr(chan
, time
, ints
, lang
, format
, timezone
));
3188 } else if (!strcasecmp(lang
, "it")) { /* Italian syntax */
3189 return (ast_say_date_with_format_it(chan
, time
, ints
, lang
, format
, timezone
));
3190 } else if (!strcasecmp(lang
, "nl")) { /* Dutch syntax */
3191 return (ast_say_date_with_format_nl(chan
, time
, ints
, lang
, format
, timezone
));
3192 } else if (!strcasecmp(lang
, "pl")) { /* Polish syntax */
3193 return (ast_say_date_with_format_pl(chan
, time
, ints
, lang
, format
, timezone
));
3194 } else if (!strcasecmp(lang
, "pt") || !strcasecmp(lang
, "pt_BR")) { /* Portuguese syntax */
3195 return(ast_say_date_with_format_pt(chan
, time
, ints
, lang
, format
, timezone
));
3196 } else if (!strcasecmp(lang
, "tw") || !strcasecmp(lang
, "zh") ) { /* Taiwanese / Chinese syntax */
3197 return(ast_say_date_with_format_tw(chan
, time
, ints
, lang
, format
, timezone
));
3198 } else if (!strcasecmp(lang
, "gr") ) { /* Greek syntax */
3199 return(ast_say_date_with_format_gr(chan
, time
, ints
, lang
, format
, timezone
));
3202 /* Default to English */
3203 return(ast_say_date_with_format_en(chan
, time
, ints
, lang
, format
, timezone
));
3206 /* English syntax */
3207 int ast_say_date_with_format_en(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
3210 int res
=0, offset
, sndoffset
;
3211 char sndfile
[256], nextmsg
[256];
3214 format
= "ABdY 'digits/at' IMp";
3216 ast_localtime(&time
,&tm
,timezone
);
3218 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
3219 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
3220 switch (format
[offset
]) {
3221 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
3223 /* Literal name of a sound file */
3225 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
3226 sndfile
[sndoffset
] = format
[offset
];
3227 sndfile
[sndoffset
] = '\0';
3228 res
= wait_file(chan
,ints
,sndfile
,lang
);
3232 /* Sunday - Saturday */
3233 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
3234 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3239 /* January - December */
3240 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
3241 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3244 /* Month enumerated */
3245 res
= ast_say_enumeration(chan
, (tm
.tm_mon
+ 1), ints
, lang
, (char *) NULL
);
3249 /* First - Thirtyfirst */
3250 res
= ast_say_enumeration(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
3254 if (tm
.tm_year
> 99) {
3255 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
3256 } else if (tm
.tm_year
< 1) {
3257 /* I'm not going to handle 1900 and prior */
3258 /* We'll just be silent on the year, instead of bombing out. */
3260 res
= wait_file(chan
, ints
, "digits/19", lang
);
3262 if (tm
.tm_year
<= 9) {
3264 res
= wait_file(chan
,ints
, "digits/oh", lang
);
3267 res
|= ast_say_number(chan
, tm
.tm_year
, ints
, lang
, (char *) NULL
);
3274 if (tm
.tm_hour
== 0)
3275 snprintf(nextmsg
,sizeof(nextmsg
), "digits/12");
3276 else if (tm
.tm_hour
> 12)
3277 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- 12);
3279 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
3280 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3285 if (format
[offset
] == 'H') {
3287 if (tm
.tm_hour
< 10) {
3288 res
= wait_file(chan
,ints
, "digits/oh",lang
);
3292 if (tm
.tm_hour
== 0) {
3293 res
= wait_file(chan
,ints
, "digits/oh",lang
);
3297 if (tm
.tm_hour
!= 0) {
3298 int remainder
= tm
.tm_hour
;
3299 if (tm
.tm_hour
> 20) {
3300 res
= wait_file(chan
,ints
, "digits/20",lang
);
3304 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", remainder
);
3305 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3313 if (tm
.tm_min
== 0) {
3314 if (format
[offset
] == 'M') {
3315 res
= wait_file(chan
, ints
, "digits/oclock", lang
);
3317 res
= wait_file(chan
, ints
, "digits/hundred", lang
);
3319 } else if (tm
.tm_min
< 10) {
3320 res
= wait_file(chan
,ints
, "digits/oh",lang
);
3322 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_min
);
3323 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3326 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
3332 if (tm
.tm_hour
> 11)
3333 snprintf(nextmsg
,sizeof(nextmsg
), "digits/p-m");
3335 snprintf(nextmsg
,sizeof(nextmsg
), "digits/a-m");
3336 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3339 /* Shorthand for "Today", "Yesterday", or ABdY */
3340 /* XXX As emphasized elsewhere, this should the native way in your
3341 * language to say the date, with changes in what you say, depending
3342 * upon how recent the date is. XXX */
3346 time_t beg_today
, tt
;
3348 gettimeofday(&now
,NULL
);
3350 ast_localtime(&tt
,&tmnow
,timezone
);
3351 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3352 /* In any case, it saves not having to do ast_mktime() */
3353 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
3354 if (beg_today
< time
) {
3356 res
= wait_file(chan
,ints
, "digits/today",lang
);
3357 } else if (beg_today
- 86400 < time
) {
3359 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
3360 } else if (beg_today
- 86400 * 6 < time
) {
3361 /* Within the last week */
3362 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "A", timezone
);
3363 } else if (beg_today
- 2628000 < time
) {
3364 /* Less than a month ago - "Sunday, October third" */
3365 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "ABd", timezone
);
3366 } else if (beg_today
- 15768000 < time
) {
3367 /* Less than 6 months ago - "August seventh" */
3368 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "Bd", timezone
);
3370 /* More than 6 months ago - "April nineteenth two thousand three" */
3371 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "BdY", timezone
);
3376 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
3377 /* XXX As emphasized elsewhere, this should the native way in your
3378 * language to say the date, with changes in what you say, depending
3379 * upon how recent the date is. XXX */
3383 time_t beg_today
, tt
;
3385 gettimeofday(&now
,NULL
);
3387 ast_localtime(&tt
,&tmnow
,timezone
);
3388 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3389 /* In any case, it saves not having to do ast_mktime() */
3390 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
3391 if (beg_today
< time
) {
3393 } else if ((beg_today
- 86400) < time
) {
3395 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
3396 } else if (beg_today
- 86400 * 6 < time
) {
3397 /* Within the last week */
3398 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "A", timezone
);
3399 } else if (beg_today
- 2628000 < time
) {
3400 /* Less than a month ago - "Sunday, October third" */
3401 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "ABd", timezone
);
3402 } else if (beg_today
- 15768000 < time
) {
3403 /* Less than 6 months ago - "August seventh" */
3404 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "Bd", timezone
);
3406 /* More than 6 months ago - "April nineteenth two thousand three" */
3407 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "BdY", timezone
);
3412 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "HM", timezone
);
3416 if (tm
.tm_sec
== 0) {
3417 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
3418 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3419 } else if (tm
.tm_sec
< 10) {
3420 res
= wait_file(chan
,ints
, "digits/oh",lang
);
3422 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
3423 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3426 res
= ast_say_number(chan
, tm
.tm_sec
, ints
, lang
, (char *) NULL
);
3430 res
= ast_say_date_with_format_en(chan
, time
, ints
, lang
, "HMS", timezone
);
3434 /* Just ignore spaces and tabs */
3437 /* Unknown character */
3438 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
3440 /* Jump out on DTMF */
3449 int ast_say_date_with_format_da(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
3452 int res
=0, offset
, sndoffset
;
3453 char sndfile
[256], nextmsg
[256];
3456 format
= "A dBY HMS";
3458 ast_localtime(&time
,&tm
,timezone
);
3460 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
3461 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
3462 switch (format
[offset
]) {
3463 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
3465 /* Literal name of a sound file */
3467 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
3468 sndfile
[sndoffset
] = format
[offset
];
3469 sndfile
[sndoffset
] = '\0';
3470 res
= wait_file(chan
,ints
,sndfile
,lang
);
3474 /* Sunday - Saturday */
3475 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
3476 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3481 /* January - December */
3482 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
3483 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3486 /* Month enumerated */
3487 res
= ast_say_enumeration(chan
, (tm
.tm_mon
+ 1), ints
, lang
, "m");
3491 /* First - Thirtyfirst */
3492 res
= ast_say_enumeration(chan
, tm
.tm_mday
, ints
, lang
, "m");
3497 int year
= tm
.tm_year
+ 1900;
3498 if (year
> 1999) { /* year 2000 and later */
3499 res
= ast_say_number(chan
, year
, ints
, lang
, (char *) NULL
);
3502 /* I'm not going to handle 1100 and prior */
3503 /* We'll just be silent on the year, instead of bombing out. */
3505 /* year 1100 to 1999. will anybody need this?!? */
3506 /* say 1967 as 'nineteen hundred seven and sixty' */
3507 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", (year
/ 100) );
3508 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3510 res
= wait_file(chan
,ints
, "digits/hundred",lang
);
3511 if (!res
&& year
% 100 != 0) {
3512 res
= ast_say_number(chan
, (year
% 100), ints
, lang
, (char *) NULL
);
3522 res
= wait_file(chan
,ints
,"digits/oclock",lang
);
3523 if (tm
.tm_hour
== 0)
3524 snprintf(nextmsg
,sizeof(nextmsg
), "digits/12");
3525 else if (tm
.tm_hour
> 12)
3526 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- 12);
3528 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
3530 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3534 /* 24-Hour, single digit hours preceeded by "oh" (0) */
3535 if (tm
.tm_hour
< 10 && tm
.tm_hour
> 0) {
3536 res
= wait_file(chan
,ints
, "digits/0",lang
);
3541 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, (char *) NULL
);
3545 if (tm
.tm_min
> 0 || format
[offset
+ 1 ] == 'S' ) { /* zero 'digits/0' only if seconds follow (kind of a hack) */
3546 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, "f");
3548 if ( !res
&& format
[offset
+ 1] == 'S' ) { /* minutes only if seconds follow (kind of a hack) */
3549 if (tm
.tm_min
== 1) {
3550 res
= wait_file(chan
,ints
,"digits/minute",lang
);
3552 res
= wait_file(chan
,ints
,"digits/minutes",lang
);
3559 if (tm
.tm_hour
> 11)
3560 snprintf(nextmsg
,sizeof(nextmsg
), "digits/p-m");
3562 snprintf(nextmsg
,sizeof(nextmsg
), "digits/a-m");
3563 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3566 /* Shorthand for "Today", "Yesterday", or AdBY */
3567 /* XXX As emphasized elsewhere, this should the native way in your
3568 * language to say the date, with changes in what you say, depending
3569 * upon how recent the date is. XXX */
3573 time_t beg_today
, tt
;
3575 gettimeofday(&now
,NULL
);
3577 ast_localtime(&tt
,&tmnow
,timezone
);
3578 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3579 /* In any case, it saves not having to do ast_mktime() */
3580 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
3581 if (beg_today
< time
) {
3583 res
= wait_file(chan
,ints
, "digits/today",lang
);
3584 } else if (beg_today
- 86400 < time
) {
3586 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
3588 res
= ast_say_date_with_format_da(chan
, time
, ints
, lang
, "AdBY", timezone
);
3593 /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */
3594 /* XXX As emphasized elsewhere, this should the native way in your
3595 * language to say the date, with changes in what you say, depending
3596 * upon how recent the date is. XXX */
3600 time_t beg_today
, tt
;
3602 gettimeofday(&now
,NULL
);
3604 ast_localtime(&tt
,&tmnow
,timezone
);
3605 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3606 /* In any case, it saves not having to do ast_mktime() */
3607 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
3608 if (beg_today
< time
) {
3610 } else if ((beg_today
- 86400) < time
) {
3612 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
3613 } else if (beg_today
- 86400 * 6 < time
) {
3614 /* Within the last week */
3615 res
= ast_say_date_with_format_da(chan
, time
, ints
, lang
, "A", timezone
);
3617 res
= ast_say_date_with_format_da(chan
, time
, ints
, lang
, "AdBY", timezone
);
3622 res
= ast_say_date_with_format_da(chan
, time
, ints
, lang
, "HM", timezone
);
3626 res
= wait_file(chan
,ints
, "digits/and",lang
);
3628 res
= ast_say_number(chan
, tm
.tm_sec
, ints
, lang
, "f");
3630 res
= wait_file(chan
,ints
, "digits/seconds",lang
);
3635 res
= ast_say_date_with_format_da(chan
, time
, ints
, lang
, "HMS", timezone
);
3639 /* Just ignore spaces and tabs */
3642 /* Unknown character */
3643 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
3645 /* Jump out on DTMF */
3654 int ast_say_date_with_format_de(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
3657 int res
=0, offset
, sndoffset
;
3658 char sndfile
[256], nextmsg
[256];
3661 format
= "A dBY HMS";
3663 ast_localtime(&time
,&tm
,timezone
);
3665 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
3666 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
3667 switch (format
[offset
]) {
3668 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
3670 /* Literal name of a sound file */
3672 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
3673 sndfile
[sndoffset
] = format
[offset
];
3674 sndfile
[sndoffset
] = '\0';
3675 res
= wait_file(chan
,ints
,sndfile
,lang
);
3679 /* Sunday - Saturday */
3680 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
3681 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3686 /* January - December */
3687 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
3688 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3691 /* Month enumerated */
3692 res
= ast_say_enumeration(chan
, (tm
.tm_mon
+ 1), ints
, lang
, "m");
3696 /* First - Thirtyfirst */
3697 res
= ast_say_enumeration(chan
, tm
.tm_mday
, ints
, lang
, "m");
3702 int year
= tm
.tm_year
+ 1900;
3703 if (year
> 1999) { /* year 2000 and later */
3704 res
= ast_say_number(chan
, year
, ints
, lang
, (char *) NULL
);
3707 /* I'm not going to handle 1100 and prior */
3708 /* We'll just be silent on the year, instead of bombing out. */
3710 /* year 1100 to 1999. will anybody need this?!? */
3711 /* say 1967 as 'neunzehn hundert sieben und sechzig' */
3712 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", (year
/ 100) );
3713 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3715 res
= wait_file(chan
,ints
, "digits/hundred",lang
);
3716 if (!res
&& year
% 100 != 0) {
3717 res
= ast_say_number(chan
, (year
% 100), ints
, lang
, (char *) NULL
);
3727 if (tm
.tm_hour
== 0)
3728 snprintf(nextmsg
,sizeof(nextmsg
), "digits/12");
3729 else if (tm
.tm_hour
> 12)
3730 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- 12);
3732 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
3733 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3735 res
= wait_file(chan
,ints
,"digits/oclock",lang
);
3741 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, (char *) NULL
);
3743 res
= wait_file(chan
,ints
,"digits/oclock",lang
);
3748 if (tm
.tm_min
> 0 || format
[offset
+ 1 ] == 'S' ) { /* zero 'digits/0' only if seconds follow (kind of a hack) */
3749 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, "f");
3751 if ( !res
&& format
[offset
+ 1] == 'S' ) { /* minutes only if seconds follow (kind of a hack) */
3752 if (tm
.tm_min
== 1) {
3753 res
= wait_file(chan
,ints
,"digits/minute",lang
);
3755 res
= wait_file(chan
,ints
,"digits/minutes",lang
);
3762 if (tm
.tm_hour
> 11)
3763 snprintf(nextmsg
,sizeof(nextmsg
), "digits/p-m");
3765 snprintf(nextmsg
,sizeof(nextmsg
), "digits/a-m");
3766 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3769 /* Shorthand for "Today", "Yesterday", or AdBY */
3770 /* XXX As emphasized elsewhere, this should the native way in your
3771 * language to say the date, with changes in what you say, depending
3772 * upon how recent the date is. XXX */
3776 time_t beg_today
, tt
;
3778 gettimeofday(&now
,NULL
);
3780 ast_localtime(&tt
,&tmnow
,timezone
);
3781 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3782 /* In any case, it saves not having to do ast_mktime() */
3783 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
3784 if (beg_today
< time
) {
3786 res
= wait_file(chan
,ints
, "digits/today",lang
);
3787 } else if (beg_today
- 86400 < time
) {
3789 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
3791 res
= ast_say_date_with_format_de(chan
, time
, ints
, lang
, "AdBY", timezone
);
3796 /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */
3797 /* XXX As emphasized elsewhere, this should the native way in your
3798 * language to say the date, with changes in what you say, depending
3799 * upon how recent the date is. XXX */
3803 time_t beg_today
, tt
;
3805 gettimeofday(&now
,NULL
);
3807 ast_localtime(&tt
,&tmnow
,timezone
);
3808 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3809 /* In any case, it saves not having to do ast_mktime() */
3810 beg_today
= now
.tv_sec
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
3811 if (beg_today
< time
) {
3813 } else if ((beg_today
- 86400) < time
) {
3815 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
3816 } else if (beg_today
- 86400 * 6 < time
) {
3817 /* Within the last week */
3818 res
= ast_say_date_with_format_de(chan
, time
, ints
, lang
, "A", timezone
);
3820 res
= ast_say_date_with_format_de(chan
, time
, ints
, lang
, "AdBY", timezone
);
3825 res
= ast_say_date_with_format_de(chan
, time
, ints
, lang
, "HM", timezone
);
3829 res
= wait_file(chan
,ints
, "digits/and",lang
);
3831 res
= ast_say_number(chan
, tm
.tm_sec
, ints
, lang
, "f");
3833 res
= wait_file(chan
,ints
, "digits/seconds",lang
);
3838 res
= ast_say_date_with_format_de(chan
, time
, ints
, lang
, "HMS", timezone
);
3842 /* Just ignore spaces and tabs */
3845 /* Unknown character */
3846 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
3848 /* Jump out on DTMF */
3856 /* TODO: this probably is not the correct format for doxygen remarks */
3858 /** ast_say_date_with_format_he Say formmated date in Hebrew
3860 * \ref ast_say_date_with_format_en for the details of the options
3862 * Changes from the English version:
3864 * * don't replicate in here the logic of ast_say_number_full_he
3866 * * year is always 4-digit (because it's simpler)
3868 * * added c, x, and X. Mainly for my tests
3870 * * The standard "long" format used in Hebrew is AdBY, rather than ABdY
3873 * * A "ha" is missing in the standard date format, before the 'd'.
3874 * * The numbers of 3000--19000 are not handled well
3876 #define IL_DATE_STR "AdBY"
3877 #define IL_TIME_STR "HM" /* NOTE: In Hebrew we do not support 12 hours, only 24. No AM or PM exists in the Hebrew language */
3878 #define IL_DATE_STR_FULL IL_DATE_STR " 'digits/at' " IL_TIME_STR
3879 int ast_say_date_with_format_he(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
3881 /* TODO: This whole function is cut&paste from
3882 * ast_say_date_with_format_en . Is that considered acceptable?
3885 int res
= 0, offset
, sndoffset
;
3886 char sndfile
[256], nextmsg
[256];
3889 format
= IL_DATE_STR_FULL
;
3892 ast_localtime(&time
, &tm
, timezone
);
3894 for (offset
= 0; format
[offset
] != '\0'; offset
++) {
3895 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
3896 switch (format
[offset
]) {
3897 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
3899 /* Literal name of a sound file */
3901 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
3902 sndfile
[sndoffset
] = format
[offset
];
3903 sndfile
[sndoffset
] = '\0';
3904 res
= wait_file(chan
,ints
,sndfile
,lang
);
3908 /* Sunday - Saturday */
3909 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
3910 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3915 /* January - December */
3916 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
3917 res
= wait_file(chan
,ints
,nextmsg
,lang
);
3920 case 'e': /* Day of the month */
3921 /* I'm not sure exactly what the parameters
3922 * audiofd and ctrlfd to
3923 * ast_say_number_full_he mean, but it seems
3924 * safe to pass -1 there.
3926 * At least in one of the pathes :-(
3928 res
= ast_say_number_full_he(chan
, tm
.tm_mday
, ints
, lang
, "m", -1, -1);
3930 case 'Y': /* Year */
3931 res
= ast_say_number_full_he(chan
, tm
.tm_year
+1900,
3932 ints
, lang
, "f", -1, -1
3936 case 'l': /* 12-Hour -> we do not support 12 hour based langauges in Hebrew */
3938 case 'k': /* 24-Hour */
3939 res
= ast_say_number_full_he(chan
, tm
.tm_hour
, ints
, lang
, "f", -1, -1);
3941 case 'M': /* Minute */
3942 if (tm
.tm_min
>= 0 && tm
.tm_min
<= 9) /* say a leading zero if needed */
3943 res
= ast_say_number_full_he(chan
, 0, ints
, lang
, "f", -1, -1);
3944 res
= ast_say_number_full_he(chan
, tm
.tm_min
, ints
, lang
, "f", -1, -1);
3948 /* AM/PM - There is no AM/PM in Hebrew... */
3951 /* Shorthand for "Today", "Yesterday", or "date" */
3953 /* Shorthand for "" (today), "Yesterday", A
3954 * (weekday), or "date" */
3955 /* XXX As emphasized elsewhere, this should the native way in your
3956 * language to say the date, with changes in what you say, depending
3957 * upon how recent the date is. XXX */
3961 time_t beg_today
, tt
;
3962 char todo
= format
[offset
]; /* The letter to format*/
3964 gettimeofday(&now
,NULL
);
3966 ast_localtime(&tt
,&tmnow
,timezone
);
3967 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3968 /* In any case, it saves not having to do ast_mktime() */
3969 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
3970 if (beg_today
< time
) {
3973 res
= wait_file(chan
,
3978 } else if (beg_today
- 86400 < time
) {
3980 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
3981 } else if ((todo
!= 'Q') &&
3982 (beg_today
- 86400 * 6 < time
))
3984 /* Within the last week */
3985 res
= ast_say_date_with_format_he(chan
,
3989 res
= ast_say_date_with_format_he(chan
,
3991 IL_DATE_STR
, timezone
);
3996 res
= ast_say_date_with_format_he(chan
, time
, ints
, lang
, "HM", timezone
);
3998 case 'S': /* Seconds */
3999 res
= ast_say_number_full_he(chan
, tm
.tm_sec
,
4000 ints
, lang
, "f", -1, -1
4004 res
= ast_say_date_with_format_he(chan
, time
, ints
, lang
, "HMS", timezone
);
4006 /* c, x, and X seem useful for testing. Not sure
4007 * if thiey're good for the general public */
4009 res
= ast_say_date_with_format_he(chan
, time
,
4010 ints
, lang
, IL_DATE_STR_FULL
, timezone
);
4013 res
= ast_say_date_with_format_he(chan
, time
,
4014 ints
, lang
, IL_DATE_STR
, timezone
);
4016 case 'X': /* Currently not locale-dependent...*/
4017 res
= ast_say_date_with_format_he(chan
, time
,
4018 ints
, lang
, IL_TIME_STR
, timezone
);
4022 /* Just ignore spaces and tabs */
4025 /* Unknown character */
4026 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
4028 /* Jump out on DTMF */
4037 /* Spanish syntax */
4038 int ast_say_date_with_format_es(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
4041 int res
=0, offset
, sndoffset
;
4042 char sndfile
[256], nextmsg
[256];
4045 format
= "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y 'digits/at' IMp";
4047 ast_localtime(&time
,&tm
,timezone
);
4049 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
4050 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
4051 switch (format
[offset
]) {
4052 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
4054 /* Literal name of a sound file */
4056 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
4057 sndfile
[sndoffset
] = format
[offset
];
4058 sndfile
[sndoffset
] = '\0';
4059 snprintf(nextmsg
,sizeof(nextmsg
), "%s", sndfile
);
4060 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4064 /* Sunday - Saturday */
4065 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
4066 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4071 /* January - December */
4072 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
4073 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4076 /* First - Twelfth */
4077 snprintf(nextmsg
,sizeof(nextmsg
), "digits/h-%d", tm
.tm_mon
+1);
4078 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4082 /* First - Thirtyfirst */
4083 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
4087 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
4092 if (tm
.tm_hour
== 0)
4093 snprintf(nextmsg
,sizeof(nextmsg
), "digits/12");
4094 else if (tm
.tm_hour
> 12)
4095 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- 12);
4097 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
4098 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4103 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, NULL
);
4107 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
4112 if (tm
.tm_hour
> 18)
4113 res
= wait_file(chan
, ints
, "digits/p-m", lang
);
4114 else if (tm
.tm_hour
> 12)
4115 res
= wait_file(chan
, ints
, "digits/afternoon", lang
);
4116 else if (tm
.tm_hour
)
4117 res
= wait_file(chan
, ints
, "digits/a-m", lang
);
4120 /* Shorthand for "Today", "Yesterday", or ABdY */
4121 /* XXX As emphasized elsewhere, this should the native way in your
4122 * language to say the date, with changes in what you say, depending
4123 * upon how recent the date is. XXX */
4127 time_t beg_today
, tt
;
4129 gettimeofday(&now
,NULL
);
4131 ast_localtime(&tt
,&tmnow
,timezone
);
4132 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
4133 /* In any case, it saves not having to do ast_mktime() */
4134 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
4135 if (beg_today
< time
) {
4137 res
= wait_file(chan
,ints
, "digits/today",lang
);
4138 } else if (beg_today
- 86400 < time
) {
4140 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
4142 res
= ast_say_date_with_format_es(chan
, time
, ints
, lang
, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone
);
4147 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
4148 /* XXX As emphasized elsewhere, this should the native way in your
4149 * language to say the date, with changes in what you say, depending
4150 * upon how recent the date is. XXX */
4154 time_t beg_today
, tt
;
4156 gettimeofday(&now
,NULL
);
4158 ast_localtime(&tt
,&tmnow
,timezone
);
4159 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
4160 /* In any case, it saves not having to do ast_mktime() */
4161 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
4162 if (beg_today
< time
) {
4164 res
= wait_file(chan
,ints
, "digits/today",lang
);
4165 } else if ((beg_today
- 86400) < time
) {
4167 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
4168 } else if (beg_today
- 86400 * 6 < time
) {
4169 /* Within the last week */
4170 res
= ast_say_date_with_format_es(chan
, time
, ints
, lang
, "A", timezone
);
4172 res
= ast_say_date_with_format_es(chan
, time
, ints
, lang
, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone
);
4177 res
= ast_say_date_with_format_es(chan
, time
, ints
, lang
, "H 'digits/y' M", timezone
);
4181 if (tm
.tm_sec
== 0) {
4182 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
4183 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4184 } else if (tm
.tm_sec
< 10) {
4185 res
= wait_file(chan
,ints
, "digits/oh",lang
);
4187 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
4188 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4190 } else if ((tm
.tm_sec
< 21) || (tm
.tm_sec
% 10 == 0)) {
4191 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
4192 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4195 ten
= (tm
.tm_sec
/ 10) * 10;
4196 one
= (tm
.tm_sec
% 10);
4197 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", ten
);
4198 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4200 /* Fifty, not fifty-zero */
4202 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", one
);
4203 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4209 res
= ast_say_date_with_format_es(chan
, time
, ints
, lang
, "HMS", timezone
);
4213 /* Just ignore spaces and tabs */
4216 /* Unknown character */
4217 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
4219 /* Jump out on DTMF */
4230 int ast_say_date_with_format_fr(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
4233 int res
=0, offset
, sndoffset
;
4234 char sndfile
[256], nextmsg
[256];
4237 format
= "AdBY 'digits/at' IMp";
4239 ast_localtime(&time
,&tm
,timezone
);
4241 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
4242 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
4243 switch (format
[offset
]) {
4244 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
4246 /* Literal name of a sound file */
4248 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
4249 sndfile
[sndoffset
] = format
[offset
];
4250 sndfile
[sndoffset
] = '\0';
4251 res
= wait_file(chan
,ints
,sndfile
,lang
);
4255 /* Sunday - Saturday */
4256 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
4257 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4262 /* January - December */
4263 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
4264 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4267 /* First - Twelfth */
4268 snprintf(nextmsg
,sizeof(nextmsg
), "digits/h-%d", tm
.tm_mon
+1);
4269 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4274 if (tm
.tm_mday
== 1) {
4275 snprintf(nextmsg
,sizeof(nextmsg
), "digits/h-%d", tm
.tm_mday
);
4276 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4278 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char * ) NULL
);
4283 if (tm
.tm_year
> 99) {
4284 res
= wait_file(chan
,ints
, "digits/2",lang
);
4286 res
= wait_file(chan
,ints
, "digits/thousand",lang
);
4288 if (tm
.tm_year
> 100) {
4290 res
= ast_say_number(chan
, tm
.tm_year
- 100, ints
, lang
, (char * ) NULL
);
4294 if (tm
.tm_year
< 1) {
4295 /* I'm not going to handle 1900 and prior */
4296 /* We'll just be silent on the year, instead of bombing out. */
4298 res
= wait_file(chan
,ints
, "digits/thousand",lang
);
4300 wait_file(chan
,ints
, "digits/9",lang
);
4301 wait_file(chan
,ints
, "digits/hundred",lang
);
4302 res
= ast_say_number(chan
, tm
.tm_year
, ints
, lang
, (char * ) NULL
);
4310 if (tm
.tm_hour
== 0)
4311 snprintf(nextmsg
,sizeof(nextmsg
), "digits/12");
4312 else if (tm
.tm_hour
> 12)
4313 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- 12);
4315 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
4316 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4318 res
= wait_file(chan
,ints
, "digits/oclock",lang
);
4323 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, (char * ) NULL
);
4325 res
= wait_file(chan
,ints
, "digits/oclock",lang
);
4329 if (tm
.tm_min
== 0) {
4332 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char * ) NULL
);
4337 if (tm
.tm_hour
> 11)
4338 snprintf(nextmsg
,sizeof(nextmsg
), "digits/p-m");
4340 snprintf(nextmsg
,sizeof(nextmsg
), "digits/a-m");
4341 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4344 /* Shorthand for "Today", "Yesterday", or AdBY */
4345 /* XXX As emphasized elsewhere, this should the native way in your
4346 * language to say the date, with changes in what you say, depending
4347 * upon how recent the date is. XXX */
4351 time_t beg_today
, tt
;
4353 gettimeofday(&now
,NULL
);
4355 ast_localtime(&tt
,&tmnow
,timezone
);
4356 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
4357 /* In any case, it saves not having to do ast_mktime() */
4358 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
4359 if (beg_today
< time
) {
4361 res
= wait_file(chan
,ints
, "digits/today",lang
);
4362 } else if (beg_today
- 86400 < time
) {
4364 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
4366 res
= ast_say_date_with_format_fr(chan
, time
, ints
, lang
, "AdBY", timezone
);
4371 /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */
4372 /* XXX As emphasized elsewhere, this should the native way in your
4373 * language to say the date, with changes in what you say, depending
4374 * upon how recent the date is. XXX */
4378 time_t beg_today
, tt
;
4380 gettimeofday(&now
,NULL
);
4382 ast_localtime(&tt
,&tmnow
,timezone
);
4383 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
4384 /* In any case, it saves not having to do ast_mktime() */
4385 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
4386 if (beg_today
< time
) {
4388 } else if ((beg_today
- 86400) < time
) {
4390 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
4391 } else if (beg_today
- 86400 * 6 < time
) {
4392 /* Within the last week */
4393 res
= ast_say_date_with_format_fr(chan
, time
, ints
, lang
, "A", timezone
);
4395 res
= ast_say_date_with_format_fr(chan
, time
, ints
, lang
, "AdBY", timezone
);
4400 res
= ast_say_date_with_format_fr(chan
, time
, ints
, lang
, "HM", timezone
);
4404 res
= ast_say_number(chan
, tm
.tm_sec
, ints
, lang
, (char * ) NULL
);
4406 res
= wait_file(chan
,ints
, "digits/second",lang
);
4410 res
= ast_say_date_with_format_fr(chan
, time
, ints
, lang
, "HMS", timezone
);
4414 /* Just ignore spaces and tabs */
4417 /* Unknown character */
4418 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
4420 /* Jump out on DTMF */
4428 int ast_say_date_with_format_it(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
4431 int res
=0, offset
, sndoffset
;
4432 char sndfile
[256], nextmsg
[256];
4435 format
= "AdB 'digits/at' IMp";
4437 ast_localtime(&time
,&tm
,timezone
);
4439 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
4440 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
4441 switch (format
[offset
]) {
4442 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
4444 /* Literal name of a sound file */
4446 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
4447 sndfile
[sndoffset
] = format
[offset
];
4448 sndfile
[sndoffset
] = '\0';
4449 res
= wait_file(chan
,ints
,sndfile
,lang
);
4453 /* Sunday - Saturday */
4454 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
4455 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4460 /* January - December */
4461 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
4462 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4465 /* First - Twelfth */
4466 snprintf(nextmsg
,sizeof(nextmsg
), "digits/h-%d", tm
.tm_mon
+1);
4467 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4471 /* First day of the month is spelled as ordinal */
4472 if (tm
.tm_mday
== 1) {
4473 snprintf(nextmsg
,sizeof(nextmsg
), "digits/h-%d", tm
.tm_mday
);
4474 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4477 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
4483 if (tm
.tm_year
> 99) {
4484 res
= wait_file(chan
,ints
, "digits/ore-2000",lang
);
4485 if (tm
.tm_year
> 100) {
4487 /* This works until the end of 2021 */
4488 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_year
- 100);
4489 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4493 if (tm
.tm_year
< 1) {
4494 /* I'm not going to handle 1900 and prior */
4495 /* We'll just be silent on the year, instead of bombing out. */
4497 res
= wait_file(chan
,ints
, "digits/ore-1900",lang
);
4498 if ((!res
) && (tm
.tm_year
!= 0)) {
4499 if (tm
.tm_year
<= 21) {
4501 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_year
);
4502 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4504 /* 1922 - 1999, but sounds badly in 1928, 1931, 1938, etc... */
4506 ten
= tm
.tm_year
/ 10;
4507 one
= tm
.tm_year
% 10;
4508 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", ten
* 10);
4509 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4512 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", one
);
4513 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4524 if (tm
.tm_hour
== 0)
4525 snprintf(nextmsg
,sizeof(nextmsg
), "digits/12");
4526 else if (tm
.tm_hour
> 12)
4527 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- 12);
4529 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
4530 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4535 if (tm
.tm_hour
== 0) {
4536 res
= wait_file(chan
,ints
, "digits/ore-mezzanotte",lang
);
4537 } else if (tm
.tm_hour
== 1) {
4538 res
= wait_file(chan
,ints
, "digits/ore-una",lang
);
4540 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, (char *) NULL
);
4545 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
4550 if (tm
.tm_hour
> 11)
4551 snprintf(nextmsg
,sizeof(nextmsg
), "digits/p-m");
4553 snprintf(nextmsg
,sizeof(nextmsg
), "digits/a-m");
4554 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4557 /* Shorthand for "Today", "Yesterday", or ABdY */
4558 /* XXX As emphasized elsewhere, this should the native way in your
4559 * language to say the date, with changes in what you say, depending
4560 * upon how recent the date is. XXX */
4564 time_t beg_today
, tt
;
4566 gettimeofday(&now
,NULL
);
4568 ast_localtime(&tt
,&tmnow
,timezone
);
4569 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
4570 /* In any case, it saves not having to do ast_mktime() */
4571 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
4572 if (beg_today
< time
) {
4574 res
= wait_file(chan
,ints
, "digits/today",lang
);
4575 } else if (beg_today
- 86400 < time
) {
4577 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
4579 res
= ast_say_date_with_format_it(chan
, time
, ints
, lang
, "AdB", timezone
);
4584 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
4588 time_t beg_today
, tt
;
4590 gettimeofday(&now
,NULL
);
4592 ast_localtime(&tt
,&tmnow
,timezone
);
4593 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
4594 /* In any case, it saves not having to do ast_mktime() */
4595 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
4596 if (beg_today
< time
) {
4598 } else if ((beg_today
- 86400) < time
) {
4600 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
4601 } else if (beg_today
- 86400 * 6 < time
) {
4602 /* Within the last week */
4603 res
= ast_say_date_with_format_it(chan
, time
, ints
, lang
, "A", timezone
);
4605 res
= ast_say_date_with_format_it(chan
, time
, ints
, lang
, "AdB", timezone
);
4610 res
= ast_say_date_with_format_it(chan
, time
, ints
, lang
, "HM", timezone
);
4614 if (tm
.tm_sec
== 0) {
4615 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
4616 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4617 } else if (tm
.tm_sec
< 10) {
4618 res
= wait_file(chan
,ints
, "digits/oh",lang
);
4620 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
4621 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4623 } else if ((tm
.tm_sec
< 21) || (tm
.tm_sec
% 10 == 0)) {
4624 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
4625 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4628 ten
= (tm
.tm_sec
/ 10) * 10;
4629 one
= (tm
.tm_sec
% 10);
4630 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", ten
);
4631 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4633 /* Fifty, not fifty-zero */
4635 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", one
);
4636 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4642 res
= ast_say_date_with_format_it(chan
, time
, ints
, lang
, "HMS", timezone
);
4646 /* Just ignore spaces and tabs */
4649 /* Unknown character */
4650 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
4652 /* Jump out on DTMF */
4661 int ast_say_date_with_format_nl(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
4664 int res
=0, offset
, sndoffset
;
4665 char sndfile
[256], nextmsg
[256];
4668 format
= "ABdY 'digits/at' IMp";
4670 ast_localtime(&time
,&tm
,timezone
);
4672 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
4673 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
4674 switch (format
[offset
]) {
4675 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
4677 /* Literal name of a sound file */
4679 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
4680 sndfile
[sndoffset
] = format
[offset
];
4681 sndfile
[sndoffset
] = '\0';
4682 res
= wait_file(chan
,ints
,sndfile
,lang
);
4686 /* Sunday - Saturday */
4687 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
4688 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4693 /* January - December */
4694 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
4695 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4698 /* First - Twelfth */
4699 snprintf(nextmsg
,sizeof(nextmsg
), "digits/h-%d", tm
.tm_mon
+1);
4700 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4704 /* First - Thirtyfirst */
4705 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, NULL
);
4709 if (tm
.tm_year
> 99) {
4710 res
= wait_file(chan
,ints
, "digits/2",lang
);
4712 res
= wait_file(chan
,ints
, "digits/thousand",lang
);
4714 if (tm
.tm_year
> 100) {
4716 /* This works until the end of 2020 */
4717 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_year
- 100);
4718 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4722 if (tm
.tm_year
< 1) {
4723 /* I'm not going to handle 1900 and prior */
4724 /* We'll just be silent on the year, instead of bombing out. */
4726 res
= wait_file(chan
,ints
, "digits/19",lang
);
4728 if (tm
.tm_year
<= 9) {
4730 res
= wait_file(chan
,ints
, "digits/oh",lang
);
4732 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_year
);
4733 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4735 } else if (tm
.tm_year
<= 20) {
4737 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_year
);
4738 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4742 ten
= tm
.tm_year
/ 10;
4743 one
= tm
.tm_year
% 10;
4744 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", ten
* 10);
4745 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4748 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", one
);
4749 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4760 if (tm
.tm_hour
== 0)
4761 snprintf(nextmsg
,sizeof(nextmsg
), "digits/12");
4762 else if (tm
.tm_hour
> 12)
4763 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- 12);
4765 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
4766 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4771 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, (char *) NULL
);
4773 res
= wait_file(chan
,ints
, "digits/nl-uur",lang
);
4778 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
4783 if (tm
.tm_hour
> 11)
4784 snprintf(nextmsg
,sizeof(nextmsg
), "digits/p-m");
4786 snprintf(nextmsg
,sizeof(nextmsg
), "digits/a-m");
4787 res
= wait_file(chan
,ints
,nextmsg
,lang
);
4790 /* Shorthand for "Today", "Yesterday", or ABdY */
4791 /* XXX As emphasized elsewhere, this should the native way in your
4792 * language to say the date, with changes in what you say, depending
4793 * upon how recent the date is. XXX */
4797 time_t beg_today
, tt
;
4799 gettimeofday(&now
,NULL
);
4801 ast_localtime(&tt
,&tmnow
,timezone
);
4802 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
4803 /* In any case, it saves not having to do ast_mktime() */
4804 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
4805 if (beg_today
< time
) {
4807 res
= wait_file(chan
,ints
, "digits/today",lang
);
4808 } else if (beg_today
- 86400 < time
) {
4810 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
4812 res
= ast_say_date_with_format_nl(chan
, time
, ints
, lang
, "ABdY", timezone
);
4817 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
4821 time_t beg_today
, tt
;
4823 gettimeofday(&now
,NULL
);
4825 ast_localtime(&tt
,&tmnow
,timezone
);
4826 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
4827 /* In any case, it saves not having to do ast_mktime() */
4828 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
4829 if (beg_today
< time
) {
4831 } else if ((beg_today
- 86400) < time
) {
4833 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
4834 } else if (beg_today
- 86400 * 6 < time
) {
4835 /* Within the last week */
4836 res
= ast_say_date_with_format_nl(chan
, time
, ints
, lang
, "A", timezone
);
4838 res
= ast_say_date_with_format_nl(chan
, time
, ints
, lang
, "ABdY", timezone
);
4843 res
= ast_say_date_with_format_nl(chan
, time
, ints
, lang
, "HM", timezone
);
4847 res
= ast_say_number(chan
, tm
.tm_sec
, ints
, lang
, (char *) NULL
);
4850 res
= ast_say_date_with_format_nl(chan
, time
, ints
, lang
, "HMS", timezone
);
4854 /* Just ignore spaces and tabs */
4857 /* Unknown character */
4858 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
4860 /* Jump out on DTMF */
4869 int ast_say_date_with_format_pl(struct ast_channel
*chan
, time_t thetime
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
4872 int res
=0, offset
, sndoffset
;
4873 char sndfile
[256], nextmsg
[256];
4875 ast_localtime(&thetime
, &tm
, timezone
);
4877 for (offset
= 0 ; format
[offset
] != '\0' ; offset
++) {
4879 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
4880 switch (format
[offset
]) {
4881 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
4883 /* Literal name of a sound file */
4885 for (sndoffset
= 0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
4886 sndfile
[sndoffset
] = format
[offset
];
4887 sndfile
[sndoffset
] = '\0';
4888 res
= wait_file(chan
, ints
, sndfile
, lang
);
4892 /* Sunday - Saturday */
4893 snprintf(nextmsg
, sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
4894 res
= wait_file(chan
, ints
, nextmsg
, lang
);
4899 /* January - December */
4900 snprintf(nextmsg
, sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
4901 res
= wait_file(chan
, ints
, nextmsg
, lang
);
4904 /* Month enumerated */
4905 res
= ast_say_enumeration(chan
, (tm
.tm_mon
+ 1), ints
, lang
, NULL
);
4909 /* First - Thirtyfirst */
4910 remainder
= tm
.tm_mday
;
4911 if (tm
.tm_mday
> 30) {
4912 res
= wait_file(chan
, ints
, "digits/h-30", lang
);
4915 if (tm
.tm_mday
> 20 && tm
.tm_mday
< 30) {
4916 res
= wait_file(chan
, ints
, "digits/h-20", lang
);
4920 snprintf(nextmsg
, sizeof(nextmsg
), "digits/h-%d", remainder
);
4921 res
= wait_file(chan
, ints
, nextmsg
, lang
);
4926 if (tm
.tm_year
> 100) {
4927 res
= wait_file(chan
, ints
, "digits/2", lang
);
4929 res
= wait_file(chan
, ints
, "digits/1000.2",lang
);
4930 if (tm
.tm_year
> 100) {
4932 res
= ast_say_enumeration(chan
, tm
.tm_year
- 100, ints
, lang
, NULL
);
4934 } else if (tm
.tm_year
== 100) {
4935 res
= wait_file(chan
, ints
, "digits/h-2000", lang
);
4937 if (tm
.tm_year
< 1) {
4938 /* I'm not going to handle 1900 and prior */
4939 /* We'll just be silent on the year, instead of bombing out. */
4942 res
= wait_file(chan
, ints
, "digits/1000", lang
);
4944 wait_file(chan
, ints
, "digits/900", lang
);
4945 res
= ast_say_enumeration(chan
, tm
.tm_year
, ints
, lang
, NULL
);
4950 wait_file(chan
, ints
, "digits/year", lang
);
4955 if (tm
.tm_hour
== 0)
4956 snprintf(nextmsg
, sizeof(nextmsg
), "digits/t-12");
4957 else if (tm
.tm_hour
> 12)
4958 snprintf(nextmsg
, sizeof(nextmsg
), "digits/t-%d", tm
.tm_hour
- 12);
4960 snprintf(nextmsg
, sizeof(nextmsg
), "digits/t-%d", tm
.tm_hour
);
4962 res
= wait_file(chan
, ints
, nextmsg
, lang
);
4967 if (tm
.tm_hour
!= 0) {
4968 snprintf(nextmsg
, sizeof(nextmsg
), "digits/t-%d", tm
.tm_hour
);
4969 res
= wait_file(chan
, ints
, nextmsg
, lang
);
4971 res
= wait_file(chan
, ints
, "digits/t-24", lang
);
4976 if (tm
.tm_min
== 0) {
4977 if (format
[offset
] == 'M') {
4978 res
= wait_file(chan
, ints
, "digits/oclock", lang
);
4980 res
= wait_file(chan
, ints
, "digits/100", lang
);
4983 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, "f");
4988 if (tm
.tm_hour
> 11)
4989 snprintf(nextmsg
, sizeof(nextmsg
), "digits/p-m");
4991 snprintf(nextmsg
, sizeof(nextmsg
), "digits/a-m");
4992 res
= wait_file(chan
, ints
, nextmsg
, lang
);
4995 /* Shorthand for "Today", "Yesterday", or AdBY */
4997 time_t tv_sec
= time(NULL
);
5001 ast_localtime(&tv_sec
,&tmnow
, timezone
);
5002 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
5003 /* In any case, it saves not having to do ast_mktime() */
5004 beg_today
= tv_sec
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
5005 if (beg_today
< thetime
) {
5007 res
= wait_file(chan
, ints
, "digits/today", lang
);
5008 } else if (beg_today
- 86400 < thetime
) {
5010 res
= wait_file(chan
, ints
, "digits/yesterday", lang
);
5012 res
= ast_say_date_with_format(chan
, thetime
, ints
, lang
, "AdBY", timezone
);
5017 /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */
5019 time_t tv_sec
= time(NULL
);
5023 ast_localtime(&tv_sec
, &tmnow
, timezone
);
5024 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
5025 /* In any case, it saves not having to do ast_mktime() */
5026 beg_today
= tv_sec
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
5027 if (beg_today
< thetime
) {
5029 } else if ((beg_today
- 86400) < thetime
) {
5031 res
= wait_file(chan
, ints
, "digits/yesterday", lang
);
5032 } else if (beg_today
- 86400 * 6 < thetime
) {
5033 /* Within the last week */
5034 res
= ast_say_date_with_format(chan
, thetime
, ints
, lang
, "A", timezone
);
5036 res
= ast_say_date_with_format(chan
, thetime
, ints
, lang
, "AdBY", timezone
);
5041 res
= ast_say_date_with_format(chan
, thetime
, ints
, lang
, "HM", timezone
);
5045 res
= wait_file(chan
, ints
, "digits/and", lang
);
5047 if (tm
.tm_sec
== 1) {
5048 res
= wait_file(chan
, ints
, "digits/1z", lang
);
5050 res
= wait_file(chan
, ints
, "digits/second-a", lang
);
5052 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, "f");
5055 ten
= tm
.tm_sec
/ 10;
5056 one
= tm
.tm_sec
% 10;
5058 if (one
> 1 && one
< 5 && ten
!= 1)
5059 res
= wait_file(chan
,ints
, "digits/seconds",lang
);
5061 res
= wait_file(chan
,ints
, "digits/second",lang
);
5067 res
= ast_say_date_with_format(chan
, thetime
, ints
, lang
, "HMS", timezone
);
5071 /* Just ignore spaces and tabs */
5074 /* Unknown character */
5075 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
5077 /* Jump out on DTMF */
5084 /* Portuguese syntax */
5085 int ast_say_date_with_format_pt(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
5088 int res
=0, offset
, sndoffset
;
5089 char sndfile
[256], nextmsg
[256];
5092 format
= "Ad 'digits/pt-de' B 'digits/pt-de' Y I 'digits/pt-e' Mp";
5094 ast_localtime(&time
,&tm
,timezone
);
5096 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
5097 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
5098 switch (format
[offset
]) {
5099 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
5101 /* Literal name of a sound file */
5103 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
5104 sndfile
[sndoffset
] = format
[offset
];
5105 sndfile
[sndoffset
] = '\0';
5106 snprintf(nextmsg
,sizeof(nextmsg
), "%s", sndfile
);
5107 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5111 /* Sunday - Saturday */
5112 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
5113 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5118 /* January - December */
5119 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
5120 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5123 /* First - Twelfth */
5124 if (!strcasecmp(lang
, "pt_BR")) {
5125 res
= ast_say_number(chan
, tm
.tm_mon
+1, ints
, lang
, (char *) NULL
);
5127 snprintf(nextmsg
,sizeof(nextmsg
), "digits/h-%d", tm
.tm_mon
+1);
5128 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5133 /* First - Thirtyfirst */
5134 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
5138 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
5143 if (!strcasecmp(lang
, "pt_BR")) {
5144 if (tm
.tm_hour
== 0) {
5145 if (format
[offset
] == 'I')
5146 res
= wait_file(chan
, ints
, "digits/pt-a", lang
);
5148 res
= wait_file(chan
, ints
, "digits/pt-meianoite", lang
);
5149 } else if (tm
.tm_hour
== 12) {
5150 if (format
[offset
] == 'I')
5151 res
= wait_file(chan
, ints
, "digits/pt-ao", lang
);
5153 res
= wait_file(chan
, ints
, "digits/pt-meiodia", lang
);
5155 if (format
[offset
] == 'I') {
5156 if ((tm
.tm_hour
% 12) != 1)
5157 res
= wait_file(chan
, ints
, "digits/pt-as", lang
);
5159 res
= wait_file(chan
, ints
, "digits/pt-a", lang
);
5162 res
= ast_say_number(chan
, (tm
.tm_hour
% 12), ints
, lang
, "f");
5165 if (tm
.tm_hour
== 0) {
5166 if (format
[offset
] == 'I')
5167 res
= wait_file(chan
, ints
, "digits/pt-ah", lang
);
5169 res
= wait_file(chan
, ints
, "digits/pt-meianoite", lang
);
5171 else if (tm
.tm_hour
== 12) {
5172 if (format
[offset
] == 'I')
5173 res
= wait_file(chan
, ints
, "digits/pt-ao", lang
);
5175 res
= wait_file(chan
, ints
, "digits/pt-meiodia", lang
);
5178 if (format
[offset
] == 'I') {
5179 res
= wait_file(chan
, ints
, "digits/pt-ah", lang
);
5180 if ((tm
.tm_hour
% 12) != 1)
5182 res
= wait_file(chan
, ints
, "digits/pt-sss", lang
);
5185 res
= ast_say_number(chan
, (tm
.tm_hour
% 12), ints
, lang
, "f");
5192 if (!strcasecmp(lang
, "pt_BR")) {
5193 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, "f");
5194 if ((!res
) && (format
[offset
] == 'H')) {
5195 if (tm
.tm_hour
> 1) {
5196 res
= wait_file(chan
,ints
,"digits/hours",lang
);
5198 res
= wait_file(chan
,ints
,"digits/hour",lang
);
5202 res
= ast_say_number(chan
, -tm
.tm_hour
, ints
, lang
, NULL
);
5204 if (tm
.tm_hour
!= 0) {
5205 int remainder
= tm
.tm_hour
;
5206 if (tm
.tm_hour
> 20) {
5207 res
= wait_file(chan
,ints
, "digits/20",lang
);
5211 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", remainder
);
5212 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5220 if (!strcasecmp(lang
, "pt_BR")) {
5221 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, NULL
);
5223 if (tm
.tm_min
> 1) {
5224 res
= wait_file(chan
,ints
,"digits/minutes",lang
);
5226 res
= wait_file(chan
,ints
,"digits/minute",lang
);
5230 if (tm
.tm_min
== 0) {
5231 res
= wait_file(chan
, ints
, "digits/pt-hora", lang
);
5232 if (tm
.tm_hour
!= 1)
5234 res
= wait_file(chan
, ints
, "digits/pt-sss", lang
);
5236 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5243 if (!strcasecmp(lang
, "pt_BR")) {
5244 if ((tm
.tm_hour
!= 0) && (tm
.tm_hour
!= 12)) {
5245 res
= wait_file(chan
, ints
, "digits/pt-da", lang
);
5247 if ((tm
.tm_hour
>= 0) && (tm
.tm_hour
< 12))
5248 res
= wait_file(chan
, ints
, "digits/morning", lang
);
5249 else if ((tm
.tm_hour
>= 12) && (tm
.tm_hour
< 18))
5250 res
= wait_file(chan
, ints
, "digits/afternoon", lang
);
5251 else res
= wait_file(chan
, ints
, "digits/night", lang
);
5255 if (tm
.tm_hour
> 12)
5256 res
= wait_file(chan
, ints
, "digits/p-m", lang
);
5257 else if (tm
.tm_hour
&& tm
.tm_hour
< 12)
5258 res
= wait_file(chan
, ints
, "digits/a-m", lang
);
5262 /* Shorthand for "Today", "Yesterday", or ABdY */
5263 /* XXX As emphasized elsewhere, this should the native way in your
5264 * language to say the date, with changes in what you say, depending
5265 * upon how recent the date is. XXX */
5269 time_t beg_today
, tt
;
5271 gettimeofday(&now
,NULL
);
5273 ast_localtime(&tt
,&tmnow
,timezone
);
5274 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
5275 /* In any case, it saves not having to do ast_mktime() */
5276 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
5277 if (beg_today
< time
) {
5279 res
= wait_file(chan
,ints
, "digits/today",lang
);
5280 } else if (beg_today
- 86400 < time
) {
5282 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
5284 res
= ast_say_date_with_format_pt(chan
, time
, ints
, lang
, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone
);
5289 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
5290 /* XXX As emphasized elsewhere, this should the native way in your
5291 * language to say the date, with changes in what you say, depending
5292 * upon how recent the date is. XXX */
5296 time_t beg_today
, tt
;
5298 gettimeofday(&now
,NULL
);
5300 ast_localtime(&tt
,&tmnow
,timezone
);
5301 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
5302 /* In any case, it saves not having to do ast_mktime() */
5303 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
5304 if (beg_today
< time
) {
5306 } else if ((beg_today
- 86400) < time
) {
5308 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
5309 } else if (beg_today
- 86400 * 6 < time
) {
5310 /* Within the last week */
5311 res
= ast_say_date_with_format_pt(chan
, time
, ints
, lang
, "A", timezone
);
5313 res
= ast_say_date_with_format_pt(chan
, time
, ints
, lang
, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone
);
5318 res
= ast_say_date_with_format_pt(chan
, time
, ints
, lang
, "H 'digits/pt-e' M", timezone
);
5322 if (!strcasecmp(lang
, "pt_BR")) {
5323 res
= ast_say_number(chan
, tm
.tm_sec
, ints
, lang
, NULL
);
5325 if (tm
.tm_sec
> 1) {
5326 res
= wait_file(chan
,ints
,"digits/seconds",lang
);
5328 res
= wait_file(chan
,ints
,"digits/second",lang
);
5330 } else if (tm
.tm_sec
< 10) {
5331 res
= wait_file(chan
,ints
, "digits/oh",lang
);
5333 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
5334 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5336 } else if ((tm
.tm_sec
< 21) || (tm
.tm_sec
% 10 == 0)) {
5337 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
5338 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5341 ten
= (tm
.tm_sec
/ 10) * 10;
5342 one
= (tm
.tm_sec
% 10);
5343 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", ten
);
5344 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5346 /* Fifty, not fifty-zero */
5348 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", one
);
5349 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5356 res
= ast_say_date_with_format_pt(chan
, time
, ints
, lang
, "HMS", timezone
);
5360 /* Just ignore spaces and tabs */
5363 /* Unknown character */
5364 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
5366 /* Jump out on DTMF */
5374 /* Taiwanese / Chinese syntax */
5375 int ast_say_date_with_format_tw(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
5378 int res
=0, offset
, sndoffset
;
5379 char sndfile
[256], nextmsg
[256];
5384 ast_localtime(&time
,&tm
,timezone
);
5386 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
5387 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
5388 switch (format
[offset
]) {
5389 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
5391 /* Literal name of a sound file */
5393 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
5394 sndfile
[sndoffset
] = format
[offset
];
5395 sndfile
[sndoffset
] = '\0';
5396 res
= wait_file(chan
,ints
,sndfile
,lang
);
5400 /* Sunday - Saturday */
5401 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
5402 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5408 /* January - December */
5409 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
5410 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5414 /* First - Thirtyfirst */
5415 if (!(tm
.tm_mday
% 10) || (tm
.tm_mday
< 10)) {
5416 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_mday
);
5417 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5419 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_mday
- (tm
.tm_mday
% 10));
5420 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5422 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_mday
% 10);
5423 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5426 if (!res
) res
= wait_file(chan
,ints
,"digits/day",lang
);
5430 if (tm
.tm_year
> 99) {
5431 res
= wait_file(chan
,ints
, "digits/2",lang
);
5433 res
= wait_file(chan
,ints
, "digits/thousand",lang
);
5435 if (tm
.tm_year
> 100) {
5437 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", (tm
.tm_year
- 100) / 10);
5438 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5440 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", (tm
.tm_year
- 100) % 10);
5441 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5446 res
= wait_file(chan
,ints
, "digits/year",lang
);
5449 if (tm
.tm_year
< 1) {
5450 /* I'm not going to handle 1900 and prior */
5451 /* We'll just be silent on the year, instead of bombing out. */
5453 res
= wait_file(chan
,ints
, "digits/1",lang
);
5455 res
= wait_file(chan
,ints
, "digits/9",lang
);
5458 if (tm
.tm_year
<= 9) {
5460 res
= wait_file(chan
,ints
, "digits/0",lang
);
5462 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_year
);
5463 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5467 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_year
/ 10);
5468 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5470 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_year
% 10);
5471 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5477 res
= wait_file(chan
,ints
, "digits/year",lang
);
5484 if (tm
.tm_hour
== 0)
5485 snprintf(nextmsg
,sizeof(nextmsg
), "digits/12");
5486 else if (tm
.tm_hour
> 12)
5487 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- 12);
5489 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
5490 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5492 res
= wait_file(chan
,ints
, "digits/oclock",lang
);
5496 if (tm
.tm_hour
< 10) {
5497 res
= wait_file(chan
, ints
, "digits/0", lang
);
5501 if (!(tm
.tm_hour
% 10) || tm
.tm_hour
< 10) {
5502 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
);
5503 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5505 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
- (tm
.tm_hour
% 10));
5506 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5508 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_hour
% 10);
5509 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5513 res
= wait_file(chan
,ints
, "digits/oclock",lang
);
5518 if (!(tm
.tm_min
% 10) || tm
.tm_min
< 10) {
5519 if (tm
.tm_min
< 10) {
5520 res
= wait_file(chan
, ints
, "digits/0", lang
);
5522 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_min
);
5523 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5525 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_min
- (tm
.tm_min
% 10));
5526 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5528 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_min
% 10);
5529 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5533 res
= wait_file(chan
,ints
, "digits/minute",lang
);
5539 if (tm
.tm_hour
> 11)
5540 snprintf(nextmsg
,sizeof(nextmsg
), "digits/p-m");
5542 snprintf(nextmsg
,sizeof(nextmsg
), "digits/a-m");
5543 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5546 /* Shorthand for "Today", "Yesterday", or ABdY */
5547 /* XXX As emphasized elsewhere, this should the native way in your
5548 * language to say the date, with changes in what you say, depending
5549 * upon how recent the date is. XXX */
5553 time_t beg_today
, tt
;
5555 gettimeofday(&now
,NULL
);
5557 ast_localtime(&tt
,&tmnow
,timezone
);
5558 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
5559 /* In any case, it saves not having to do ast_mktime() */
5560 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
5561 if (beg_today
< time
) {
5563 res
= wait_file(chan
,ints
, "digits/today",lang
);
5564 } else if (beg_today
- 86400 < time
) {
5566 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
5568 res
= ast_say_date_with_format_tw(chan
, time
, ints
, lang
, "YBdA", timezone
);
5573 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
5574 /* XXX As emphasized elsewhere, this should the native way in your
5575 * language to say the date, with changes in what you say, depending
5576 * upon how recent the date is. XXX */
5580 time_t beg_today
, tt
;
5582 gettimeofday(&now
,NULL
);
5584 ast_localtime(&tt
,&tmnow
,timezone
);
5585 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
5586 /* In any case, it saves not having to do ast_mktime() */
5587 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
5588 if (beg_today
< time
) {
5590 } else if ((beg_today
- 86400) < time
) {
5592 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
5593 } else if (beg_today
- 86400 * 6 < time
) {
5594 /* Within the last week */
5595 res
= ast_say_date_with_format_tw(chan
, time
, ints
, lang
, "A", timezone
);
5597 res
= ast_say_date_with_format_tw(chan
, time
, ints
, lang
, "YBdA", timezone
);
5602 res
= ast_say_date_with_format_tw(chan
, time
, ints
, lang
, "kM", timezone
);
5606 if (!(tm
.tm_sec
% 10) || tm
.tm_sec
< 10) {
5607 if (tm
.tm_sec
< 10) {
5608 res
= wait_file(chan
, ints
, "digits/0", lang
);
5610 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
);
5611 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5613 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
- (tm
.tm_sec
% 10));
5614 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5616 snprintf(nextmsg
,sizeof(nextmsg
), "digits/%d", tm
.tm_sec
% 10);
5617 res
= wait_file(chan
,ints
,nextmsg
,lang
);
5621 res
= wait_file(chan
,ints
, "digits/second",lang
);
5625 res
= ast_say_date_with_format_tw(chan
, time
, ints
, lang
, "HMS", timezone
);
5629 /* Just ignore spaces and tabs */
5632 /* Unknown character */
5633 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
5635 /* Jump out on DTMF */
5643 static int say_time(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5645 if (!strcasecmp(lang
, "en") ) { /* English syntax */
5646 return(ast_say_time_en(chan
, t
, ints
, lang
));
5647 } else if (!strcasecmp(lang
, "de") ) { /* German syntax */
5648 return(ast_say_time_de(chan
, t
, ints
, lang
));
5649 } else if (!strcasecmp(lang
, "fr") ) { /* French syntax */
5650 return(ast_say_time_fr(chan
, t
, ints
, lang
));
5651 } else if (!strcasecmp(lang
, "nl") ) { /* Dutch syntax */
5652 return(ast_say_time_nl(chan
, t
, ints
, lang
));
5653 } else if (!strcasecmp(lang
, "pt") ) { /* Portuguese syntax */
5654 return(ast_say_time_pt(chan
, t
, ints
, lang
));
5655 } else if (!strcasecmp(lang
, "pt_BR") ) { /* Brazilian Portuguese syntax */
5656 return(ast_say_time_pt_BR(chan
, t
, ints
, lang
));
5657 } else if (!strcasecmp(lang
, "tw") || !strcasecmp(lang
, "zh") ) { /* Taiwanese / Chinese syntax */
5658 return(ast_say_time_tw(chan
, t
, ints
, lang
));
5659 } else if (!strcasecmp(lang
, "gr") ) { /* Greek syntax */
5660 return(ast_say_time_gr(chan
, t
, ints
, lang
));
5661 } else if (!strcasecmp(lang
, "ge") ) { /* Georgian syntax */
5662 return(ast_say_time_ge(chan
, t
, ints
, lang
));
5663 } else if (!strcasecmp(lang
, "he")) { /* Hebrew syntax */
5664 return (ast_say_time_he(chan
, t
, ints
, lang
));
5667 /* Default to English */
5668 return(ast_say_time_en(chan
, t
, ints
, lang
));
5671 /* English syntax */
5672 int ast_say_time_en(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5678 ast_localtime(&t
, &tm
, NULL
);
5682 else if (hour
== 12)
5684 else if (hour
> 12) {
5689 res
= ast_say_number(chan
, hour
, ints
, lang
, (char *) NULL
);
5691 if (tm
.tm_min
> 9) {
5693 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5694 } else if (tm
.tm_min
) {
5696 res
= ast_streamfile(chan
, "digits/oh", lang
);
5698 res
= ast_waitstream(chan
, ints
);
5700 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5703 res
= ast_streamfile(chan
, "digits/oclock", lang
);
5705 res
= ast_waitstream(chan
, ints
);
5709 res
= ast_streamfile(chan
, "digits/p-m", lang
);
5712 res
= ast_streamfile(chan
, "digits/a-m", lang
);
5715 res
= ast_waitstream(chan
, ints
);
5720 int ast_say_time_de(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5725 ast_localtime(&t
, &tm
, NULL
);
5727 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, "n");
5729 res
= ast_streamfile(chan
, "digits/oclock", lang
);
5731 res
= ast_waitstream(chan
, ints
);
5734 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, "f");
5739 int ast_say_time_fr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5744 ast_localtime(&t
, &tm
, NULL
);
5746 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, "f");
5748 res
= ast_streamfile(chan
, "digits/oclock", lang
);
5751 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5757 int ast_say_time_nl(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5762 ast_localtime(&t
, &tm
, NULL
);
5764 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, (char *) NULL
);
5766 res
= ast_streamfile(chan
, "digits/nl-uur", lang
);
5768 res
= ast_waitstream(chan
, ints
);
5771 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, NULL
);
5775 /* Portuguese syntax */
5776 int ast_say_time_pt(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5782 ast_localtime(&t
, &tm
, NULL
);
5785 res
= ast_say_number(chan
, hour
, ints
, lang
, "f");
5788 res
= wait_file(chan
, ints
, "digits/pt-e", lang
);
5790 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5793 res
= wait_file(chan
, ints
, "digits/pt-hora", lang
);
5794 if (tm
.tm_hour
!= 1)
5796 res
= wait_file(chan
, ints
, "digits/pt-sss", lang
);
5799 res
= ast_say_number(chan
, hour
, ints
, lang
, (char *) NULL
);
5803 /* Brazilian Portuguese syntax */
5804 int ast_say_time_pt_BR(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5809 ast_localtime(&t
, &tm
, NULL
);
5811 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, "f");
5814 res
= wait_file(chan
, ints
, "digits/hours", lang
);
5816 res
= wait_file(chan
, ints
, "digits/hour", lang
);
5818 if ((!res
) && (tm
.tm_min
)) {
5819 res
= wait_file(chan
, ints
, "digits/pt-e", lang
);
5821 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5824 res
= wait_file(chan
, ints
, "digits/minutes", lang
);
5826 res
= wait_file(chan
, ints
, "digits/minute", lang
);
5832 /* Taiwanese / Chinese syntax */
5833 int ast_say_time_tw(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5839 ast_localtime(&t
, &tm
, NULL
);
5843 else if (hour
== 12)
5845 else if (hour
> 12) {
5851 res
= ast_streamfile(chan
, "digits/p-m", lang
);
5854 res
= ast_streamfile(chan
, "digits/a-m", lang
);
5857 res
= ast_waitstream(chan
, ints
);
5859 res
= ast_say_number(chan
, hour
, ints
, lang
, (char *) NULL
);
5861 res
= ast_streamfile(chan
, "digits/oclock", lang
);
5863 res
= ast_waitstream(chan
, ints
);
5865 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5867 res
= ast_streamfile(chan
, "digits/minute", lang
);
5869 res
= ast_waitstream(chan
, ints
);
5874 int ast_say_time_he(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5880 ast_localtime(&t
, &tm
, NULL
);
5886 res
= ast_say_number_full_he(chan
, hour
, ints
, lang
, "f", -1, -1);
5888 if (tm
.tm_min
> 9) {
5890 res
= ast_say_number_full_he(chan
, tm
.tm_min
, ints
, lang
, "f", -1, -1);
5891 } else if (tm
.tm_min
) {
5892 if (!res
) { /* say a leading zero if needed */
5893 res
= ast_say_number_full_he(chan
, 0, ints
, lang
, "f", -1, -1);
5896 res
= ast_waitstream(chan
, ints
);
5898 res
= ast_say_number_full_he(chan
, tm
.tm_min
, ints
, lang
, "f", -1, -1);
5901 res
= ast_waitstream(chan
, ints
);
5904 res
= ast_waitstream(chan
, ints
);
5907 static int say_datetime(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5909 if (!strcasecmp(lang
, "en") ) { /* English syntax */
5910 return(ast_say_datetime_en(chan
, t
, ints
, lang
));
5911 } else if (!strcasecmp(lang
, "de") ) { /* German syntax */
5912 return(ast_say_datetime_de(chan
, t
, ints
, lang
));
5913 } else if (!strcasecmp(lang
, "fr") ) { /* French syntax */
5914 return(ast_say_datetime_fr(chan
, t
, ints
, lang
));
5915 } else if (!strcasecmp(lang
, "nl") ) { /* Dutch syntax */
5916 return(ast_say_datetime_nl(chan
, t
, ints
, lang
));
5917 } else if (!strcasecmp(lang
, "pt") ) { /* Portuguese syntax */
5918 return(ast_say_datetime_pt(chan
, t
, ints
, lang
));
5919 } else if (!strcasecmp(lang
, "pt_BR") ) { /* Brazilian Portuguese syntax */
5920 return(ast_say_datetime_pt_BR(chan
, t
, ints
, lang
));
5921 } else if (!strcasecmp(lang
, "tw") || !strcasecmp(lang
, "zh") ) { /* Taiwanese / Chinese syntax */
5922 return(ast_say_datetime_tw(chan
, t
, ints
, lang
));
5923 } else if (!strcasecmp(lang
, "gr") ) { /* Greek syntax */
5924 return(ast_say_datetime_gr(chan
, t
, ints
, lang
));
5925 } else if (!strcasecmp(lang
, "ge") ) { /* Georgian syntax */
5926 return(ast_say_datetime_ge(chan
, t
, ints
, lang
));
5927 } else if (!strcasecmp(lang
, "he")) { /* Hebrew syntax */
5928 return (ast_say_datetime_he(chan
, t
, ints
, lang
));
5931 /* Default to English */
5932 return(ast_say_datetime_en(chan
, t
, ints
, lang
));
5935 /* English syntax */
5936 int ast_say_datetime_en(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
5943 ast_localtime(&t
, &tm
, NULL
);
5945 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
5946 res
= ast_streamfile(chan
, fn
, lang
);
5948 res
= ast_waitstream(chan
, ints
);
5951 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
5952 res
= ast_streamfile(chan
, fn
, lang
);
5954 res
= ast_waitstream(chan
, ints
);
5957 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
5962 else if (hour
== 12)
5964 else if (hour
> 12) {
5969 res
= ast_say_number(chan
, hour
, ints
, lang
, (char *) NULL
);
5971 if (tm
.tm_min
> 9) {
5973 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5974 } else if (tm
.tm_min
) {
5976 res
= ast_streamfile(chan
, "digits/oh", lang
);
5978 res
= ast_waitstream(chan
, ints
);
5980 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
5983 res
= ast_streamfile(chan
, "digits/oclock", lang
);
5985 res
= ast_waitstream(chan
, ints
);
5989 res
= ast_streamfile(chan
, "digits/p-m", lang
);
5992 res
= ast_streamfile(chan
, "digits/a-m", lang
);
5995 res
= ast_waitstream(chan
, ints
);
5997 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
6002 int ast_say_datetime_de(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6007 ast_localtime(&t
, &tm
, NULL
);
6008 res
= ast_say_date(chan
, t
, ints
, lang
);
6010 ast_say_time(chan
, t
, ints
, lang
);
6016 int ast_say_datetime_fr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6022 ast_localtime(&t
, &tm
, NULL
);
6025 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
6028 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6029 res
= ast_streamfile(chan
, fn
, lang
);
6031 res
= ast_waitstream(chan
, ints
);
6034 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6035 res
= ast_streamfile(chan
, fn
, lang
);
6037 res
= ast_waitstream(chan
, ints
);
6041 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, "f");
6043 res
= ast_streamfile(chan
, "digits/oclock", lang
);
6044 if (tm
.tm_min
> 0) {
6046 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
6049 res
= ast_waitstream(chan
, ints
);
6051 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
6056 int ast_say_datetime_nl(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6061 ast_localtime(&t
, &tm
, NULL
);
6062 res
= ast_say_date(chan
, t
, ints
, lang
);
6064 res
= ast_streamfile(chan
, "digits/nl-om", lang
);
6066 res
= ast_waitstream(chan
, ints
);
6069 ast_say_time(chan
, t
, ints
, lang
);
6073 /* Portuguese syntax */
6074 int ast_say_datetime_pt(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6081 ast_localtime(&t
, &tm
, NULL
);
6083 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6084 res
= ast_streamfile(chan
, fn
, lang
);
6086 res
= ast_waitstream(chan
, ints
);
6089 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6090 res
= ast_streamfile(chan
, fn
, lang
);
6092 res
= ast_waitstream(chan
, ints
);
6095 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
6100 else if (hour
== 12)
6102 else if (hour
> 12) {
6107 res
= ast_say_number(chan
, hour
, ints
, lang
, (char *) NULL
);
6109 if (tm
.tm_min
> 9) {
6111 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
6112 } else if (tm
.tm_min
) {
6114 res
= ast_streamfile(chan
, "digits/oh", lang
);
6116 res
= ast_waitstream(chan
, ints
);
6118 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
6121 res
= ast_streamfile(chan
, "digits/oclock", lang
);
6123 res
= ast_waitstream(chan
, ints
);
6127 res
= ast_streamfile(chan
, "digits/p-m", lang
);
6130 res
= ast_streamfile(chan
, "digits/a-m", lang
);
6133 res
= ast_waitstream(chan
, ints
);
6135 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
6139 /* Brazilian Portuguese syntax */
6140 int ast_say_datetime_pt_BR(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6145 ast_localtime(&t
, &tm
, NULL
);
6146 res
= ast_say_date(chan
, t
, ints
, lang
);
6148 res
= ast_say_time(chan
, t
, ints
, lang
);
6152 /* Taiwanese / Chinese syntax */
6153 int ast_say_datetime_tw(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6160 ast_localtime(&t
, &tm
, NULL
);
6162 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
6164 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6165 res
= ast_streamfile(chan
, fn
, lang
);
6167 res
= ast_waitstream(chan
, ints
);
6170 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
6172 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6173 res
= ast_streamfile(chan
, fn
, lang
);
6175 res
= ast_waitstream(chan
, ints
);
6181 else if (hour
== 12)
6183 else if (hour
> 12) {
6189 res
= ast_streamfile(chan
, "digits/p-m", lang
);
6192 res
= ast_streamfile(chan
, "digits/a-m", lang
);
6195 res
= ast_waitstream(chan
, ints
);
6197 res
= ast_say_number(chan
, hour
, ints
, lang
, (char *) NULL
);
6199 res
= ast_streamfile(chan
, "digits/oclock", lang
);
6201 res
= ast_waitstream(chan
, ints
);
6203 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
6205 res
= ast_streamfile(chan
, "digits/minute", lang
);
6207 res
= ast_waitstream(chan
, ints
);
6212 int ast_say_datetime_he(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6219 ast_localtime(&t
, &tm
, NULL
);
6221 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6222 res
= ast_streamfile(chan
, fn
, lang
);
6224 res
= ast_waitstream(chan
, ints
);
6228 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6229 res
= ast_streamfile(chan
, fn
, lang
);
6231 res
= ast_waitstream(chan
, ints
);
6235 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, "f");
6244 res
= ast_say_number(chan
, hour
, ints
, lang
, "f");
6247 if (tm
.tm_min
> 9) {
6249 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, "f");
6251 } else if (tm
.tm_min
) {
6253 /* say a leading zero if needed */
6254 res
= ast_say_number(chan
, 0, ints
, lang
, "f");
6257 res
= ast_waitstream(chan
, ints
);
6260 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, "f");
6264 res
= ast_waitstream(chan
, ints
);
6268 res
= ast_waitstream(chan
, ints
);
6271 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, "f");
6275 static int say_datetime_from_now(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6277 if (!strcasecmp(lang
, "en") ) { /* English syntax */
6278 return(ast_say_datetime_from_now_en(chan
, t
, ints
, lang
));
6279 } else if (!strcasecmp(lang
, "fr") ) { /* French syntax */
6280 return(ast_say_datetime_from_now_fr(chan
, t
, ints
, lang
));
6281 } else if (!strcasecmp(lang
, "pt") || !strcasecmp(lang
, "pt_BR")) { /* Portuguese syntax */
6282 return(ast_say_datetime_from_now_pt(chan
, t
, ints
, lang
));
6283 } else if (!strcasecmp(lang
, "ge") ) { /* Georgian syntax */
6284 return(ast_say_datetime_from_now_ge(chan
, t
, ints
, lang
));
6285 } else if (!strcasecmp(lang
, "he")) { /* Georgian syntax */
6286 return (ast_say_datetime_from_now_he(chan
, t
, ints
, lang
));
6289 /* Default to English */
6290 return(ast_say_datetime_from_now_en(chan
, t
, ints
, lang
));
6293 /* English syntax */
6294 int ast_say_datetime_from_now_en(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6305 ast_localtime(&t
, &tm
, NULL
);
6306 ast_localtime(&nowt
,&now
, NULL
);
6307 daydiff
= now
.tm_yday
- tm
.tm_yday
;
6308 if ((daydiff
< 0) || (daydiff
> 6)) {
6309 /* Day of month and month */
6311 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6312 res
= ast_streamfile(chan
, fn
, lang
);
6314 res
= ast_waitstream(chan
, ints
);
6317 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
6319 } else if (daydiff
) {
6320 /* Just what day of the week */
6322 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6323 res
= ast_streamfile(chan
, fn
, lang
);
6325 res
= ast_waitstream(chan
, ints
);
6327 } /* Otherwise, it was today */
6329 res
= ast_say_time(chan
, t
, ints
, lang
);
6334 int ast_say_datetime_from_now_fr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6345 ast_localtime(&t
, &tm
, NULL
);
6346 ast_localtime(&nowt
, &now
, NULL
);
6347 daydiff
= now
.tm_yday
- tm
.tm_yday
;
6348 if ((daydiff
< 0) || (daydiff
> 6)) {
6349 /* Day of month and month */
6351 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6352 res
= ast_streamfile(chan
, fn
, lang
);
6354 res
= ast_waitstream(chan
, ints
);
6357 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
6359 } else if (daydiff
) {
6360 /* Just what day of the week */
6362 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6363 res
= ast_streamfile(chan
, fn
, lang
);
6365 res
= ast_waitstream(chan
, ints
);
6367 } /* Otherwise, it was today */
6369 res
= ast_say_time(chan
, t
, ints
, lang
);
6373 /* Portuguese syntax */
6374 int ast_say_datetime_from_now_pt(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6385 ast_localtime(&t
, &tm
, NULL
);
6386 ast_localtime(&nowt
, &now
, NULL
);
6387 daydiff
= now
.tm_yday
- tm
.tm_yday
;
6388 if ((daydiff
< 0) || (daydiff
> 6)) {
6389 /* Day of month and month */
6391 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
6393 res
= wait_file(chan
, ints
, "digits/pt-de", lang
);
6394 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6396 res
= wait_file(chan
, ints
, fn
, lang
);
6398 } else if (daydiff
) {
6399 /* Just what day of the week */
6400 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6402 res
= wait_file(chan
, ints
, fn
, lang
);
6403 } /* Otherwise, it was today */
6404 if (!strcasecmp(lang
, "pt_BR")) {
6405 if (tm
.tm_hour
> 1) {
6406 snprintf(fn
, sizeof(fn
), "digits/pt-as");
6408 snprintf(fn
, sizeof(fn
), "digits/pt-a");
6411 res
= wait_file(chan
, ints
, fn
, lang
);
6413 snprintf(fn
, sizeof(fn
), "digits/pt-ah");
6415 res
= wait_file(chan
, ints
, fn
, lang
);
6416 if (tm
.tm_hour
!= 1)
6418 res
= wait_file(chan
, ints
, "digits/pt-sss", lang
);
6420 res
= ast_say_time(chan
, t
, ints
, lang
);
6426 int ast_say_datetime_from_now_he(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6437 ast_localtime(&t
, &tm
, NULL
);
6438 ast_localtime(&nowt
, &now
, NULL
);
6439 daydiff
= now
.tm_yday
- tm
.tm_yday
;
6440 if ((daydiff
< 0) || (daydiff
> 6)) {
6441 /* Day of month and month */
6443 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6444 res
= ast_streamfile(chan
, fn
, lang
);
6446 res
= ast_waitstream(chan
, ints
);
6449 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, "f");
6451 } else if (daydiff
) {
6452 /* Just what day of the week */
6454 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6455 res
= ast_streamfile(chan
, fn
, lang
);
6457 res
= ast_waitstream(chan
, ints
);
6460 } /* Otherwise, it was today */
6462 res
= ast_say_time(chan
, t
, ints
, lang
);
6467 /*********************************** GREEK SUPPORT ***************************************/
6471 * digits/female-[1..4] : "Mia, dyo , treis, tessereis"
6473 static int gr_say_number_female(int num
, struct ast_channel
*chan
, const char *ints
, const char *lang
){
6479 /* ast_log(LOG_DEBUG, "\n\n Saying number female %s %d \n\n",lang, num); */
6481 snprintf(fn
, sizeof(fn
), "digits/female-%d", num
);
6482 res
= wait_file(chan
, ints
, fn
, lang
);
6483 } else if (num
< 13) {
6484 res
= ast_say_number(chan
, num
, ints
, lang
, (char *) NULL
);
6485 } else if (num
<100 ) {
6486 tmp
= (num
/10) * 10;
6488 snprintf(fn
, sizeof(fn
), "digits/%d", tmp
);
6489 res
= ast_streamfile(chan
, fn
, lang
);
6491 res
= ast_waitstream(chan
, ints
);
6493 gr_say_number_female(left
, chan
, ints
, lang
);
6504 * A list of the files that you need to create
6505 -> digits/xilia = "xilia"
6506 -> digits/myrio = "ekatomyrio"
6507 -> digits/thousands = "xiliades"
6508 -> digits/millions = "ektatomyria"
6509 -> digits/[1..12] :: A pronunciation of th digits form 1 to 12 e.g. "tria"
6510 -> digits/[10..100] :: A pronunciation of the tens from 10 to 90
6512 Here we must note that we use digits/tens/100 to utter "ekato"
6513 and digits/hundred-100 to utter "ekaton"
6514 -> digits/hundred-[100...1000] :: A pronunciation of hundreds from 100 to 1000 e.g 400 =
6515 "terakosia". Here again we use hundreds/1000 for "xilia"
6516 and digits/thousnds for "xiliades"
6519 static int ast_say_number_full_gr(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
,int audiofd
, int ctrlfd
)
6527 snprintf(fn
, sizeof(fn
), "digits/0");
6528 res
= ast_streamfile(chan
, fn
, chan
->language
);
6530 return ast_waitstream(chan
, ints
);
6533 while (!res
&& num
) {
6536 snprintf(fn
, sizeof(fn
), "digits/%d", num
);
6538 } else if (num
<= 100) {
6539 /* 13 < num <= 100 */
6540 snprintf(fn
, sizeof(fn
), "digits/%d", (num
/10) * 10);
6541 num
-= ((num
/ 10) * 10);
6542 } else if (num
< 200) {
6543 /* 100 < num < 200 */
6544 snprintf(fn
, sizeof(fn
), "digits/hundred-100");
6545 num
-= ((num
/ 100) * 100);
6546 } else if (num
< 1000) {
6547 /* 200 < num < 1000 */
6548 snprintf(fn
, sizeof(fn
), "digits/hundred-%d", (num
/100)*100);
6549 num
-= ((num
/ 100) * 100);
6550 } else if (num
< 2000){
6551 snprintf(fn
, sizeof(fn
), "digits/xilia");
6552 num
-= ((num
/ 1000) * 1000);
6555 if (num
< 1000000) {
6556 res
= ast_say_number_full_gr(chan
, (num
/ 1000), ints
, chan
->language
, audiofd
, ctrlfd
);
6560 snprintf(fn
, sizeof(fn
), "digits/thousands");
6562 if (num
< 1000000000) { /* 1,000,000,000 */
6563 res
= ast_say_number_full_gr(chan
, (num
/ 1000000), ints
, chan
->language
,audiofd
, ctrlfd
);
6566 num
= num
% 1000000;
6567 snprintf(fn
, sizeof(fn
), "digits/millions");
6569 ast_log(LOG_DEBUG
, "Number '%d' is too big for me\n", num
);
6575 if (!ast_streamfile(chan
, fn
, language
)) {
6576 if ((audiofd
> -1) && (ctrlfd
> -1))
6577 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
6579 res
= ast_waitstream(chan
, ints
);
6581 ast_stopstream(chan
);
6589 * The format is weekday - day - month -year
6591 * A list of the files that you need to create
6592 * digits/day-[1..7] : "Deytera .. Paraskeyh"
6593 * digits/months/1..12 : "Ianouariou .. Dekembriou"
6594 Attention the months are in
6599 static int ast_say_date_gr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6607 ast_localtime(&t
,&tm
,NULL
);
6608 /* W E E K - D A Y */
6610 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6611 res
= ast_streamfile(chan
, fn
, lang
);
6613 res
= ast_waitstream(chan
, ints
);
6617 gr_say_number_female(tm
.tm_mday
, chan
, ints
, lang
);
6621 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6622 res
= ast_streamfile(chan
, fn
, lang
);
6624 res
= ast_waitstream(chan
, ints
);
6628 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
6634 /* A list of the files that you need to create
6635 * digits/female/1..4 : "Mia, dyo , treis, tesseris "
6636 * digits/kai : "KAI"
6638 * digits/p-m : "meta meshmbrias"
6639 * digits/a-m : "pro meshmbrias"
6642 static int ast_say_time_gr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6649 ast_localtime(&t
, &tm
, NULL
);
6654 else if (hour
== 12)
6656 else if (hour
> 12) {
6661 res
= gr_say_number_female(hour
, chan
, ints
, lang
);
6664 res
= ast_streamfile(chan
, "digits/kai", lang
);
6666 res
= ast_waitstream(chan
, ints
);
6668 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char *) NULL
);
6671 res
= ast_streamfile(chan
, "digits/hwra", lang
);
6673 res
= ast_waitstream(chan
, ints
);
6677 res
= ast_streamfile(chan
, "digits/p-m", lang
);
6680 res
= ast_streamfile(chan
, "digits/a-m", lang
);
6683 res
= ast_waitstream(chan
, ints
);
6689 static int ast_say_datetime_gr(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
6695 ast_localtime(&t
, &tm
, NULL
);
6698 /* W E E K - D A Y */
6700 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
6701 res
= ast_streamfile(chan
, fn
, lang
);
6703 res
= ast_waitstream(chan
, ints
);
6707 gr_say_number_female(tm
.tm_mday
, chan
, ints
, lang
);
6711 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
6712 res
= ast_streamfile(chan
, fn
, lang
);
6714 res
= ast_waitstream(chan
, ints
);
6717 res
= ast_say_time_gr(chan
, t
, ints
, lang
);
6721 static int ast_say_date_with_format_gr(struct ast_channel
*chan
, time_t time
, const char *ints
, const char *lang
, const char *format
, const char *timezone
)
6725 int res
=0, offset
, sndoffset
;
6726 char sndfile
[256], nextmsg
[256];
6729 format
= "AdBY 'digits/at' IMp";
6731 ast_localtime(&time
,&tm
,timezone
);
6733 for (offset
=0 ; format
[offset
] != '\0' ; offset
++) {
6734 ast_log(LOG_DEBUG
, "Parsing %c (offset %d) in %s\n", format
[offset
], offset
, format
);
6735 switch (format
[offset
]) {
6736 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
6738 /* Literal name of a sound file */
6740 for (sndoffset
=0 ; (format
[++offset
] != '\'') && (sndoffset
< 256) ; sndoffset
++)
6741 sndfile
[sndoffset
] = format
[offset
];
6742 sndfile
[sndoffset
] = '\0';
6743 res
= wait_file(chan
,ints
,sndfile
,lang
);
6747 /* Sunday - Saturday */
6748 snprintf(nextmsg
,sizeof(nextmsg
), "digits/day-%d", tm
.tm_wday
);
6749 res
= wait_file(chan
,ints
,nextmsg
,lang
);
6754 /* January - December */
6755 snprintf(nextmsg
,sizeof(nextmsg
), "digits/mon-%d", tm
.tm_mon
);
6756 res
= wait_file(chan
,ints
,nextmsg
,lang
);
6760 /* first - thirtyfirst */
6761 gr_say_number_female(tm
.tm_mday
, chan
, ints
, lang
);
6766 ast_say_number_full_gr(chan
, 1900+tm
.tm_year
, ints
, chan
->language
, -1, -1);
6771 if (tm
.tm_hour
== 0)
6772 gr_say_number_female(12, chan
, ints
, lang
);
6773 else if (tm
.tm_hour
> 12)
6774 gr_say_number_female(tm
.tm_hour
- 12, chan
, ints
, lang
);
6776 gr_say_number_female(tm
.tm_hour
, chan
, ints
, lang
);
6781 gr_say_number_female(tm
.tm_hour
, chan
, ints
, lang
);
6787 res
= ast_streamfile(chan
, "digits/kai", lang
);
6789 res
= ast_waitstream(chan
, ints
);
6791 res
= ast_say_number_full_gr(chan
, tm
.tm_min
, ints
, lang
, -1, -1);
6794 res
= ast_streamfile(chan
, "digits/oclock", lang
);
6796 res
= ast_waitstream(chan
, ints
);
6802 if (tm
.tm_hour
> 11)
6803 snprintf(nextmsg
,sizeof(nextmsg
), "digits/p-m");
6805 snprintf(nextmsg
,sizeof(nextmsg
), "digits/a-m");
6806 res
= wait_file(chan
,ints
,nextmsg
,lang
);
6809 /* Shorthand for "Today", "Yesterday", or ABdY */
6810 /* XXX As emphasized elsewhere, this should the native way in your
6811 * language to say the date, with changes in what you say, depending
6812 * upon how recent the date is. XXX */
6816 time_t beg_today
, tt
;
6818 gettimeofday(&now
,NULL
);
6820 ast_localtime(&tt
,&tmnow
,timezone
);
6821 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
6822 /* In any case, it saves not having to do ast_mktime() */
6823 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
6824 if (beg_today
< time
) {
6826 res
= wait_file(chan
,ints
, "digits/today",lang
);
6827 } else if (beg_today
- 86400 < time
) {
6829 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
6831 res
= ast_say_date_with_format_gr(chan
, time
, ints
, lang
, "AdBY", timezone
);
6836 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
6837 /* XXX As emphasized elsewhere, this should the native way in your
6838 * language to say the date, with changes in what you say, depending
6839 * upon how recent the date is. XXX */
6843 time_t beg_today
, tt
;
6845 gettimeofday(&now
,NULL
);
6847 ast_localtime(&tt
,&tmnow
,timezone
);
6848 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
6849 /* In any case, it saves not having to do ast_mktime() */
6850 beg_today
= tt
- (tmnow
.tm_hour
* 3600) - (tmnow
.tm_min
* 60) - (tmnow
.tm_sec
);
6851 if (beg_today
< time
) {
6853 } else if ((beg_today
- 86400) < time
) {
6855 res
= wait_file(chan
,ints
, "digits/yesterday",lang
);
6856 } else if (beg_today
- 86400 * 6 < time
) {
6857 /* Within the last week */
6858 res
= ast_say_date_with_format_gr(chan
, time
, ints
, lang
, "A", timezone
);
6860 res
= ast_say_date_with_format_gr(chan
, time
, ints
, lang
, "AdBY", timezone
);
6865 res
= ast_say_date_with_format_gr(chan
, time
, ints
, lang
, "HM", timezone
);
6869 snprintf(nextmsg
,sizeof(nextmsg
), "digits/kai");
6870 res
= wait_file(chan
,ints
,nextmsg
,lang
);
6872 res
= ast_say_number_full_gr(chan
, tm
.tm_sec
, ints
, lang
, -1, -1);
6874 snprintf(nextmsg
,sizeof(nextmsg
), "digits/seconds");
6875 res
= wait_file(chan
,ints
,nextmsg
,lang
);
6878 res
= ast_say_date_with_format_gr(chan
, time
, ints
, lang
, "HMS", timezone
);
6882 /* Just ignore spaces and tabs */
6885 /* Unknown character */
6886 ast_log(LOG_WARNING
, "Unknown character in datetime format %s: %c at pos %d\n", format
, format
[offset
], offset
);
6888 /* Jump out on DTMF */
6899 /*********************************** Georgian Support ***************************************/
6903 Convert a number into a semi-localized string. Only for Georgian.
6904 res must be of at least 256 bytes, preallocated.
6905 The output corresponds to Georgian spoken numbers, so
6906 it may be either converted to real words by applying a direct conversion
6907 table, or played just by substituting the entities with played files.
6909 Output may consist of the following tokens (separated by spaces):
6911 1-9, 1_-9_. (erti, ori, sami, otxi, ... . erti, or, sam, otx, ...).
6913 20, 40, 60, 80, 20_, 40_, 60_, 80_. (oci, ormoci, ..., ocda, ormocda, ...).
6914 100, 100_, 200, 200_, ..., 900, 900_. (asi, as, orasi, oras, ...).
6915 1000, 1000_. (atasi, atas).
6916 1000000, 1000000_. (milioni, milion).
6917 1000000000, 1000000000_. (miliardi, miliard).
6919 To be able to play the sounds, each of the above tokens needs
6920 a corresponding sound file. (e.g. 200_.gsm).
6922 static char* ast_translate_number_ge(int num
, char* res
, int res_len
)
6930 strncat(res
, "minus ", res_len
- strlen(res
) - 1);
6931 if ( num
> INT_MIN
) {
6939 /* directly read the numbers */
6940 if (num
<= 20 || num
== 40 || num
== 60 || num
== 80 || num
== 100) {
6941 snprintf(buf
, sizeof(buf
), "%d", num
);
6942 strncat(res
, buf
, res_len
- strlen(res
) - 1);
6947 if (num
< 40) { /* ocda... */
6948 strncat(res
, "20_ ", res_len
- strlen(res
) - 1);
6949 return ast_translate_number_ge(num
- 20, res
, res_len
);
6952 if (num
< 60) { /* ormocda... */
6953 strncat(res
, "40_ ", res_len
- strlen(res
) - 1);
6954 return ast_translate_number_ge(num
- 40, res
, res_len
);
6957 if (num
< 80) { /* samocda... */
6958 strncat(res
, "60_ ", res_len
- strlen(res
) - 1);
6959 return ast_translate_number_ge(num
- 60, res
, res_len
);
6962 if (num
< 100) { /* otxmocda... */
6963 strncat(res
, "80_ ", res_len
- strlen(res
) - 1);
6964 return ast_translate_number_ge(num
- 80, res
, res_len
);
6968 if (num
< 1000) { /* as, oras, samas, ..., cxraas. asi, orasi, ..., cxraasi. */
6969 remainder
= num
% 100;
6970 digit
= (num
- remainder
) / 100;
6972 if (remainder
== 0) {
6973 snprintf(buf
, sizeof(buf
), "%d", num
);
6974 strncat(res
, buf
, res_len
- strlen(res
) - 1);
6977 snprintf(buf
, sizeof(buf
), "%d_ ", digit
*100);
6978 strncat(res
, buf
, res_len
- strlen(res
) - 1);
6979 return ast_translate_number_ge(remainder
, res
, res_len
);
6985 strncat(res
, "1000", res_len
- strlen(res
) - 1);
6990 if (num
< 1000000) {
6991 remainder
= num
% 1000;
6992 digit
= (num
- remainder
) / 1000;
6994 if (remainder
== 0) {
6995 ast_translate_number_ge(digit
, res
, res_len
);
6996 strncat(res
, " 1000", res_len
- strlen(res
) - 1);
7001 strncat(res
, "1000_ ", res_len
- strlen(res
) - 1);
7002 return ast_translate_number_ge(remainder
, res
, res_len
);
7005 ast_translate_number_ge(digit
, res
, res_len
);
7006 strncat(res
, " 1000_ ", res_len
- strlen(res
) - 1);
7007 return ast_translate_number_ge(remainder
, res
, res_len
);
7012 if (num
== 1000000) {
7013 strncat(res
, "1 1000000", res_len
- strlen(res
) - 1);
7018 if (num
< 1000000000) {
7019 remainder
= num
% 1000000;
7020 digit
= (num
- remainder
) / 1000000;
7022 if (remainder
== 0) {
7023 ast_translate_number_ge(digit
, res
, res_len
);
7024 strncat(res
, " 1000000", res_len
- strlen(res
) - 1);
7028 ast_translate_number_ge(digit
, res
, res_len
);
7029 strncat(res
, " 1000000_ ", res_len
- strlen(res
) - 1);
7030 return ast_translate_number_ge(remainder
, res
, res_len
);
7035 if (num
== 1000000000) {
7036 strncat(res
, "1 1000000000", res_len
- strlen(res
) - 1);
7041 if (num
> 1000000000) {
7042 remainder
= num
% 1000000000;
7043 digit
= (num
- remainder
) / 1000000000;
7045 if (remainder
== 0) {
7046 ast_translate_number_ge(digit
, res
, res_len
);
7047 strncat(res
, " 1000000000", res_len
- strlen(res
) - 1);
7051 ast_translate_number_ge(digit
, res
, res_len
);
7052 strncat(res
, " 1000000000_ ", res_len
- strlen(res
) - 1);
7053 return ast_translate_number_ge(remainder
, res
, res_len
);
7063 /*! \brief ast_say_number_full_ge: Georgian syntax */
7064 static int ast_say_number_full_ge(struct ast_channel
*chan
, int num
, const char *ints
, const char *language
, const char *options
, int audiofd
, int ctrlfd
)
7069 const char* remainder
= fn
;
7072 return ast_say_digits_full(chan
, 0, ints
, language
, audiofd
, ctrlfd
);
7075 ast_translate_number_ge(num
, fn
, 512);
7079 while (res
== 0 && (s
= strstr(remainder
, " "))) {
7080 size_t len
= s
- remainder
;
7081 char* new_string
= malloc(len
+ 1 + strlen("digits/"));
7083 sprintf(new_string
, "digits/");
7084 strncat(new_string
, remainder
, len
); /* we can't sprintf() it, it's not null-terminated. */
7085 /* new_string[len + strlen("digits/")] = '\0'; */
7087 if (!ast_streamfile(chan
, new_string
, language
)) {
7088 if ((audiofd
> -1) && (ctrlfd
> -1))
7089 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
7091 res
= ast_waitstream(chan
, ints
);
7093 ast_stopstream(chan
);
7097 remainder
= s
+ 1; /* position just after the found space char. */
7098 while (*remainder
== ' ') /* skip multiple spaces */
7103 /* the last chunk. */
7104 if (res
== 0 && *remainder
) {
7106 char* new_string
= malloc(strlen(remainder
) + 1 + strlen("digits/"));
7107 sprintf(new_string
, "digits/%s", remainder
);
7109 if (!ast_streamfile(chan
, new_string
, language
)) {
7110 if ((audiofd
> -1) && (ctrlfd
> -1))
7111 res
= ast_waitstream_full(chan
, ints
, audiofd
, ctrlfd
);
7113 res
= ast_waitstream(chan
, ints
);
7115 ast_stopstream(chan
);
7129 Georgian support for date/time requires the following files (*.gsm):
7131 mon-1, mon-2, ... (ianvari, tebervali, ...)
7132 day-1, day-2, ... (orshabati, samshabati, ...)
7140 /* Georgian syntax. e.g. "oriatas xuti tslis 5 noemberi". */
7141 static int ast_say_date_ge(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
7146 ast_localtime(&t
,&tm
,NULL
);
7149 res
= ast_say_number(chan
, tm
.tm_year
+ 1900, ints
, lang
, (char *) NULL
);
7152 snprintf(fn
, sizeof(fn
), "digits/tslis %d", tm
.tm_wday
);
7153 res
= ast_streamfile(chan
, fn
, lang
);
7155 res
= ast_waitstream(chan
, ints
);
7159 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char * ) NULL
);
7161 res = ast_waitstream(chan, ints);
7166 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
7167 res
= ast_streamfile(chan
, fn
, lang
);
7169 res
= ast_waitstream(chan
, ints
);
7179 /* Georgian syntax. e.g. "otxi saati da eqvsi tsuti" */
7180 static int ast_say_time_ge(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
7185 ast_localtime(&t
, &tm
, NULL
);
7187 res
= ast_say_number(chan
, tm
.tm_hour
, ints
, lang
, (char*)NULL
);
7189 res
= ast_streamfile(chan
, "digits/saati_da", lang
);
7191 res
= ast_waitstream(chan
, ints
);
7196 res
= ast_say_number(chan
, tm
.tm_min
, ints
, lang
, (char*)NULL
);
7199 res
= ast_streamfile(chan
, "digits/tsuti", lang
);
7201 res
= ast_waitstream(chan
, ints
);
7210 /* Georgian syntax. Say date, then say time. */
7211 static int ast_say_datetime_ge(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
7216 ast_localtime(&t
, &tm
, NULL
);
7217 res
= ast_say_date(chan
, t
, ints
, lang
);
7219 ast_say_time(chan
, t
, ints
, lang
);
7227 /* Georgian syntax */
7228 static int ast_say_datetime_from_now_ge(struct ast_channel
*chan
, time_t t
, const char *ints
, const char *lang
)
7239 ast_localtime(&t
, &tm
, NULL
);
7240 ast_localtime(&nowt
, &now
, NULL
);
7241 daydiff
= now
.tm_yday
- tm
.tm_yday
;
7242 if ((daydiff
< 0) || (daydiff
> 6)) {
7243 /* Day of month and month */
7245 res
= ast_say_number(chan
, tm
.tm_mday
, ints
, lang
, (char *) NULL
);
7247 snprintf(fn
, sizeof(fn
), "digits/mon-%d", tm
.tm_mon
);
7248 res
= ast_streamfile(chan
, fn
, lang
);
7250 res
= ast_waitstream(chan
, ints
);
7253 } else if (daydiff
) {
7254 /* Just what day of the week */
7256 snprintf(fn
, sizeof(fn
), "digits/day-%d", tm
.tm_wday
);
7257 res
= ast_streamfile(chan
, fn
, lang
);
7259 res
= ast_waitstream(chan
, ints
);
7261 } /* Otherwise, it was today */
7263 res
= ast_say_time(chan
, t
, ints
, lang
);
7271 * remap the 'say' functions to use those in this file
7273 static void __attribute__((constructor
)) __say_init(void)
7275 ast_say_number_full
= say_number_full
;
7276 ast_say_enumeration_full
= say_enumeration_full
;
7277 ast_say_digit_str_full
= say_digit_str_full
;
7278 ast_say_character_str_full
= say_character_str_full
;
7279 ast_say_phonetic_str_full
= say_phonetic_str_full
;
7280 ast_say_datetime
= say_datetime
;
7281 ast_say_time
= say_time
;
7282 ast_say_date
= say_date
;
7283 ast_say_datetime_from_now
= say_datetime_from_now
;
7284 ast_say_date_with_format
= say_date_with_format
;