![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
say.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2005, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * George Konstantoulakis <gkon@inaccessnetworks.com> 00008 * 00009 * See http://www.asterisk.org for more information about 00010 * the Asterisk project. Please do not directly contact 00011 * any of the maintainers of this project for assistance; 00012 * the project provides a web site, mailing lists and IRC 00013 * channels for your use. 00014 * 00015 * This program is free software, distributed under the terms of 00016 * the GNU General Public License Version 2. See the LICENSE file 00017 * at the top of the source tree. 00018 */ 00019 00020 /*! \file 00021 * 00022 * \brief Say numbers and dates (maybe words one day too) 00023 * 00024 * \author Mark Spencer <markster@digium.com> 00025 * 00026 * \note 12-16-2004 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr) George Konstantoulakis <gkon@inaccessnetworks.com> 00027 * 00028 */ 00029 00030 #include "asterisk.h" 00031 00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51499 $") 00033 00034 #include <sys/types.h> 00035 #include <string.h> 00036 #include <stdlib.h> 00037 #include <netinet/in.h> 00038 #include <time.h> 00039 #include <ctype.h> 00040 #include <math.h> 00041 #include <stdio.h> 00042 00043 #ifdef SOLARIS 00044 #include <iso/limits_iso.h> 00045 #endif 00046 00047 #include "asterisk/file.h" 00048 #include "asterisk/channel.h" 00049 #include "asterisk/logger.h" 00050 #include "asterisk/options.h" 00051 #include "asterisk/say.h" 00052 #include "asterisk/lock.h" 00053 #include "asterisk/localtime.h" 00054 #include "asterisk/utils.h" 00055 00056 /* Forward declaration */ 00057 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang); 00058 00059 00060 static int say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd) 00061 { 00062 const char *fn; 00063 char fnbuf[256]; 00064 char ltr; 00065 int num = 0; 00066 int res = 0; 00067 00068 while (str[num]) { 00069 fn = NULL; 00070 switch (str[num]) { 00071 case ('*'): 00072 fn = "digits/star"; 00073 break; 00074 case ('#'): 00075 fn = "digits/pound"; 00076 break; 00077 case ('!'): 00078 fn = "letters/exclaimation-point"; 00079 break; 00080 case ('@'): 00081 fn = "letters/at"; 00082 break; 00083 case ('$'): 00084 fn = "letters/dollar"; 00085 break; 00086 case ('-'): 00087 fn = "letters/dash"; 00088 break; 00089 case ('.'): 00090 fn = "letters/dot"; 00091 break; 00092 case ('='): 00093 fn = "letters/equals"; 00094 break; 00095 case ('+'): 00096 fn = "letters/plus"; 00097 break; 00098 case ('/'): 00099 fn = "letters/slash"; 00100 break; 00101 case (' '): 00102 fn = "letters/space"; 00103 break; 00104 case ('0'): 00105 case ('1'): 00106 case ('2'): 00107 case ('3'): 00108 case ('4'): 00109 case ('5'): 00110 case ('6'): 00111 case ('7'): 00112 case ('8'): 00113 case ('9'): 00114 strcpy(fnbuf, "digits/X"); 00115 fnbuf[7] = str[num]; 00116 fn = fnbuf; 00117 break; 00118 default: 00119 ltr = str[num]; 00120 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */ 00121 strcpy(fnbuf, "letters/X"); 00122 fnbuf[8] = ltr; 00123 fn = fnbuf; 00124 } 00125 res = ast_streamfile(chan, fn, lang); 00126 if (!res) 00127 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00128 ast_stopstream(chan); 00129 num++; 00130 } 00131 00132 return res; 00133 } 00134 00135 static int say_phonetic_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd) 00136 { 00137 const char *fn; 00138 char fnbuf[256]; 00139 char ltr; 00140 int num = 0; 00141 int res = 0; 00142 00143 while (str[num]) { 00144 fn = NULL; 00145 switch (str[num]) { 00146 case ('*'): 00147 fn = "digits/star"; 00148 break; 00149 case ('#'): 00150 fn = "digits/pound"; 00151 break; 00152 case ('!'): 00153 fn = "letters/exclaimation-point"; 00154 break; 00155 case ('@'): 00156 fn = "letters/at"; 00157 break; 00158 case ('$'): 00159 fn = "letters/dollar"; 00160 break; 00161 case ('-'): 00162 fn = "letters/dash"; 00163 break; 00164 case ('.'): 00165 fn = "letters/dot"; 00166 break; 00167 case ('='): 00168 fn = "letters/equals"; 00169 break; 00170 case ('+'): 00171 fn = "letters/plus"; 00172 break; 00173 case ('/'): 00174 fn = "letters/slash"; 00175 break; 00176 case (' '): 00177 fn = "letters/space"; 00178 break; 00179 case ('0'): 00180 case ('1'): 00181 case ('2'): 00182 case ('3'): 00183 case ('4'): 00184 case ('5'): 00185 case ('6'): 00186 case ('7'): 00187 case ('8'): 00188 strcpy(fnbuf, "digits/X"); 00189 fnbuf[7] = str[num]; 00190 fn = fnbuf; 00191 break; 00192 default: /* '9' falls here... */ 00193 ltr = str[num]; 00194 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */ 00195 strcpy(fnbuf, "phonetic/X_p"); 00196 fnbuf[9] = ltr; 00197 fn = fnbuf; 00198 } 00199 res = ast_streamfile(chan, fn, lang); 00200 if (!res) 00201 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00202 ast_stopstream(chan); 00203 num++; 00204 } 00205 00206 return res; 00207 } 00208 00209 static int say_digit_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd) 00210 { 00211 const char *fn; 00212 char fnbuf[256]; 00213 int num = 0; 00214 int res = 0; 00215 00216 while (str[num] && !res) { 00217 fn = NULL; 00218 switch (str[num]) { 00219 case ('*'): 00220 fn = "digits/star"; 00221 break; 00222 case ('#'): 00223 fn = "digits/pound"; 00224 break; 00225 case ('-'): 00226 fn = "digits/minus"; 00227 break; 00228 case '0': 00229 case '1': 00230 case '2': 00231 case '3': 00232 case '4': 00233 case '5': 00234 case '6': 00235 case '7': 00236 case '8': 00237 case '9': 00238 strcpy(fnbuf, "digits/X"); 00239 fnbuf[7] = str[num]; 00240 fn = fnbuf; 00241 break; 00242 } 00243 if (fn) { 00244 res = ast_streamfile(chan, fn, lang); 00245 if (!res) 00246 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00247 ast_stopstream(chan); 00248 } 00249 num++; 00250 } 00251 00252 return res; 00253 } 00254 00255 /* Forward declarations */ 00256 /*! \page Def_syntaxlang Asterisk Language Syntaxes supported 00257 \note Not really language codes. 00258 For these language codes, Asterisk will change the syntax when 00259 saying numbers (and in some cases dates and voicemail messages 00260 as well) 00261 \arg \b da - Danish 00262 \arg \b de - German 00263 \arg \b en - English (US) 00264 \arg \b en_GB - English (British) 00265 \arg \b es - Spanish, Mexican 00266 \arg \b fr - French 00267 \arg \b he - Hebrew 00268 \arg \b it - Italian 00269 \arg \b nl - Dutch 00270 \arg \b no - Norwegian 00271 \arg \b pl - Polish 00272 \arg \b pt - Portuguese 00273 \arg \b pt_BR - Portuguese (Brazil) 00274 \arg \b se - Swedish 00275 \arg \b tw - Taiwanese / Chinese 00276 \arg \b ru - Russian 00277 00278 \par Gender: 00279 For Some languages the numbers differ for gender and plural. 00280 \arg Use the option argument 'f' for female, 'm' for male and 'n' for neuter in languages like Portuguese, French, Spanish and German. 00281 \arg use the option argument 'c' is for commune and 'n' for neuter gender in nordic languages like Danish, Swedish and Norwegian. 00282 use the option argument 'p' for plural enumerations like in German 00283 00284 Date/Time functions currently have less languages supported than saynumber(). 00285 00286 \todo Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK 00287 00288 See contrib/i18n.testsuite.conf for some examples of the different syntaxes 00289 00290 \par Portuguese 00291 Portuguese sound files needed for Time/Date functions: 00292 pt-ah 00293 pt-ao 00294 pt-de 00295 pt-e 00296 pt-ora 00297 pt-meianoite 00298 pt-meiodia 00299 pt-sss 00300 00301 \par Spanish 00302 Spanish sound files needed for Time/Date functions: 00303 es-de 00304 es-el 00305 00306 \par Italian 00307 Italian sound files needed for Time/Date functions: 00308 ore-una 00309 ore-mezzanotte 00310 00311 */ 00312 00313 /* Forward declarations of language specific variants of ast_say_number_full */ 00314 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); 00315 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); 00316 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); 00317 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); 00318 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); 00319 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); 00320 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); 00321 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); 00322 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); 00323 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); 00324 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); 00325 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); 00326 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); 00327 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); 00328 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); 00329 static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); 00330 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); 00331 00332 /* Forward declarations of language specific variants of ast_say_enumeration_full */ 00333 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd); 00334 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); 00335 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); 00336 00337 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */ 00338 static int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00339 static int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00340 static int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00341 static int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00342 static int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00343 static int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00344 static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00345 00346 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); 00347 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); 00348 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); 00349 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); 00350 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); 00351 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); 00352 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); 00353 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); 00354 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); 00355 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); 00356 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); 00357 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); 00358 00359 static int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00360 static int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00361 static int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00362 static int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00363 static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00364 static int ast_say_time_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00365 static int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00366 static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00367 00368 static int ast_say_datetime_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00369 static int ast_say_datetime_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00370 static int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00371 static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00372 static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00373 static int ast_say_datetime_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00374 static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00375 static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00376 00377 static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00378 static int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00379 static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang); 00380 00381 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang) 00382 { 00383 int res; 00384 if ((res = ast_streamfile(chan, file, lang))) 00385 ast_log(LOG_WARNING, "Unable to play message %s\n", file); 00386 if (!res) 00387 res = ast_waitstream(chan, ints); 00388 return res; 00389 } 00390 00391 /*! \brief ast_say_number_full: call language-specific functions */ 00392 /* Called from AGI */ 00393 static int say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd) 00394 { 00395 if (!strcasecmp(language,"en") ) { /* English syntax */ 00396 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd)); 00397 } else if (!strcasecmp(language, "cz") ) { /* Czech syntax */ 00398 return(ast_say_number_full_cz(chan, num, ints, language, options, audiofd, ctrlfd)); 00399 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */ 00400 return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd)); 00401 } else if (!strcasecmp(language, "de") ) { /* German syntax */ 00402 return(ast_say_number_full_de(chan, num, ints, language, options, audiofd, ctrlfd)); 00403 } else if (!strcasecmp(language, "en_GB") ) { /* British syntax */ 00404 return(ast_say_number_full_en_GB(chan, num, ints, language, audiofd, ctrlfd)); 00405 } else if (!strcasecmp(language, "no") ) { /* Norwegian syntax */ 00406 return(ast_say_number_full_no(chan, num, ints, language, options, audiofd, ctrlfd)); 00407 } else if (!strcasecmp(language, "es") || !strcasecmp(language, "mx")) { /* Spanish syntax */ 00408 return(ast_say_number_full_es(chan, num, ints, language, options, audiofd, ctrlfd)); 00409 } else if (!strcasecmp(language, "fr") ) { /* French syntax */ 00410 return(ast_say_number_full_fr(chan, num, ints, language, options, audiofd, ctrlfd)); 00411 } else if (!strcasecmp(language, "he") ) { /* Hebrew syntax */ 00412 return(ast_say_number_full_he(chan, num, ints, language, options, audiofd, ctrlfd)); 00413 } else if (!strcasecmp(language, "it") ) { /* Italian syntax */ 00414 return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd)); 00415 } else if (!strcasecmp(language, "nl") ) { /* Dutch syntax */ 00416 return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd)); 00417 } else if (!strcasecmp(language, "pl") ) { /* Polish syntax */ 00418 return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd)); 00419 } else if (!strcasecmp(language, "pt") || !strcasecmp(language, "pt_BR")) { /* Portuguese syntax */ 00420 return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd)); 00421 } else if (!strcasecmp(language, "se") ) { /* Swedish syntax */ 00422 return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd)); 00423 } else if (!strcasecmp(language, "tw") || !strcasecmp(language, "zh") ) { /* Taiwanese / Chinese syntax */ 00424 return(ast_say_number_full_tw(chan, num, ints, language, audiofd, ctrlfd)); 00425 } else if (!strcasecmp(language, "gr") ) { /* Greek syntax */ 00426 return(ast_say_number_full_gr(chan, num, ints, language, audiofd, ctrlfd)); 00427 } else if (!strcasecmp(language, "ru") ) { /* Russian syntax */ 00428 return(ast_say_number_full_ru(chan, num, ints, language, options, audiofd, ctrlfd)); 00429 } 00430 00431 /* Default to english */ 00432 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd)); 00433 } 00434 00435 /*! \brief ast_say_number_full_en: English syntax */ 00436 /* This is the default syntax, if no other syntax defined in this file is used */ 00437 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) 00438 { 00439 int res = 0; 00440 int playh = 0; 00441 char fn[256] = ""; 00442 if (!num) 00443 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00444 00445 while (!res && (num || playh)) { 00446 if (num < 0) { 00447 snprintf(fn, sizeof(fn), "digits/minus"); 00448 if ( num > INT_MIN ) { 00449 num = -num; 00450 } else { 00451 num = 0; 00452 } 00453 } else if (playh) { 00454 snprintf(fn, sizeof(fn), "digits/hundred"); 00455 playh = 0; 00456 } else if (num < 20) { 00457 snprintf(fn, sizeof(fn), "digits/%d", num); 00458 num = 0; 00459 } else if (num < 100) { 00460 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 00461 num -= ((num / 10) * 10); 00462 } else { 00463 if (num < 1000){ 00464 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 00465 playh++; 00466 num -= ((num / 100) * 100); 00467 } else { 00468 if (num < 1000000) { /* 1,000,000 */ 00469 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd); 00470 if (res) 00471 return res; 00472 num = num % 1000; 00473 snprintf(fn, sizeof(fn), "digits/thousand"); 00474 } else { 00475 if (num < 1000000000) { /* 1,000,000,000 */ 00476 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd); 00477 if (res) 00478 return res; 00479 num = num % 1000000; 00480 snprintf(fn, sizeof(fn), "digits/million"); 00481 } else { 00482 if (option_debug) 00483 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00484 res = -1; 00485 } 00486 } 00487 } 00488 } 00489 if (!res) { 00490 if (!ast_streamfile(chan, fn, language)) { 00491 if ((audiofd > -1) && (ctrlfd > -1)) 00492 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00493 else 00494 res = ast_waitstream(chan, ints); 00495 } 00496 ast_stopstream(chan); 00497 } 00498 } 00499 return res; 00500 } 00501 00502 static int exp10_int(int power) 00503 { 00504 int x, res= 1; 00505 for (x=0;x<power;x++) 00506 res *= 10; 00507 return res; 00508 } 00509 00510 /*! \brief ast_say_number_full_cz: Czech syntax */ 00511 /* files needed: 00512 * 1m,2m - gender male 00513 * 1w,2w - gender female 00514 * 3,4,...,20 00515 * 30,40,...,90 00516 * 00517 * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set 00518 * 00519 * for each number 10^(3n + 3) exist 3 files represented as: 00520 * 1 tousand = jeden tisic = 1_E3 00521 * 2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3 00522 * 5,6,... tousands = pet,sest,... tisic = 5_E3 00523 * 00524 * million = _E6 00525 * miliard = _E9 00526 * etc... 00527 * 00528 * tousand, milion are gender male, so 1 and 2 is 1m 2m 00529 * miliard is gender female, so 1 and 2 is 1w 2w 00530 */ 00531 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) 00532 { 00533 int res = 0; 00534 int playh = 0; 00535 char fn[256] = ""; 00536 00537 int hundered = 0; 00538 int left = 0; 00539 int length = 0; 00540 00541 /* options - w = woman, m = man, n = neutral. Defaultl is woman */ 00542 if (!options) 00543 options = "w"; 00544 00545 if (!num) 00546 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00547 00548 while (!res && (num || playh)) { 00549 if (num < 0) { 00550 snprintf(fn, sizeof(fn), "digits/minus"); 00551 if ( num > INT_MIN ) { 00552 num = -num; 00553 } else { 00554 num = 0; 00555 } 00556 } else if (num < 3 ) { 00557 snprintf(fn, sizeof(fn), "digits/%d%c",num,options[0]); 00558 playh = 0; 00559 num = 0; 00560 } else if (num < 20) { 00561 snprintf(fn, sizeof(fn), "digits/%d",num); 00562 playh = 0; 00563 num = 0; 00564 } else if (num < 100) { 00565 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 00566 num -= ((num / 10) * 10); 00567 } else if (num < 1000) { 00568 hundered = num / 100; 00569 if ( hundered == 1 ) { 00570 snprintf(fn, sizeof(fn), "digits/1sto"); 00571 } else if ( hundered == 2 ) { 00572 snprintf(fn, sizeof(fn), "digits/2ste"); 00573 } else { 00574 res = ast_say_number_full_cz(chan,hundered,ints,language,options,audiofd,ctrlfd); 00575 if (res) 00576 return res; 00577 if (hundered == 3 || hundered == 4) { 00578 snprintf(fn, sizeof(fn), "digits/sta"); 00579 } else if ( hundered > 4 ) { 00580 snprintf(fn, sizeof(fn), "digits/set"); 00581 } 00582 } 00583 num -= (hundered * 100); 00584 } else { /* num > 1000 */ 00585 length = (int)log10(num)+1; 00586 while ( (length % 3 ) != 1 ) { 00587 length--; 00588 } 00589 left = num / (exp10_int(length-1)); 00590 if ( left == 2 ) { 00591 switch (length-1) { 00592 case 9: options = "w"; /* 1,000,000,000 gender female */ 00593 break; 00594 default : options = "m"; /* others are male */ 00595 } 00596 } 00597 if ( left > 1 ) { /* we dont say "one thousand" but only thousand */ 00598 res = ast_say_number_full_cz(chan,left,ints,language,options,audiofd,ctrlfd); 00599 if (res) 00600 return res; 00601 } 00602 if ( left >= 5 ) { /* >= 5 have the same declesion */ 00603 snprintf(fn, sizeof(fn), "digits/5_E%d",length-1); 00604 } else if ( left >= 2 && left <= 4 ) { 00605 snprintf(fn, sizeof(fn), "digits/2-4_E%d",length-1); 00606 } else { /* left == 1 */ 00607 snprintf(fn, sizeof(fn), "digits/1_E%d",length-1); 00608 } 00609 num -= left * (exp10_int(length-1)); 00610 } 00611 if (!res) { 00612 if (!ast_streamfile(chan, fn, language)) { 00613 if ((audiofd > -1) && (ctrlfd > -1)) { 00614 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00615 } else { 00616 res = ast_waitstream(chan, ints); 00617 } 00618 } 00619 ast_stopstream(chan); 00620 } 00621 } 00622 return res; 00623 } 00624 00625 /*! \brief ast_say_number_full_da: Danish syntax */ 00626 /* New files: 00627 In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and" 00628 */ 00629 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) 00630 { 00631 int res = 0; 00632 int playh = 0; 00633 int playa = 0; 00634 int cn = 1; /* +1 = commune; -1 = neuter */ 00635 char fn[256] = ""; 00636 if (!num) 00637 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00638 00639 if (options && !strncasecmp(options, "n",1)) cn = -1; 00640 00641 while (!res && (num || playh || playa )) { 00642 /* The grammar for Danish numbers is the same as for English except 00643 * for the following: 00644 * - 1 exists in both commune ("en", file "1N") and neuter ("et", file "1") 00645 * - numbers 20 through 99 are said in reverse order, i.e. 21 is 00646 * "one-and twenty" and 68 is "eight-and sixty". 00647 * - "million" is different in singular and plural form 00648 * - numbers > 1000 with zero as the third digit from last have an 00649 * "and" before the last two digits, i.e. 2034 is "two thousand and 00650 * four-and thirty" and 1000012 is "one million and twelve". 00651 */ 00652 if (num < 0) { 00653 snprintf(fn, sizeof(fn), "digits/minus"); 00654 if ( num > INT_MIN ) { 00655 num = -num; 00656 } else { 00657 num = 0; 00658 } 00659 } else if (playh) { 00660 snprintf(fn, sizeof(fn), "digits/hundred"); 00661 playh = 0; 00662 } else if (playa) { 00663 snprintf(fn, sizeof(fn), "digits/and"); 00664 playa = 0; 00665 } else if (num == 1 && cn == -1) { 00666 snprintf(fn, sizeof(fn), "digits/1N"); 00667 num = 0; 00668 } else if (num < 20) { 00669 snprintf(fn, sizeof(fn), "digits/%d", num); 00670 num = 0; 00671 } else if (num < 100) { 00672 int ones = num % 10; 00673 if (ones) { 00674 snprintf(fn, sizeof(fn), "digits/%d-and", ones); 00675 num -= ones; 00676 } else { 00677 snprintf(fn, sizeof(fn), "digits/%d", num); 00678 num = 0; 00679 } 00680 } else { 00681 if (num < 1000) { 00682 int hundreds = num / 100; 00683 if (hundreds == 1) 00684 snprintf(fn, sizeof(fn), "digits/1N"); 00685 else 00686 snprintf(fn, sizeof(fn), "digits/%d", (num / 100)); 00687 00688 playh++; 00689 num -= 100 * hundreds; 00690 if (num) 00691 playa++; 00692 00693 } else { 00694 if (num < 1000000) { 00695 res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd); 00696 if (res) 00697 return res; 00698 num = num % 1000; 00699 snprintf(fn, sizeof(fn), "digits/thousand"); 00700 } else { 00701 if (num < 1000000000) { 00702 int millions = num / 1000000; 00703 res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd); 00704 if (res) 00705 return res; 00706 if (millions == 1) 00707 snprintf(fn, sizeof(fn), "digits/million"); 00708 else 00709 snprintf(fn, sizeof(fn), "digits/millions"); 00710 num = num % 1000000; 00711 } else { 00712 if (option_debug) 00713 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00714 res = -1; 00715 } 00716 } 00717 if (num && num < 100) 00718 playa++; 00719 } 00720 } 00721 if (!res) { 00722 if (!ast_streamfile(chan, fn, language)) { 00723 if ((audiofd > -1) && (ctrlfd > -1)) 00724 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00725 else 00726 res = ast_waitstream(chan, ints); 00727 } 00728 ast_stopstream(chan); 00729 } 00730 } 00731 return res; 00732 } 00733 00734 /*! \brief ast_say_number_full_de: German syntax */ 00735 /* New files: 00736 In addition to English, the following sounds are required: 00737 "millions" 00738 "1-and" through "9-and" 00739 "1F" (eine) 00740 "1N" (ein) 00741 NB "1" is recorded as 'eins' 00742 */ 00743 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) 00744 { 00745 int res = 0, t = 0; 00746 int mf = 1; /* +1 = male and neuter; -1 = female */ 00747 char fn[256] = ""; 00748 char fna[256] = ""; 00749 if (!num) 00750 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00751 00752 if (options && (!strncasecmp(options, "f",1))) 00753 mf = -1; 00754 00755 while (!res && num) { 00756 /* The grammar for German numbers is the same as for English except 00757 * for the following: 00758 * - numbers 20 through 99 are said in reverse order, i.e. 21 is 00759 * "one-and twenty" and 68 is "eight-and sixty". 00760 * - "one" varies according to gender 00761 * - 100 is 'hundert', however all other instances are 'ein hundert' 00762 * - 1000 is 'tausend', however all other instances are 'ein tausend' 00763 * - 1000000 is always 'eine million' 00764 * - "million" is different in singular and plural form 00765 */ 00766 if (num < 0) { 00767 snprintf(fn, sizeof(fn), "digits/minus"); 00768 if ( num > INT_MIN ) { 00769 num = -num; 00770 } else { 00771 num = 0; 00772 } 00773 } else if (num < 100 && t) { 00774 snprintf(fn, sizeof(fn), "digits/and"); 00775 t = 0; 00776 } else if (num == 1 && mf == -1) { 00777 snprintf(fn, sizeof(fn), "digits/%dF", num); 00778 num = 0; 00779 } else if (num < 20) { 00780 snprintf(fn, sizeof(fn), "digits/%d", num); 00781 num = 0; 00782 } else if (num < 100) { 00783 int ones = num % 10; 00784 if (ones) { 00785 snprintf(fn, sizeof(fn), "digits/%d-and", ones); 00786 num -= ones; 00787 } else { 00788 snprintf(fn, sizeof(fn), "digits/%d", num); 00789 num = 0; 00790 } 00791 } else if (num == 100 && t == 0) { 00792 snprintf(fn, sizeof(fn), "digits/hundred"); 00793 num = 0; 00794 } else if (num < 1000) { 00795 int hundreds = num / 100; 00796 num = num % 100; 00797 if (hundreds == 1) { 00798 snprintf(fn, sizeof(fn), "digits/1N"); 00799 } else { 00800 snprintf(fn, sizeof(fn), "digits/%d", hundreds); 00801 } 00802 snprintf(fna, sizeof(fna), "digits/hundred"); 00803 t = 1; 00804 } else if (num == 1000 && t == 0) { 00805 snprintf(fn, sizeof(fn), "digits/thousand"); 00806 num = 0; 00807 } else if (num < 1000000) { 00808 int thousands = num / 1000; 00809 num = num % 1000; 00810 t = 1; 00811 if (thousands == 1) { 00812 snprintf(fn, sizeof(fn), "digits/1N"); 00813 snprintf(fna, sizeof(fna), "digits/thousand"); 00814 } else { 00815 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd); 00816 if (res) 00817 return res; 00818 snprintf(fn, sizeof(fn), "digits/thousand"); 00819 } 00820 } else if (num < 1000000000) { 00821 int millions = num / 1000000; 00822 num = num % 1000000; 00823 t = 1; 00824 if (millions == 1) { 00825 snprintf(fn, sizeof(fn), "digits/1F"); 00826 snprintf(fna, sizeof(fna), "digits/million"); 00827 } else { 00828 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd); 00829 if (res) 00830 return res; 00831 snprintf(fn, sizeof(fn), "digits/millions"); 00832 } 00833 } else if (num <= INT_MAX) { 00834 int billions = num / 1000000000; 00835 num = num % 1000000000; 00836 t = 1; 00837 if (billions == 1) { 00838 snprintf(fn, sizeof(fn), "digits/1F"); 00839 snprintf(fna, sizeof(fna), "digits/milliard"); 00840 } else { 00841 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd); 00842 if (res) { 00843 return res; 00844 } 00845 snprintf(fn, sizeof(fn), "digits/milliards"); 00846 } 00847 } else { 00848 if (option_debug) 00849 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00850 res = -1; 00851 } 00852 if (!res) { 00853 if (!ast_streamfile(chan, fn, language)) { 00854 if ((audiofd > -1) && (ctrlfd > -1)) 00855 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00856 else 00857 res = ast_waitstream(chan, ints); 00858 } 00859 ast_stopstream(chan); 00860 if (!res) { 00861 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) { 00862 if ((audiofd > -1) && (ctrlfd > -1)) 00863 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00864 else 00865 res = ast_waitstream(chan, ints); 00866 } 00867 ast_stopstream(chan); 00868 strcpy(fna, ""); 00869 } 00870 } 00871 } 00872 return res; 00873 } 00874 00875 /*! \brief ast_say_number_full_en_GB: British and Norwegian syntax */ 00876 /* New files: 00877 In addition to American English, the following sounds are required: "and" 00878 */ 00879 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) 00880 { 00881 int res = 0; 00882 int playh = 0; 00883 int playa = 0; 00884 char fn[256] = ""; 00885 if (!num) 00886 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00887 00888 while (!res && (num || playh || playa )) { 00889 if (num < 0) { 00890 snprintf(fn, sizeof(fn), "digits/minus"); 00891 if ( num > INT_MIN ) { 00892 num = -num; 00893 } else { 00894 num = 0; 00895 } 00896 } else if (playh) { 00897 snprintf(fn, sizeof(fn), "digits/hundred"); 00898 playh = 0; 00899 } else if (playa) { 00900 snprintf(fn, sizeof(fn), "digits/and"); 00901 playa = 0; 00902 } else if (num < 20) { 00903 snprintf(fn, sizeof(fn), "digits/%d", num); 00904 num = 0; 00905 } else if (num < 100) { 00906 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 00907 num -= ((num / 10) * 10); 00908 } else if (num < 1000) { 00909 int hundreds = num / 100; 00910 snprintf(fn, sizeof(fn), "digits/%d", (num / 100)); 00911 00912 playh++; 00913 num -= 100 * hundreds; 00914 if (num) 00915 playa++; 00916 } else if (num < 1000000) { 00917 res = ast_say_number_full_en_GB(chan, num / 1000, ints, language, audiofd, ctrlfd); 00918 if (res) 00919 return res; 00920 snprintf(fn, sizeof(fn), "digits/thousand"); 00921 num = num % 1000; 00922 if (num && num < 100) 00923 playa++; 00924 } else if (num < 1000000000) { 00925 int millions = num / 1000000; 00926 res = ast_say_number_full_en_GB(chan, millions, ints, language, audiofd, ctrlfd); 00927 if (res) 00928 return res; 00929 snprintf(fn, sizeof(fn), "digits/million"); 00930 num = num % 1000000; 00931 if (num && num < 100) 00932 playa++; 00933 } else { 00934 if (option_debug) 00935 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00936 res = -1; 00937 } 00938 00939 if (!res) { 00940 if (!ast_streamfile(chan, fn, language)) { 00941 if ((audiofd > -1) && (ctrlfd > -1)) 00942 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00943 else 00944 res = ast_waitstream(chan, ints); 00945 } 00946 ast_stopstream(chan); 00947 } 00948 } 00949 return res; 00950 } 00951 00952 /*! \brief ast_say_number_full_es: Spanish syntax */ 00953 /* New files: 00954 Requires a few new audios: 00955 1F.gsm: feminine 'una' 00956 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 00957 */ 00958 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) 00959 { 00960 int res = 0; 00961 int playa = 0; 00962 int mf = 0; /* +1 = male; -1 = female */ 00963 char fn[256] = ""; 00964 if (!num) 00965 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00966 00967 if (options) { 00968 if (!strncasecmp(options, "f",1)) 00969 mf = -1; 00970 else if (!strncasecmp(options, "m", 1)) 00971 mf = 1; 00972 } 00973 00974 while (!res && num) { 00975 if (num < 0) { 00976 snprintf(fn, sizeof(fn), "digits/minus"); 00977 if ( num > INT_MIN ) { 00978 num = -num; 00979 } else { 00980 num = 0; 00981 } 00982 } else if (playa) { 00983 snprintf(fn, sizeof(fn), "digits/and"); 00984 playa = 0; 00985 } else if (num == 1) { 00986 if (mf < 0) 00987 snprintf(fn, sizeof(fn), "digits/%dF", num); 00988 else if (mf > 0) 00989 snprintf(fn, sizeof(fn), "digits/%dM", num); 00990 else 00991 snprintf(fn, sizeof(fn), "digits/%d", num); 00992 num = 0; 00993 } else if (num < 31) { 00994 snprintf(fn, sizeof(fn), "digits/%d", num); 00995 num = 0; 00996 } else if (num < 100) { 00997 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10); 00998 num -= ((num/10)*10); 00999 if (num) 01000 playa++; 01001 } else if (num == 100) { 01002 snprintf(fn, sizeof(fn), "digits/100"); 01003 num = 0; 01004 } else if (num < 200) { 01005 snprintf(fn, sizeof(fn), "digits/100-and"); 01006 num -= 100; 01007 } else { 01008 if (num < 1000) { 01009 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100); 01010 num -= ((num/100)*100); 01011 } else if (num < 2000) { 01012 num = num % 1000; 01013 snprintf(fn, sizeof(fn), "digits/thousand"); 01014 } else { 01015 if (num < 1000000) { 01016 res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd); 01017 if (res) 01018 return res; 01019 num = num % 1000; 01020 snprintf(fn, sizeof(fn), "digits/thousand"); 01021 } else { 01022 if (num < 2147483640) { 01023 if ((num/1000000) == 1) { 01024 res = ast_say_number_full_es(chan, num / 1000000, ints, language, "M", audiofd, ctrlfd); 01025 if (res) 01026 return res; 01027 snprintf(fn, sizeof(fn), "digits/million"); 01028 } else { 01029 res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd); 01030 if (res) 01031 return res; 01032 snprintf(fn, sizeof(fn), "digits/millions"); 01033 } 01034 num = num % 1000000; 01035 } else { 01036 if (option_debug) 01037 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01038 res = -1; 01039 } 01040 } 01041 } 01042 } 01043 01044 if (!res) { 01045 if (!ast_streamfile(chan, fn, language)) { 01046 if ((audiofd > -1) && (ctrlfd > -1)) 01047 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01048 else 01049 res = ast_waitstream(chan, ints); 01050 } 01051 ast_stopstream(chan); 01052 01053 } 01054 01055 } 01056 return res; 01057 } 01058 01059 /*! \brief ast_say_number_full_fr: French syntax */ 01060 /* Extra sounds needed: 01061 1F: feminin 'une' 01062 et: 'and' */ 01063 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) 01064 { 01065 int res = 0; 01066 int playh = 0; 01067 int playa = 0; 01068 int mf = 1; /* +1 = male; -1 = female */ 01069 char fn[256] = ""; 01070 if (!num) 01071 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01072 01073 if (options && !strncasecmp(options, "f",1)) 01074 mf = -1; 01075 01076 while (!res && (num || playh || playa)) { 01077 if (num < 0) { 01078 snprintf(fn, sizeof(fn), "digits/minus"); 01079 if ( num > INT_MIN ) { 01080 num = -num; 01081 } else { 01082 num = 0; 01083 } 01084 } else if (playh) { 01085 snprintf(fn, sizeof(fn), "digits/hundred"); 01086 playh = 0; 01087 } else if (playa) { 01088 snprintf(fn, sizeof(fn), "digits/et"); 01089 playa = 0; 01090 } else if (num == 1) { 01091 if (mf < 0) 01092 snprintf(fn, sizeof(fn), "digits/%dF", num); 01093 else 01094 snprintf(fn, sizeof(fn), "digits/%d", num); 01095 num = 0; 01096 } else if (num < 21) { 01097 snprintf(fn, sizeof(fn), "digits/%d", num); 01098 num = 0; 01099 } else if (num < 70) { 01100 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10); 01101 if ((num % 10) == 1) playa++; 01102 num = num % 10; 01103 } else if (num < 80) { 01104 snprintf(fn, sizeof(fn), "digits/60"); 01105 if ((num % 10) == 1) playa++; 01106 num = num - 60; 01107 } else if (num < 100) { 01108 snprintf(fn, sizeof(fn), "digits/80"); 01109 num = num - 80; 01110 } else if (num < 200) { 01111 snprintf(fn, sizeof(fn), "digits/hundred"); 01112 num = num - 100; 01113 } else if (num < 1000) { 01114 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 01115 playh++; 01116 num = num % 100; 01117 } else if (num < 2000) { 01118 snprintf(fn, sizeof(fn), "digits/thousand"); 01119 num = num - 1000; 01120 } else if (num < 1000000) { 01121 res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd); 01122 if (res) 01123 return res; 01124 snprintf(fn, sizeof(fn), "digits/thousand"); 01125 num = num % 1000; 01126 } else if (num < 1000000000) { 01127 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd); 01128 if (res) 01129 return res; 01130 snprintf(fn, sizeof(fn), "digits/million"); 01131 num = num % 1000000; 01132 } else { 01133 if (option_debug) 01134 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01135 res = -1; 01136 } 01137 if (!res) { 01138 if (!ast_streamfile(chan, fn, language)) { 01139 if ((audiofd > -1) && (ctrlfd > -1)) 01140 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01141 else 01142 res = ast_waitstream(chan, ints); 01143 } 01144 ast_stopstream(chan); 01145 } 01146 } 01147 return res; 01148 } 01149 01150 01151 01152 /*! \brief ast_say_number_full_he: Hebrew syntax */ 01153 /* Extra sounds needed: 01154 1F: feminin 'one' 01155 ve: 'and' 01156 1hundred: 1 hundred 01157 2hundred: 2 hundreds 01158 2thousands: 2 thousand 01159 thousands: plural of 'thousand' 01160 3sF 'Smichut forms (female) 01161 4sF 01162 5sF 01163 6sF 01164 7sF 01165 8sF 01166 9sF 01167 3s 'Smichut' forms (male) 01168 4s 01169 5s 01170 6s 01171 7s 01172 9s 01173 10s 01174 11s 01175 12s 01176 13s 01177 14s 01178 15s 01179 16s 01180 17s 01181 18s 01182 19s 01183 01184 TODO: 've' should sometimed be 'hu': 01185 * before 'shtaym' (2, F) 01186 * before 'shnaym' (2, M) 01187 * before 'shlosha' (3, M) 01188 * before 'shmone' (8, M) 01189 * before 'shlosim' (30) 01190 * before 'shmonim' (80) 01191 01192 What about: 01193 'sheva' (7, F)? 01194 'tesha' (9, F)? 01195 */ 01196 #define SAY_NUM_BUF_SIZE 256 01197 static int ast_say_number_full_he(struct ast_channel *chan, int num, 01198 const char *ints, const char *language, const char *options, 01199 int audiofd, int ctrlfd) 01200 { 01201 int res = 0; 01202 int state = 0; /* no need to save anything */ 01203 int mf = 1; /* +1 = Masculin; -1 = Feminin */ 01204 char fn[SAY_NUM_BUF_SIZE] = ""; 01205 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: started. " 01206 "num: %d, options=\"%s\"\n", 01207 num, options 01208 ); 01209 if (!num) 01210 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01211 01212 if (options && !strncasecmp(options, "f",1)) 01213 mf = -1; 01214 01215 /* Do we have work to do? */ 01216 while (!res && (num || (state>0) )) { 01217 /* first type of work: play a second sound. In this loop 01218 * we can only play one sound file at a time. Thus playing 01219 * a second one requires repeating the loop just for the 01220 * second file. The variable 'state' remembers where we were. 01221 * state==0 is the normal mode and it means that we continue 01222 * to check if the number num has yet anything left. 01223 */ 01224 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: num: %d, " 01225 "state=%d, options=\"%s\", mf=%d\n", 01226 num, state, options, mf 01227 ); 01228 if (state==1) { 01229 snprintf(fn, sizeof(fn), "digits/hundred"); 01230 state = 0; 01231 } else if (state==2) { 01232 snprintf(fn, sizeof(fn), "digits/ve"); 01233 state = 0; 01234 } else if (state==3) { 01235 snprintf(fn, sizeof(fn), "digits/thousands"); 01236 state=0; 01237 } else if (num <21) { 01238 if (mf < 0) 01239 snprintf(fn, sizeof(fn), "digits/%dF", num); 01240 else 01241 snprintf(fn, sizeof(fn), "digits/%d", num); 01242 num = 0; 01243 } else if (num < 100) { 01244 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10); 01245 num = num % 10; 01246 if (num>0) state=2; 01247 } else if (num < 200) { 01248 snprintf(fn, sizeof(fn), "digits/1hundred"); 01249 num = num - 100; 01250 state=2; 01251 } else if (num < 300) { 01252 snprintf(fn, sizeof(fn), "digits/2hundred"); 01253 num = num - 200; 01254 state=2; 01255 } else if (num < 1000) { 01256 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 01257 state=1; 01258 num = num % 100; 01259 } else if (num < 2000) { 01260 snprintf(fn, sizeof(fn), "digits/thousand"); 01261 num = num - 1000; 01262 } else if (num < 3000) { 01263 snprintf(fn, sizeof(fn), "digits/2thousand"); 01264 num = num - 2000; 01265 if (num>0) state=2; 01266 } else if (num < 20000) { 01267 snprintf(fn, sizeof(fn), "digits/%ds",(num/1000)); 01268 num = num % 1000; 01269 state=3; 01270 } else if (num < 1000000) { 01271 res = ast_say_number_full_he(chan, num / 1000, ints, language, options, audiofd, ctrlfd); 01272 if (res) 01273 return res; 01274 snprintf(fn, sizeof(fn), "digits/thousand"); 01275 num = num % 1000; 01276 } else if (num < 1000000000) { 01277 res = ast_say_number_full_he(chan, num / 1000000, ints, language, options, audiofd, ctrlfd); 01278 if (res) 01279 return res; 01280 snprintf(fn, sizeof(fn), "digits/million"); 01281 num = num % 1000000; 01282 } else { 01283 if (option_debug) 01284 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01285 res = -1; 01286 } 01287 if (!res) { 01288 if (!ast_streamfile(chan, fn, language)) { 01289 if ((audiofd > -1) && (ctrlfd > -1)) 01290 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01291 else 01292 res = ast_waitstream(chan, ints); 01293 } 01294 ast_stopstream(chan); 01295 } 01296 } 01297 return res; 01298 } 01299 01300 /*! \brief ast_say_number_full_it: Italian */ 01301 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) 01302 { 01303 int res = 0; 01304 int playh = 0; 01305 int tempnum = 0; 01306 char fn[256] = ""; 01307 01308 if (!num) 01309 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01310 01311 /* 01312 Italian support 01313 01314 Like english, numbers up to 20 are a single 'word', and others 01315 compound, but with exceptions. 01316 For example 21 is not twenty-one, but there is a single word in 'it'. 01317 Idem for 28 (ie when a the 2nd part of a compund number 01318 starts with a vowel) 01319 01320 There are exceptions also for hundred, thousand and million. 01321 In english 100 = one hundred, 200 is two hundred. 01322 In italian 100 = cento , like to say hundred (without one), 01323 200 and more are like english. 01324 01325 Same applies for thousand: 01326 1000 is one thousand in en, 2000 is two thousand. 01327 In it we have 1000 = mille , 2000 = 2 mila 01328 01329 For million(s) we use the plural, if more than one 01330 Also, one million is abbreviated in it, like on-million, 01331 or 'un milione', not 'uno milione'. 01332 So the right file is provided. 01333 */ 01334 01335 while (!res && (num || playh)) { 01336 if (num < 0) { 01337 snprintf(fn, sizeof(fn), "digits/minus"); 01338 if ( num > INT_MIN ) { 01339 num = -num; 01340 } else { 01341 num = 0; 01342 } 01343 } else if (playh) { 01344 snprintf(fn, sizeof(fn), "digits/hundred"); 01345 playh = 0; 01346 } else if (num < 20) { 01347 snprintf(fn, sizeof(fn), "digits/%d", num); 01348 num = 0; 01349 } else if (num == 21) { 01350 snprintf(fn, sizeof(fn), "digits/%d", num); 01351 num = 0; 01352 } else if (num == 28) { 01353 snprintf(fn, sizeof(fn), "digits/%d", num); 01354 num = 0; 01355 } else if (num == 31) { 01356 snprintf(fn, sizeof(fn), "digits/%d", num); 01357 num = 0; 01358 } else if (num == 38) { 01359 snprintf(fn, sizeof(fn), "digits/%d", num); 01360 num = 0; 01361 } else if (num == 41) { 01362 snprintf(fn, sizeof(fn), "digits/%d", num); 01363 num = 0; 01364 } else if (num == 48) { 01365 snprintf(fn, sizeof(fn), "digits/%d", num); 01366 num = 0; 01367 } else if (num == 51) { 01368 snprintf(fn, sizeof(fn), "digits/%d", num); 01369 num = 0; 01370 } else if (num == 58) { 01371 snprintf(fn, sizeof(fn), "digits/%d", num); 01372 num = 0; 01373 } else if (num == 61) { 01374 snprintf(fn, sizeof(fn), "digits/%d", num); 01375 num = 0; 01376 } else if (num == 68) { 01377 snprintf(fn, sizeof(fn), "digits/%d", num); 01378 num = 0; 01379 } else if (num == 71) { 01380 snprintf(fn, sizeof(fn), "digits/%d", num); 01381 num = 0; 01382 } else if (num == 78) { 01383 snprintf(fn, sizeof(fn), "digits/%d", num); 01384 num = 0; 01385 } else if (num == 81) { 01386 snprintf(fn, sizeof(fn), "digits/%d", num); 01387 num = 0; 01388 } else if (num == 88) { 01389 snprintf(fn, sizeof(fn), "digits/%d", num); 01390 num = 0; 01391 } else if (num == 91) { 01392 snprintf(fn, sizeof(fn), "digits/%d", num); 01393 num = 0; 01394 } else if (num == 98) { 01395 snprintf(fn, sizeof(fn), "digits/%d", num); 01396 num = 0; 01397 } else if (num < 100) { 01398 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 01399 num -= ((num / 10) * 10); 01400 } else { 01401 if (num < 1000) { 01402 if ((num / 100) > 1) { 01403 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 01404 playh++; 01405 } else { 01406 snprintf(fn, sizeof(fn), "digits/hundred"); 01407 } 01408 num -= ((num / 100) * 100); 01409 } else { 01410 if (num < 1000000) { /* 1,000,000 */ 01411 if ((num/1000) > 1) 01412 res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd); 01413 if (res) 01414 return res; 01415 tempnum = num; 01416 num = num % 1000; 01417 if ((tempnum / 1000) < 2) 01418 snprintf(fn, sizeof(fn), "digits/thousand"); 01419 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */ 01420 snprintf(fn, sizeof(fn), "digits/thousands"); 01421 } else { 01422 if (num < 1000000000) { /* 1,000,000,000 */ 01423 if ((num / 1000000) > 1) 01424 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd); 01425 if (res) 01426 return res; 01427 tempnum = num; 01428 num = num % 1000000; 01429 if ((tempnum / 1000000) < 2) 01430 snprintf(fn, sizeof(fn), "digits/million"); 01431 else 01432 snprintf(fn, sizeof(fn), "digits/millions"); 01433 } else { 01434 if (option_debug) 01435 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01436 res = -1; 01437 } 01438 } 01439 } 01440 } 01441 if (!res) { 01442 if (!ast_streamfile(chan, fn, language)) { 01443 if ((audiofd > -1) && (ctrlfd > -1)) 01444 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01445 else 01446 res = ast_waitstream(chan, ints); 01447 } 01448 ast_stopstream(chan); 01449 } 01450 } 01451 return res; 01452 } 01453 01454 /*! \brief ast_say_number_full_nl: dutch syntax */ 01455 /* New files: digits/nl-en 01456 */ 01457 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) 01458 { 01459 int res = 0; 01460 int playh = 0; 01461 int units = 0; 01462 char fn[256] = ""; 01463 if (!num) 01464 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01465 while (!res && (num || playh )) { 01466 if (num < 0) { 01467 snprintf(fn, sizeof(fn), "digits/minus"); 01468 if ( num > INT_MIN ) { 01469 num = -num; 01470 } else { 01471 num = 0; 01472 } 01473 } else if (playh) { 01474 snprintf(fn, sizeof(fn), "digits/hundred"); 01475 playh = 0; 01476 } else if (num < 20) { 01477 snprintf(fn, sizeof(fn), "digits/%d", num); 01478 num = 0; 01479 } else if (num < 100) { 01480 units = num % 10; 01481 if (units > 0) { 01482 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd); 01483 if (res) 01484 return res; 01485 num = num - units; 01486 snprintf(fn, sizeof(fn), "digits/nl-en"); 01487 } else { 01488 snprintf(fn, sizeof(fn), "digits/%d", num - units); 01489 num = 0; 01490 } 01491 } else { 01492 if (num < 1000) { 01493 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 01494 playh++; 01495 num -= ((num / 100) * 100); 01496 } else { 01497 if (num < 1000000) { /* 1,000,000 */ 01498 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd); 01499 if (res) 01500 return res; 01501 num = num % 1000; 01502 snprintf(fn, sizeof(fn), "digits/thousand"); 01503 } else { 01504 if (num < 1000000000) { /* 1,000,000,000 */ 01505 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd); 01506 if (res) 01507 return res; 01508 num = num % 1000000; 01509 snprintf(fn, sizeof(fn), "digits/million"); 01510 } else { 01511 if (option_debug) 01512 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01513 res = -1; 01514 } 01515 } 01516 } 01517 } 01518 01519 if (!res) { 01520 if (!ast_streamfile(chan, fn, language)) { 01521 if ((audiofd > -1) && (ctrlfd > -1)) 01522 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01523 else 01524 res = ast_waitstream(chan, ints); 01525 } 01526 ast_stopstream(chan); 01527 } 01528 } 01529 return res; 01530 } 01531 01532 /*! \brief ast_say_number_full_no: Norwegian syntax */ 01533 /* New files: 01534 In addition to American English, the following sounds are required: "and", "1N" 01535 */ 01536 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) 01537 { 01538 int res = 0; 01539 int playh = 0; 01540 int playa = 0; 01541 int cn = 1; /* +1 = commune; -1 = neuter */ 01542 char fn[256] = ""; 01543 01544 if (!num) 01545 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01546 01547 if (options && !strncasecmp(options, "n",1)) cn = -1; 01548 01549 while (!res && (num || playh || playa )) { 01550 /* The grammar for Norwegian numbers is the same as for English except 01551 * for the following: 01552 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N") 01553 * "and" before the last two digits, i.e. 2034 is "two thousand and 01554 * thirty-four" and 1000012 is "one million and twelve". 01555 */ 01556 if (num < 0) { 01557 snprintf(fn, sizeof(fn), "digits/minus"); 01558 if ( num > INT_MIN ) { 01559 num = -num; 01560 } else { 01561 num = 0; 01562 } 01563 } else if (playh) { 01564 snprintf(fn, sizeof(fn), "digits/hundred"); 01565 playh = 0; 01566 } else if (playa) { 01567 snprintf(fn, sizeof(fn), "digits/and"); 01568 playa = 0; 01569 } else if (num == 1 && cn == -1) { 01570 snprintf(fn, sizeof(fn), "digits/1N"); 01571 num = 0; 01572 } else if (num < 20) { 01573 snprintf(fn, sizeof(fn), "digits/%d", num); 01574 num = 0; 01575 } else if (num < 100) { 01576 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 01577 num -= ((num / 10) * 10); 01578 } else if (num < 1000) { 01579 int hundreds = num / 100; 01580 if (hundreds == 1) 01581 snprintf(fn, sizeof(fn), "digits/1N"); 01582 else 01583 snprintf(fn, sizeof(fn), "digits/%d", (num / 100)); 01584 01585 playh++; 01586 num -= 100 * hundreds; 01587 if (num) 01588 playa++; 01589 } else if (num < 1000000) { 01590 res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd); 01591 if (res) 01592 return res; 01593 snprintf(fn, sizeof(fn), "digits/thousand"); 01594 num = num % 1000; 01595 if (num && num < 100) 01596 playa++; 01597 } else if (num < 1000000000) { 01598 int millions = num / 1000000; 01599 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd); 01600 if (res) 01601 return res; 01602 snprintf(fn, sizeof(fn), "digits/million"); 01603 num = num % 1000000; 01604 if (num && num < 100) 01605 playa++; 01606 } else { 01607 if (option_debug) 01608 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01609 res = -1; 01610 } 01611 01612 if (!res) { 01613 if (!ast_streamfile(chan, fn, language)) { 01614 if ((audiofd > -1) && (ctrlfd > -1)) 01615 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01616 else 01617 res = ast_waitstream(chan, ints); 01618 } 01619 ast_stopstream(chan); 01620 } 01621 } 01622 return res; 01623 } 01624 01625 typedef struct { 01626 char *separator_dziesiatek; 01627 char *cyfry[10]; 01628 char *cyfry2[10]; 01629 char *setki[10]; 01630 char *dziesiatki[10]; 01631 char *nastki[10]; 01632 char *rzedy[3][3]; 01633 } odmiana; 01634 01635 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad) 01636 { 01637 if (rzad==0) 01638 return ""; 01639 01640 if (i==1) 01641 return odm->rzedy[rzad - 1][0]; 01642 if ((i > 21 || i < 11) && i%10 > 1 && i%10 < 5) 01643 return odm->rzedy[rzad - 1][1]; 01644 else 01645 return odm->rzedy[rzad - 1][2]; 01646 } 01647 01648 static char* pl_append(char* buffer, char* str) 01649 { 01650 strcpy(buffer, str); 01651 buffer += strlen(str); 01652 return buffer; 01653 } 01654 01655 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn) 01656 { 01657 char file_name[255] = "digits/"; 01658 strcat(file_name, fn); 01659 if (option_debug) 01660 ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name); 01661 if (!ast_streamfile(chan, file_name, language)) { 01662 if ((audiofd > -1) && (ctrlfd > -1)) 01663 ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01664 else 01665 ast_waitstream(chan, ints); 01666 } 01667 ast_stopstream(chan); 01668 } 01669 01670 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i) 01671 { 01672 /* Initialise variables to allow compilation on Debian-stable, etc */ 01673 int m1000E6 = 0; 01674 int i1000E6 = 0; 01675 int m1000E3 = 0; 01676 int i1000E3 = 0; 01677 int m1000 = 0; 01678 int i1000 = 0; 01679 int m100 = 0; 01680 int i100 = 0; 01681 01682 if (i == 0 && rzad > 0) { 01683 return; 01684 } 01685 if (i == 0) { 01686 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]); 01687 return; 01688 } 01689 01690 m1000E6 = i % 1000000000; 01691 i1000E6 = i / 1000000000; 01692 01693 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6); 01694 01695 m1000E3 = m1000E6 % 1000000; 01696 i1000E3 = m1000E6 / 1000000; 01697 01698 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3); 01699 01700 m1000 = m1000E3 % 1000; 01701 i1000 = m1000E3 / 1000; 01702 01703 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000); 01704 01705 m100 = m1000 % 100; 01706 i100 = m1000 / 100; 01707 01708 if (i100>0) 01709 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]); 01710 01711 if ( m100 > 0 && m100 <=9 ) { 01712 if (m1000>0) 01713 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]); 01714 else 01715 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]); 01716 } else if (m100 % 10 == 0) { 01717 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]); 01718 } else if (m100 <= 19 ) { 01719 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]); 01720 } else if (m100 != 0) { 01721 if (odm->separator_dziesiatek[0]==' ') { 01722 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]); 01723 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]); 01724 } else { 01725 char buf[10]; 01726 char *b = buf; 01727 b = pl_append(b, odm->dziesiatki[m100 / 10]); 01728 b = pl_append(b, odm->separator_dziesiatek); 01729 b = pl_append(b, odm->cyfry2[m100 % 10]); 01730 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf); 01731 } 01732 } 01733 01734 if (rzad > 0) { 01735 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad)); 01736 } 01737 } 01738 01739 /* ast_say_number_full_pl: Polish syntax */ 01740 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) 01741 /* 01742 Sounds needed: 01743 0 zero 01744 1 jeden 01745 10 dziesiec 01746 100 sto 01747 1000 tysiac 01748 1000000 milion 01749 1000000000 miliard 01750 1000000000.2 miliardy 01751 1000000000.5 miliardow 01752 1000000.2 miliony 01753 1000000.5 milionow 01754 1000.2 tysiace 01755 1000.5 tysiecy 01756 100m stu 01757 10m dziesieciu 01758 11 jedenascie 01759 11m jedenastu 01760 12 dwanascie 01761 12m dwunastu 01762 13 trzynascie 01763 13m trzynastu 01764 14 czternascie 01765 14m czternastu 01766 15 pietnascie 01767 15m pietnastu 01768 16 szesnascie 01769 16m szesnastu 01770 17 siedemnascie 01771 17m siedemnastu 01772 18 osiemnascie 01773 18m osiemnastu 01774 19 dziewietnascie 01775 19m dziewietnastu 01776 1z jedna 01777 2 dwa 01778 20 dwadziescia 01779 200 dwiescie 01780 200m dwustu 01781 20m dwudziestu 01782 2-1m dwaj 01783 2-2m dwoch 01784 2z dwie 01785 3 trzy 01786 30 trzydziesci 01787 300 trzysta 01788 300m trzystu 01789 30m trzydziestu 01790 3-1m trzej 01791 3-2m trzech 01792 4 cztery 01793 40 czterdziesci 01794 400 czterysta 01795 400m czterystu 01796 40m czterdziestu 01797 4-1m czterej 01798 4-2m czterech 01799 5 piec 01800 50 piecdziesiat 01801 500 piecset 01802 500m pieciuset 01803 50m piedziesieciu 01804 5m pieciu 01805 6 szesc 01806 60 szescdziesiat 01807 600 szescset 01808 600m szesciuset 01809 60m szescdziesieciu 01810 6m szesciu 01811 7 siedem 01812 70 siedemdziesiat 01813 700 siedemset 01814 700m siedmiuset 01815 70m siedemdziesieciu 01816 7m siedmiu 01817 8 osiem 01818 80 osiemdziesiat 01819 800 osiemset 01820 800m osmiuset 01821 80m osiemdziesieciu 01822 8m osmiu 01823 9 dziewiec 01824 90 dziewiecdziesiat 01825 900 dziewiecset 01826 900m dziewieciuset 01827 90m dziewiedziesieciu 01828 9m dziewieciu 01829 and combinations of eg.: 20_1, 30m_3m, etc... 01830 01831 */ 01832 { 01833 char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"}; 01834 01835 char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"}; 01836 01837 char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m", /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"}; 01838 01839 char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"}; 01840 01841 char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"}; 01842 01843 char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"}; 01844 01845 char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"}; 01846 01847 char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"}; 01848 01849 char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"}; 01850 01851 char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"}; 01852 01853 char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"}; 01854 01855 char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"}; 01856 01857 char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}}; 01858 01859 /* Initialise variables to allow compilation on Debian-stable, etc */ 01860 odmiana *o; 01861 01862 static odmiana *odmiana_nieosobowa = NULL; 01863 static odmiana *odmiana_meska = NULL; 01864 static odmiana *odmiana_zenska = NULL; 01865 01866 if (odmiana_nieosobowa == NULL) { 01867 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana)); 01868 01869 odmiana_nieosobowa->separator_dziesiatek = " "; 01870 01871 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry)); 01872 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry)); 01873 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki)); 01874 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki)); 01875 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki)); 01876 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy)); 01877 } 01878 01879 if (odmiana_zenska == NULL) { 01880 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana)); 01881 01882 odmiana_zenska->separator_dziesiatek = " "; 01883 01884 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry)); 01885 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry)); 01886 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki)); 01887 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki)); 01888 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki)); 01889 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy)); 01890 } 01891 01892 if (odmiana_meska == NULL) { 01893 odmiana_meska = (odmiana *) malloc(sizeof(odmiana)); 01894 01895 odmiana_meska->separator_dziesiatek = " "; 01896 01897 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry)); 01898 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry)); 01899 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki)); 01900 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki)); 01901 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki)); 01902 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy)); 01903 } 01904 01905 if (options) { 01906 if (strncasecmp(options, "f", 1) == 0) 01907 o = odmiana_zenska; 01908 else if (strncasecmp(options, "m", 1) == 0) 01909 o = odmiana_meska; 01910 else 01911 o = odmiana_nieosobowa; 01912 } else 01913 o = odmiana_nieosobowa; 01914 01915 powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num); 01916 return 0; 01917 } 01918 01919 /* ast_say_number_full_pt: Portuguese syntax */ 01920 /* Extra sounds needed: */ 01921 /* For feminin all sound files end with F */ 01922 /* 100E for 100+ something */ 01923 /* 1000000S for plural */ 01924 /* pt-e for 'and' */ 01925 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) 01926 { 01927 int res = 0; 01928 int playh = 0; 01929 int mf = 1; /* +1 = male; -1 = female */ 01930 char fn[256] = ""; 01931 01932 if (!num) 01933 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01934 01935 if (options && !strncasecmp(options, "f",1)) 01936 mf = -1; 01937 01938 while (!res && num ) { 01939 if (num < 0) { 01940 snprintf(fn, sizeof(fn), "digits/minus"); 01941 if ( num > INT_MIN ) { 01942 num = -num; 01943 } else { 01944 num = 0; 01945 } 01946 } else if (num < 20) { 01947 if ((num == 1 || num == 2) && (mf < 0)) 01948 snprintf(fn, sizeof(fn), "digits/%dF", num); 01949 else 01950 snprintf(fn, sizeof(fn), "digits/%d", num); 01951 num = 0; 01952 } else if (num < 100) { 01953 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10); 01954 if (num % 10) 01955 playh = 1; 01956 num = num % 10; 01957 } else if (num < 1000) { 01958 if (num == 100) 01959 snprintf(fn, sizeof(fn), "digits/100"); 01960 else if (num < 200) 01961 snprintf(fn, sizeof(fn), "digits/100E"); 01962 else { 01963 if (mf < 0 && num > 199) 01964 snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100); 01965 else 01966 snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100); 01967 if (num % 100) 01968 playh = 1; 01969 } 01970 num = num % 100; 01971 } else if (num < 1000000) { 01972 if (num > 1999) { 01973 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd); 01974 if (res) 01975 return res; 01976 } 01977 snprintf(fn, sizeof(fn), "digits/1000"); 01978 if ((num % 1000) && ((num % 1000) < 100 || !(num % 100))) 01979 playh = 1; 01980 num = num % 1000; 01981 } else if (num < 1000000000) { 01982 res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd ); 01983 if (res) 01984 return res; 01985 if (num < 2000000) 01986 snprintf(fn, sizeof(fn), "digits/1000000"); 01987 else 01988 snprintf(fn, sizeof(fn), "digits/1000000S"); 01989 01990 if ((num % 1000000) && 01991 /* no thousands */ 01992 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) || 01993 /* no hundreds and below */ 01994 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) ) 01995 playh = 1; 01996 num = num % 1000000; 01997 } else { 01998 /* number is too big */ 01999 ast_log(LOG_WARNING, "Number '%d' is too big to say.", num); 02000 res = -1; 02001 } 02002 if (!res) { 02003 if (!ast_streamfile(chan, fn, language)) { 02004 if ((audiofd > -1) && (ctrlfd > -1)) 02005 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02006 else 02007 res = ast_waitstream(chan, ints); 02008 } 02009 ast_stopstream(chan); 02010 } 02011 if (!res && playh) { 02012 res = wait_file(chan, ints, "digits/pt-e", language); 02013 ast_stopstream(chan); 02014 playh = 0; 02015 } 02016 } 02017 return res; 02018 } 02019 02020 /*! \brief ast_say_number_full_se: Swedish syntax */ 02021 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) 02022 { 02023 int res = 0; 02024 int playh = 0; 02025 char fn[256] = ""; 02026 int cn = 1; /* +1 = commune; -1 = neuter */ 02027 if (!num) 02028 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 02029 if (options && !strncasecmp(options, "n",1)) cn = -1; 02030 02031 while (!res && (num || playh)) { 02032 if (num < 0) { 02033 snprintf(fn, sizeof(fn), "digits/minus"); 02034 if ( num > INT_MIN ) { 02035 num = -num; 02036 } else { 02037 num = 0; 02038 } 02039 } else if (playh) { 02040 snprintf(fn, sizeof(fn), "digits/hundred"); 02041 playh = 0; 02042 } else if (num < 20) { 02043 snprintf(fn, sizeof(fn), "digits/%d", num); 02044 num = 0; 02045 } else if (num < 100) { 02046 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 02047 num -= ((num / 10) * 10); 02048 } else if (num == 1 && cn == -1) { /* En eller ett? */ 02049 snprintf(fn, sizeof(fn), "digits/1N"); 02050 num = 0; 02051 } else { 02052 if (num < 1000){ 02053 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 02054 playh++; 02055 num -= ((num / 100) * 100); 02056 } else { 02057 if (num < 1000000) { /* 1,000,000 */ 02058 res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd); 02059 if (res) { 02060 return res; 02061 } 02062 num = num % 1000; 02063 snprintf(fn, sizeof(fn), "digits/thousand"); 02064 } else { 02065 if (num < 1000000000) { /* 1,000,000,000 */ 02066 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd); 02067 if (res) { 02068 return res; 02069 } 02070 num = num % 1000000; 02071 snprintf(fn, sizeof(fn), "digits/million"); 02072 } else { 02073 if (option_debug) 02074 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 02075 res = -1; 02076 } 02077 } 02078 } 02079 } 02080 if (!res) { 02081 if (!ast_streamfile(chan, fn, language)) { 02082 if ((audiofd > -1) && (ctrlfd > -1)) 02083 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02084 else 02085 res = ast_waitstream(chan, ints); 02086 ast_stopstream(chan); 02087 } 02088 } 02089 } 02090 return res; 02091 } 02092 02093 /*! \brief ast_say_number_full_tw: Taiwanese / Chinese syntax */ 02094 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) 02095 { 02096 int res = 0; 02097 int playh = 0; 02098 char fn[256] = ""; 02099 if (!num) 02100 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 02101 02102 while (!res && (num || playh)) { 02103 if (num < 0) { 02104 snprintf(fn, sizeof(fn), "digits/minus"); 02105 if ( num > INT_MIN ) { 02106 num = -num; 02107 } else { 02108 num = 0; 02109 } 02110 } else if (playh) { 02111 snprintf(fn, sizeof(fn), "digits/hundred"); 02112 playh = 0; 02113 } else if (num < 10) { 02114 snprintf(fn, sizeof(fn), "digits/%d", num); 02115 num = 0; 02116 } else if (num < 100) { 02117 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 02118 num -= ((num / 10) * 10); 02119 } else { 02120 if (num < 1000){ 02121 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 02122 playh++; 02123 num -= ((num / 100) * 100); 02124 } else { 02125 if (num < 1000000) { /* 1,000,000 */ 02126 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd); 02127 if (res) 02128 return res; 02129 num = num % 1000; 02130 snprintf(fn, sizeof(fn), "digits/thousand"); 02131 } else { 02132 if (num < 1000000000) { /* 1,000,000,000 */ 02133 res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd); 02134 if (res) 02135 return res; 02136 num = num % 1000000; 02137 snprintf(fn, sizeof(fn), "digits/million"); 02138 } else { 02139 if (option_debug) 02140 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 02141 res = -1; 02142 } 02143 } 02144 } 02145 } 02146 if (!res) { 02147 if (!ast_streamfile(chan, fn, language)) { 02148 if ((audiofd > -1) && (ctrlfd > -1)) 02149 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02150 else 02151 res = ast_waitstream(chan, ints); 02152 } 02153 ast_stopstream(chan); 02154 } 02155 } 02156 return res; 02157 } 02158 02159 02160 /*! \brief determine last digits for thousands/millions (ru) */ 02161 static int get_lastdigits_ru(int num) { 02162 if (num < 20) { 02163 return num; 02164 } else if (num < 100) { 02165 return get_lastdigits_ru(num % 10); 02166 } else if (num < 1000) { 02167 return get_lastdigits_ru(num % 100); 02168 } 02169 return 0; /* number too big */ 02170 } 02171 02172 02173 /*! \brief ast_say_number_full_ru: Russian syntax */ 02174 /*! \brief additional files: 02175 n00.gsm (one hundred, two hundred, ...) 02176 thousand.gsm 02177 million.gsm 02178 thousands-i.gsm (tisyachi) 02179 million-a.gsm (milliona) 02180 thousands.gsm 02181 millions.gsm 02182 1f.gsm (odna) 02183 2f.gsm (dve) 02184 02185 where 'n' from 1 to 9 02186 */ 02187 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) 02188 { 02189 int res = 0; 02190 int lastdigits = 0; 02191 char fn[256] = ""; 02192 if (!num) 02193 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 02194 02195 while (!res && (num)) { 02196 if (num < 0) { 02197 snprintf(fn, sizeof(fn), "digits/minus"); 02198 if ( num > INT_MIN ) { 02199 num = -num; 02200 } else { 02201 num = 0; 02202 } 02203 } else if (num < 20) { 02204 if (options && strlen(options) == 1 && num < 3) { 02205 snprintf(fn, sizeof(fn), "digits/%d%s", num, options); 02206 } else { 02207 snprintf(fn, sizeof(fn), "digits/%d", num); 02208 } 02209 num = 0; 02210 } else if (num < 100) { 02211 snprintf(fn, sizeof(fn), "digits/%d", num - (num % 10)); 02212 num %= 10; 02213 } else if (num < 1000){ 02214 snprintf(fn, sizeof(fn), "digits/%d", num - (num % 100)); 02215 num %= 100; 02216 } else if (num < 1000000) { /* 1,000,000 */ 02217 lastdigits = get_lastdigits_ru(num / 1000); 02218 /* say thousands */ 02219 if (lastdigits < 3) { 02220 res = ast_say_number_full_ru(chan, num / 1000, ints, language, "f", audiofd, ctrlfd); 02221 } else { 02222 res = ast_say_number_full_ru(chan, num / 1000, ints, language, NULL, audiofd, ctrlfd); 02223 } 02224 if (res) 02225 return res; 02226 if (lastdigits == 1) { 02227 snprintf(fn, sizeof(fn), "digits/thousand"); 02228 } else if (lastdigits > 1 && lastdigits < 5) { 02229 snprintf(fn, sizeof(fn), "digits/thousands-i"); 02230 } else { 02231 snprintf(fn, sizeof(fn), "digits/thousands"); 02232 } 02233 num %= 1000; 02234 } else if (num < 1000000000) { /* 1,000,000,000 */ 02235 lastdigits = get_lastdigits_ru(num / 1000000); 02236 /* say millions */ 02237 res = ast_say_number_full_ru(chan, num / 1000000, ints, language, NULL, audiofd, ctrlfd); 02238 if (res) 02239 return res; 02240 if (lastdigits == 1) { 02241 snprintf(fn, sizeof(fn), "digits/million"); 02242 } else if (lastdigits > 1 && lastdigits < 5) { 02243 snprintf(fn, sizeof(fn), "digits/million-a"); 02244 } else { 02245 snprintf(fn, sizeof(fn), "digits/millions"); 02246 } 02247 num %= 1000000; 02248 } else { 02249 if (option_debug) 02250 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 02251 res = -1; 02252 } 02253 if (!res) { 02254 if (!ast_streamfile(chan, fn, language)) { 02255 if ((audiofd > -1) && (ctrlfd > -1)) 02256 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02257 else 02258 res = ast_waitstream(chan, ints); 02259 } 02260 ast_stopstream(chan); 02261 } 02262 } 02263 return res; 02264 } 02265 02266 02267 /*! \brief ast_say_enumeration_full: call language-specific functions */ 02268 /* Called from AGI */ 02269 static int say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd) 02270 { 02271 if (!strcasecmp(language,"en") ) { /* English syntax */ 02272 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd)); 02273 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */ 02274 return(ast_say_enumeration_full_da(chan, num, ints, language, options, audiofd, ctrlfd)); 02275 } else if (!strcasecmp(language, "de") ) { /* German syntax */ 02276 return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd)); 02277 } 02278 02279 /* Default to english */ 02280 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd)); 02281 } 02282 02283 /*! \brief ast_say_enumeration_full_en: English syntax */ 02284 /* This is the default syntax, if no other syntax defined in this file is used */ 02285 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd) 02286 { 02287 int res = 0, t = 0; 02288 char fn[256] = ""; 02289 02290 while (!res && num) { 02291 if (num < 0) { 02292 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */ 02293 if ( num > INT_MIN ) { 02294 num = -num; 02295 } else { 02296 num = 0; 02297 } 02298 } else if (num < 20) { 02299 snprintf(fn, sizeof(fn), "digits/h-%d", num); 02300 num = 0; 02301 } else if (num < 100) { 02302 int tens = num / 10; 02303 num = num % 10; 02304 if (num == 0) { 02305 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10)); 02306 } else { 02307 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10)); 02308 } 02309 } else if (num < 1000) { 02310 int hundreds = num / 100; 02311 num = num % 100; 02312 if (hundreds > 1 || t == 1) { 02313 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd); 02314 } 02315 if (res) 02316 return res; 02317 if (num) { 02318 snprintf(fn, sizeof(fn), "digits/hundred"); 02319 } else { 02320 snprintf(fn, sizeof(fn), "digits/h-hundred"); 02321 } 02322 } else if (num < 1000000) { 02323 int thousands = num / 1000; 02324 num = num % 1000; 02325 if (thousands > 1 || t == 1) { 02326 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd); 02327 } 02328 if (res) 02329 return res; 02330 if (num) { 02331 snprintf(fn, sizeof(fn), "digits/thousand"); 02332 } else { 02333 snprintf(fn, sizeof(fn), "digits/h-thousand"); 02334 } 02335 t = 1; 02336 } else if (num < 1000000000) { 02337 int millions = num / 1000000; 02338 num = num % 1000000; 02339 t = 1; 02340 res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd); 02341 if (res) 02342 return res; 02343 if (num) { 02344 snprintf(fn, sizeof(fn), "digits/million"); 02345 } else { 02346 snprintf(fn, sizeof(fn), "digits/h-million"); 02347 } 02348 } else if (num < INT_MAX) { 02349 int billions = num / 1000000000; 02350 num = num % 1000000000; 02351 t = 1; 02352 res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd); 02353 if (res) 02354 return res; 02355 if (num) { 02356 snprintf(fn, sizeof(fn), "digits/billion"); 02357 } else { 02358 snprintf(fn, sizeof(fn), "digits/h-billion"); 02359 } 02360 } else if (num == INT_MAX) { 02361 snprintf(fn, sizeof(fn), "digits/h-last"); 02362 num = 0; 02363 } else { 02364 if (option_debug) 02365 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 02366 res = -1; 02367 } 02368 02369 if (!res) { 02370 if (!ast_streamfile(chan, fn, language)) { 02371 if ((audiofd > -1) && (ctrlfd > -1)) { 02372 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02373 } else { 02374 res = ast_waitstream(chan, ints); 02375 } 02376 } 02377 ast_stopstream(chan); 02378 } 02379 } 02380 return res; 02381 } 02382 02383 /*! \brief ast_say_enumeration_full_da: Danish syntax */ 02384 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) 02385 { 02386 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */ 02387 int res = 0, t = 0; 02388 char fn[256] = "", fna[256] = ""; 02389 char *gender; 02390 02391 if (options && !strncasecmp(options, "f",1)) { 02392 gender = "F"; 02393 } else if (options && !strncasecmp(options, "n",1)) { 02394 gender = "N"; 02395 } else { 02396 gender = ""; 02397 } 02398 02399 if (!num) 02400 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 02401 02402 while (!res && num) { 02403 if (num < 0) { 02404 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */ 02405 if ( num > INT_MIN ) { 02406 num = -num; 02407 } else { 02408 num = 0; 02409 } 02410 } else if (num < 100 && t) { 02411 snprintf(fn, sizeof(fn), "digits/and"); 02412 t = 0; 02413 } else if (num < 20) { 02414 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender); 02415 num = 0; 02416 } else if (num < 100) { 02417 int ones = num % 10; 02418 if (ones) { 02419 snprintf(fn, sizeof(fn), "digits/%d-and", ones); 02420 num -= ones; 02421 } else { 02422 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender); 02423 num = 0; 02424 } 02425 } else if (num == 100 && t == 0) { 02426 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender); 02427 num = 0; 02428 } else if (num < 1000) { 02429 int hundreds = num / 100; 02430 num = num % 100; 02431 if (hundreds == 1) { 02432 snprintf(fn, sizeof(fn), "digits/1N"); 02433 } else { 02434 snprintf(fn, sizeof(fn), "digits/%d", hundreds); 02435 } 02436 if (num) { 02437 snprintf(fna, sizeof(fna), "digits/hundred"); 02438 } else { 02439 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender); 02440 } 02441 t = 1; 02442 } else if (num < 1000000) { 02443 int thousands = num / 1000; 02444 num = num % 1000; 02445 if (thousands == 1) { 02446 if (num) { 02447 snprintf(fn, sizeof(fn), "digits/1N"); 02448 snprintf(fna, sizeof(fna), "digits/thousand"); 02449 } else { 02450 if (t) { 02451 snprintf(fn, sizeof(fn), "digits/1N"); 02452 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender); 02453 } else { 02454 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender); 02455 } 02456 } 02457 } else { 02458 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd); 02459 if (res) { 02460 return res; 02461 } 02462 if (num) { 02463 snprintf(fn, sizeof(fn), "digits/thousand"); 02464 } else { 02465 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender); 02466 } 02467 } 02468 t = 1; 02469 } else if (num < 1000000000) { 02470 int millions = num / 1000000; 02471 num = num % 1000000; 02472 if (millions == 1) { 02473 if (num) { 02474 snprintf(fn, sizeof(fn), "digits/1F"); 02475 snprintf(fna, sizeof(fna), "digits/million"); 02476 } else { 02477 snprintf(fn, sizeof(fn), "digits/1N"); 02478 snprintf(fna, sizeof(fna), "digits/h-million%s", gender); 02479 } 02480 } else { 02481 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd); 02482 if (res) { 02483 return res; 02484 } 02485 if (num) { 02486 snprintf(fn, sizeof(fn), "digits/millions"); 02487 } else { 02488 snprintf(fn, sizeof(fn), "digits/h-million%s", gender); 02489 } 02490 } 02491 t = 1; 02492 } else if (num < INT_MAX) { 02493 int billions = num / 1000000000; 02494 num = num % 1000000000; 02495 if (billions == 1) { 02496 if (num) { 02497 snprintf(fn, sizeof(fn), "digits/1F"); 02498 snprintf(fna, sizeof(fna), "digits/milliard"); 02499 } else { 02500 snprintf(fn, sizeof(fn), "digits/1N"); 02501 snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender); 02502 } 02503 } else { 02504 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd); 02505 if (res) 02506 return res; 02507 if (num) { 02508 snprintf(fn, sizeof(fna), "digits/milliards"); 02509 } else { 02510 snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender); 02511 } 02512 } 02513 t = 1; 02514 } else if (num == INT_MAX) { 02515 snprintf(fn, sizeof(fn), "digits/h-last%s", gender); 02516 num = 0; 02517 } else { 02518 if (option_debug) 02519 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 02520 res = -1; 02521 } 02522 02523 if (!res) { 02524 if (!ast_streamfile(chan, fn, language)) { 02525 if ((audiofd > -1) && (ctrlfd > -1)) 02526 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02527 else 02528 res = ast_waitstream(chan, ints); 02529 } 02530 ast_stopstream(chan); 02531 if (!res) { 02532 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) { 02533 if ((audiofd > -1) && (ctrlfd > -1)) { 02534 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02535 } else { 02536 res = ast_waitstream(chan, ints); 02537 } 02538 } 02539 ast_stopstream(chan); 02540 strcpy(fna, ""); 02541 } 02542 } 02543 } 02544 return res; 02545 } 02546 02547 /*! \brief ast_say_enumeration_full_de: German syntax */ 02548 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) 02549 { 02550 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */ 02551 int res = 0, t = 0; 02552 char fn[256] = "", fna[256] = ""; 02553 char *gender; 02554 02555 if (options && !strncasecmp(options, "f",1)) { 02556 gender = "F"; 02557 } else if (options && !strncasecmp(options, "n",1)) { 02558 gender = "N"; 02559 } else { 02560 gender = ""; 02561 } 02562 02563 if (!num) 02564 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 02565 02566 while (!res && num) { 02567 if (num < 0) { 02568 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */ 02569 if ( num > INT_MIN ) { 02570 num = -num; 02571 } else { 02572 num = 0; 02573 } 02574 } else if (num < 100 && t) { 02575 snprintf(fn, sizeof(fn), "digits/and"); 02576 t = 0; 02577 } else if (num < 20) { 02578 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender); 02579 num = 0; 02580 } else if (num < 100) { 02581 int ones = num % 10; 02582 if (ones) { 02583 snprintf(fn, sizeof(fn), "digits/%d-and", ones); 02584 num -= ones; 02585 } else { 02586 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender); 02587 num = 0; 02588 } 02589 } else if (num == 100 && t == 0) { 02590 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender); 02591 num = 0; 02592 } else if (num < 1000) { 02593 int hundreds = num / 100; 02594 num = num % 100; 02595 if (hundreds == 1) { 02596 snprintf(fn, sizeof(fn), "digits/1N"); 02597 } else { 02598 snprintf(fn, sizeof(fn), "digits/%d", hundreds); 02599 } 02600 if (num) { 02601 snprintf(fna, sizeof(fna), "digits/hundred"); 02602 } else { 02603 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender); 02604 } 02605 t = 1; 02606 } else if (num < 1000000) { 02607 int thousands = num / 1000; 02608 num = num % 1000; 02609 if (thousands == 1) { 02610 if (num) { 02611 snprintf(fn, sizeof(fn), "digits/1N"); 02612 snprintf(fna, sizeof(fna), "digits/thousand"); 02613 } else { 02614 if (t) { 02615 snprintf(fn, sizeof(fn), "digits/1N"); 02616 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender); 02617 } else { 02618 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender); 02619 } 02620 } 02621 } else { 02622 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd); 02623 if (res) { 02624 return res; 02625 } 02626 if (num) { 02627 snprintf(fn, sizeof(fn), "digits/thousand"); 02628 } else { 02629 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender); 02630 } 02631 } 02632 t = 1; 02633 } else if (num < 1000000000) { 02634 int millions = num / 1000000; 02635 num = num % 1000000; 02636 if (millions == 1) { 02637 if (num) { 02638 snprintf(fn, sizeof(fn), "digits/1F"); 02639 snprintf(fna, sizeof(fna), "digits/million"); 02640 } else { 02641 snprintf(fn, sizeof(fn), "digits/1N"); 02642 snprintf(fna, sizeof(fna), "digits/h-million%s", gender); 02643 } 02644 } else { 02645 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd); 02646 if (res) { 02647 return res; 02648 } 02649 if (num) { 02650 snprintf(fn, sizeof(fn), "digits/millions"); 02651 } else { 02652 snprintf(fn, sizeof(fn), "digits/h-million%s", gender); 02653 } 02654 } 02655 t = 1; 02656 } else if (num < INT_MAX) { 02657 int billions = num / 1000000000; 02658 num = num % 1000000000; 02659 if (billions == 1) { 02660 if (num) { 02661 snprintf(fn, sizeof(fn), "digits/1F"); 02662 snprintf(fna, sizeof(fna), "digits/milliard"); 02663 } else { 02664 snprintf(fn, sizeof(fn), "digits/1N"); 02665 snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender); 02666 } 02667 } else { 02668 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd); 02669 if (res) 02670 return res; 02671 if (num) { 02672 snprintf(fn, sizeof(fna), "digits/milliards"); 02673 } else { 02674 snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender); 02675 } 02676 } 02677 t = 1; 02678 } else if (num == INT_MAX) { 02679 snprintf(fn, sizeof(fn), "digits/h-last%s", gender); 02680 num = 0; 02681 } else { 02682 if (option_debug) 02683 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 02684 res = -1; 02685 } 02686 02687 if (!res) { 02688 if (!ast_streamfile(chan, fn, language)) { 02689 if ((audiofd > -1) && (ctrlfd > -1)) 02690 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02691 else 02692 res = ast_waitstream(chan, ints); 02693 } 02694 ast_stopstream(chan); 02695 if (!res) { 02696 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) { 02697 if ((audiofd > -1) && (ctrlfd > -1)) { 02698 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 02699 } else { 02700 res = ast_waitstream(chan, ints); 02701 } 02702 } 02703 ast_stopstream(chan); 02704 strcpy(fna, ""); 02705 } 02706 } 02707 } 02708 return res; 02709 } 02710 02711 static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 02712 { 02713 if (!strcasecmp(lang, "en") ) { /* English syntax */ 02714 return(ast_say_date_en(chan, t, ints, lang)); 02715 } else if (!strcasecmp(lang, "da") ) { /* Danish syntax */ 02716 return(ast_say_date_da(chan, t, ints, lang)); 02717 } else if (!strcasecmp(lang, "de") ) { /* German syntax */ 02718 return(ast_say_date_de(chan, t, ints, lang)); 02719 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */ 02720 return(ast_say_date_fr(chan, t, ints, lang)); 02721 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 02722 return(ast_say_date_nl(chan, t, ints, lang)); 02723 } else if (!strcasecmp(lang, "pt") || !strcasecmp(lang, "pt_BR")) { /* Portuguese syntax */ 02724 return(ast_say_date_pt(chan, t, ints, lang)); 02725 } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */ 02726 return(ast_say_date_gr(chan, t, ints, lang)); 02727 } 02728 02729 /* Default to English */ 02730 return(ast_say_date_en(chan, t, ints, lang)); 02731 } 02732 02733 /* English syntax */ 02734 int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 02735 { 02736 struct tm tm; 02737 char fn[256]; 02738 int res = 0; 02739 ast_localtime(&t,&tm,NULL); 02740 if (!res) { 02741 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 02742 res = ast_streamfile(chan, fn, lang); 02743 if (!res) 02744 res = ast_waitstream(chan, ints); 02745 } 02746 if (!res) { 02747 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 02748 res = ast_streamfile(chan, fn, lang); 02749 if (!res) 02750 res = ast_waitstream(chan, ints); 02751 } 02752 if (!res) 02753 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); 02754 if (!res) 02755 res = ast_waitstream(chan, ints); 02756 if (!res) 02757 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 02758 return res; 02759 } 02760 02761 /* Danish syntax */ 02762 int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 02763 { 02764 struct tm tm; 02765 char fn[256]; 02766 int res = 0; 02767 ast_localtime(&t,&tm,NULL); 02768 if (!res) { 02769 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 02770 res = ast_streamfile(chan, fn, lang); 02771 if (!res) 02772 res = ast_waitstream(chan, ints); 02773 } 02774 if (!res) 02775 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL); 02776 if (!res) 02777 res = ast_waitstream(chan, ints); 02778 if (!res) { 02779 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 02780 res = ast_streamfile(chan, fn, lang); 02781 if (!res) 02782 res = ast_waitstream(chan, ints); 02783 } 02784 if (!res) { 02785 /* Year */ 02786 int year = tm.tm_year + 1900; 02787 if (year > 1999) { /* year 2000 and later */ 02788 res = ast_say_number(chan, year, ints, lang, (char *) NULL); 02789 } else { 02790 if (year < 1100) { 02791 /* I'm not going to handle 1100 and prior */ 02792 /* We'll just be silent on the year, instead of bombing out. */ 02793 } else { 02794 /* year 1100 to 1999. will anybody need this?!? */ 02795 snprintf(fn,sizeof(fn), "digits/%d", (year / 100) ); 02796 res = wait_file(chan, ints, fn, lang); 02797 if (!res) { 02798 res = wait_file(chan,ints, "digits/hundred", lang); 02799 if (!res && year % 100 != 0) { 02800 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL); 02801 } 02802 } 02803 } 02804 } 02805 } 02806 return res; 02807 } 02808 02809 /* German syntax */ 02810 int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 02811 { 02812 struct tm tm; 02813 char fn[256]; 02814 int res = 0; 02815 ast_localtime(&t,&tm,NULL); 02816 if (!res) { 02817 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 02818 res = ast_streamfile(chan, fn, lang); 02819 if (!res) 02820 res = ast_waitstream(chan, ints); 02821 } 02822 if (!res) 02823 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL); 02824 if (!res) 02825 res = ast_waitstream(chan, ints); 02826 if (!res) { 02827 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 02828 res = ast_streamfile(chan, fn, lang); 02829 if (!res) 02830 res = ast_waitstream(chan, ints); 02831 } 02832 if (!res) { 02833 /* Year */ 02834 int year = tm.tm_year + 1900; 02835 if (year > 1999) { /* year 2000 and later */ 02836 res = ast_say_number(chan, year, ints, lang, (char *) NULL); 02837 } else { 02838 if (year < 1100) { 02839 /* I'm not going to handle 1100 and prior */ 02840 /* We'll just be silent on the year, instead of bombing out. */ 02841 } else { 02842 /* year 1100 to 1999. will anybody need this?!? */ 02843 /* say 1967 as 'neunzehn hundert sieben und sechzig' */ 02844 snprintf(fn,sizeof(fn), "digits/%d", (year / 100) ); 02845 res = wait_file(chan, ints, fn, lang); 02846 if (!res) { 02847 res = wait_file(chan,ints, "digits/hundred", lang); 02848 if (!res && year % 100 != 0) { 02849 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL); 02850 } 02851 } 02852 } 02853 } 02854 } 02855 return res; 02856 } 02857 02858 /* French syntax */ 02859 int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 02860 { 02861 struct tm tm; 02862 char fn[256]; 02863 int res = 0; 02864 ast_localtime(&t,&tm,NULL); 02865 if (!res) { 02866 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 02867 res = ast_streamfile(chan, fn, lang); 02868 if (!res) 02869 res = ast_waitstream(chan, ints); 02870 } 02871 if (!res) 02872 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); 02873 if (!res) 02874 res = ast_waitstream(chan, ints); 02875 if (!res) { 02876 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 02877 res = ast_streamfile(chan, fn, lang); 02878 if (!res) 02879 res = ast_waitstream(chan, ints); 02880 } 02881 if (!res) 02882 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 02883 return res; 02884 } 02885 02886 /* Dutch syntax */ 02887 int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 02888 { 02889 struct tm tm; 02890 char fn[256]; 02891 int res = 0; 02892 ast_localtime(&t,&tm,NULL); 02893 if (!res) { 02894 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 02895 res = ast_streamfile(chan, fn, lang); 02896 if (!res) 02897 res = ast_waitstream(chan, ints); 02898 } 02899 if (!res) 02900 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); 02901 if (!res) { 02902 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 02903 res = ast_streamfile(chan, fn, lang); 02904 if (!res) 02905 res = ast_waitstream(chan, ints); 02906 } 02907 if (!res) 02908 res = ast_waitstream(chan, ints); 02909 if (!res) 02910 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 02911 return res; 02912 } 02913 02914 /* Portuguese syntax */ 02915 int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 02916 { 02917 struct tm tm; 02918 char fn[256]; 02919 int res = 0; 02920 ast_localtime(&t,&tm,NULL); 02921 localtime_r(&t,&tm); 02922 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 02923 if (!res) 02924 res = wait_file(chan, ints, fn, lang); 02925 if (!res) 02926 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 02927 if (!res) 02928 res = wait_file(chan, ints, "digits/pt-de", lang); 02929 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 02930 if (!res) 02931 res = wait_file(chan, ints, fn, lang); 02932 if (!res) 02933 res = wait_file(chan, ints, "digits/pt-de", lang); 02934 if (!res) 02935 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 02936 02937 return res; 02938 } 02939 02940 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) 02941 { 02942 if (!strcasecmp(lang, "en") ) { /* English syntax */ 02943 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone)); 02944 } else if (!strcasecmp(lang, "da") ) { /* Danish syntax */ 02945 return(ast_say_date_with_format_da(chan, time, ints, lang, format, timezone)); 02946 } else if (!strcasecmp(lang, "de") ) { /* German syntax */ 02947 return(ast_say_date_with_format_de(chan, time, ints, lang, format, timezone)); 02948 } else if (!strcasecmp(lang, "es") || !strcasecmp(lang, "mx")) { /* Spanish syntax */ 02949 return(ast_say_date_with_format_es(chan, time, ints, lang, format, timezone)); 02950 } else if (!strcasecmp(lang, "he")) { /* Hebrew syntax */ 02951 return(ast_say_date_with_format_he(chan, time, ints, lang, format, timezone)); 02952 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */ 02953 return(ast_say_date_with_format_fr(chan, time, ints, lang, format, timezone)); 02954 } else if (!strcasecmp(lang, "it") ) { /* Italian syntax */ 02955 return(ast_say_date_with_format_it(chan, time, ints, lang, format, timezone)); 02956 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 02957 return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone)); 02958 } else if (!strcasecmp(lang, "pl") ) { /* Polish syntax */ 02959 return(ast_say_date_with_format_pl(chan, time, ints, lang, format, timezone)); 02960 } else if (!strcasecmp(lang, "pt") || !strcasecmp(lang, "pt_BR")) { /* Portuguese syntax */ 02961 return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone)); 02962 } else if (!strcasecmp(lang, "tw") || !strcasecmp(lang, "zh") ) { /* Taiwanese / Chinese syntax */ 02963 return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone)); 02964 } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */ 02965 return(ast_say_date_with_format_gr(chan, time, ints, lang, format, timezone)); 02966 } 02967 02968 /* Default to English */ 02969 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone)); 02970 } 02971 02972 /* English syntax */ 02973 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) 02974 { 02975 struct tm tm; 02976 int res=0, offset, sndoffset; 02977 char sndfile[256], nextmsg[256]; 02978 02979 if (format == NULL) 02980 format = "ABdY 'digits/at' IMp"; 02981 02982 ast_localtime(&time,&tm,timezone); 02983 02984 for (offset=0 ; format[offset] != '\0' ; offset++) { 02985 if (option_debug) 02986 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02987 switch (format[offset]) { 02988 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02989 case '\'': 02990 /* Literal name of a sound file */ 02991 sndoffset=0; 02992 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02993 sndfile[sndoffset] = format[offset]; 02994 sndfile[sndoffset] = '\0'; 02995 res = wait_file(chan,ints,sndfile,lang); 02996 break; 02997 case 'A': 02998 case 'a': 02999 /* Sunday - Saturday */ 03000 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 03001 res = wait_file(chan,ints,nextmsg,lang); 03002 break; 03003 case 'B': 03004 case 'b': 03005 case 'h': 03006 /* January - December */ 03007 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 03008 res = wait_file(chan,ints,nextmsg,lang); 03009 break; 03010 case 'm': 03011 /* Month enumerated */ 03012 res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, (char *) NULL); 03013 break; 03014 case 'd': 03015 case 'e': 03016 /* First - Thirtyfirst */ 03017 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char *) NULL); 03018 break; 03019 case 'Y': 03020 /* Year */ 03021 if (tm.tm_year > 99) { 03022 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 03023 } else if (tm.tm_year < 1) { 03024 /* I'm not going to handle 1900 and prior */ 03025 /* We'll just be silent on the year, instead of bombing out. */ 03026 } else { 03027 res = wait_file(chan, ints, "digits/19", lang); 03028 if (!res) { 03029 if (tm.tm_year <= 9) { 03030 /* 1901 - 1909 */ 03031 res = wait_file(chan,ints, "digits/oh", lang); 03032 } 03033 03034 res |= ast_say_number(chan, tm.tm_year, ints, lang, (char *) NULL); 03035 } 03036 } 03037 break; 03038 case 'I': 03039 case 'l': 03040 /* 12-Hour */ 03041 if (tm.tm_hour == 0) 03042 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 03043 else if (tm.tm_hour > 12) 03044 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 03045 else 03046 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 03047 res = wait_file(chan,ints,nextmsg,lang); 03048 break; 03049 case 'H': 03050 case 'k': 03051 /* 24-Hour */ 03052 if (format[offset] == 'H') { 03053 /* e.g. oh-eight */ 03054 if (tm.tm_hour < 10) { 03055 res = wait_file(chan,ints, "digits/oh",lang); 03056 } 03057 } else { 03058 /* e.g. eight */ 03059 if (tm.tm_hour == 0) { 03060 res = wait_file(chan,ints, "digits/oh",lang); 03061 } 03062 } 03063 if (!res) { 03064 if (tm.tm_hour != 0) { 03065 int remainder = tm.tm_hour; 03066 if (tm.tm_hour > 20) { 03067 res = wait_file(chan,ints, "digits/20",lang); 03068 remainder -= 20; 03069 } 03070 if (!res) { 03071 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 03072 res = wait_file(chan,ints,nextmsg,lang); 03073 } 03074 } 03075 } 03076 break; 03077 case 'M': 03078 case 'N': 03079 /* Minute */ 03080 if (tm.tm_min == 0) { 03081 if (format[offset] == 'M') { 03082 res = wait_file(chan, ints, "digits/oclock", lang); 03083 } else { 03084 res = wait_file(chan, ints, "digits/hundred", lang); 03085 } 03086 } else if (tm.tm_min < 10) { 03087 res = wait_file(chan,ints, "digits/oh",lang); 03088 if (!res) { 03089 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 03090 res = wait_file(chan,ints,nextmsg,lang); 03091 } 03092 } else { 03093 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03094 } 03095 break; 03096 case 'P': 03097 case 'p': 03098 /* AM/PM */ 03099 if (tm.tm_hour > 11) 03100 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 03101 else 03102 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 03103 res = wait_file(chan,ints,nextmsg,lang); 03104 break; 03105 case 'Q': 03106 /* Shorthand for "Today", "Yesterday", or ABdY */ 03107 /* XXX As emphasized elsewhere, this should the native way in your 03108 * language to say the date, with changes in what you say, depending 03109 * upon how recent the date is. XXX */ 03110 { 03111 struct timeval now; 03112 struct tm tmnow; 03113 time_t beg_today, tt; 03114 03115 gettimeofday(&now,NULL); 03116 tt = now.tv_sec; 03117 ast_localtime(&tt,&tmnow,timezone); 03118 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03119 /* In any case, it saves not having to do ast_mktime() */ 03120 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03121 if (beg_today < time) { 03122 /* Today */ 03123 res = wait_file(chan,ints, "digits/today",lang); 03124 } else if (beg_today - 86400 < time) { 03125 /* Yesterday */ 03126 res = wait_file(chan,ints, "digits/yesterday",lang); 03127 } else if (beg_today - 86400 * 6 < time) { 03128 /* Within the last week */ 03129 res = ast_say_date_with_format_en(chan, time, ints, lang, "A", timezone); 03130 } else if (beg_today - 2628000 < time) { 03131 /* Less than a month ago - "Sunday, October third" */ 03132 res = ast_say_date_with_format_en(chan, time, ints, lang, "ABd", timezone); 03133 } else if (beg_today - 15768000 < time) { 03134 /* Less than 6 months ago - "August seventh" */ 03135 res = ast_say_date_with_format_en(chan, time, ints, lang, "Bd", timezone); 03136 } else { 03137 /* More than 6 months ago - "April nineteenth two thousand three" */ 03138 res = ast_say_date_with_format_en(chan, time, ints, lang, "BdY", timezone); 03139 } 03140 } 03141 break; 03142 case 'q': 03143 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 03144 /* XXX As emphasized elsewhere, this should the native way in your 03145 * language to say the date, with changes in what you say, depending 03146 * upon how recent the date is. XXX */ 03147 { 03148 struct timeval now; 03149 struct tm tmnow; 03150 time_t beg_today, tt; 03151 03152 gettimeofday(&now,NULL); 03153 tt = now.tv_sec; 03154 ast_localtime(&tt,&tmnow,timezone); 03155 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03156 /* In any case, it saves not having to do ast_mktime() */ 03157 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03158 if (beg_today < time) { 03159 /* Today */ 03160 } else if ((beg_today - 86400) < time) { 03161 /* Yesterday */ 03162 res = wait_file(chan,ints, "digits/yesterday",lang); 03163 } else if (beg_today - 86400 * 6 < time) { 03164 /* Within the last week */ 03165 res = ast_say_date_with_format_en(chan, time, ints, lang, "A", timezone); 03166 } else if (beg_today - 2628000 < time) { 03167 /* Less than a month ago - "Sunday, October third" */ 03168 res = ast_say_date_with_format_en(chan, time, ints, lang, "ABd", timezone); 03169 } else if (beg_today - 15768000 < time) { 03170 /* Less than 6 months ago - "August seventh" */ 03171 res = ast_say_date_with_format_en(chan, time, ints, lang, "Bd", timezone); 03172 } else { 03173 /* More than 6 months ago - "April nineteenth two thousand three" */ 03174 res = ast_say_date_with_format_en(chan, time, ints, lang, "BdY", timezone); 03175 } 03176 } 03177 break; 03178 case 'R': 03179 res = ast_say_date_with_format_en(chan, time, ints, lang, "HM", timezone); 03180 break; 03181 case 'S': 03182 /* Seconds */ 03183 if (tm.tm_sec == 0) { 03184 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03185 res = wait_file(chan,ints,nextmsg,lang); 03186 } else if (tm.tm_sec < 10) { 03187 res = wait_file(chan,ints, "digits/oh",lang); 03188 if (!res) { 03189 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03190 res = wait_file(chan,ints,nextmsg,lang); 03191 } 03192 } else { 03193 res = ast_say_number(chan, tm.tm_sec, ints, lang, (char *) NULL); 03194 } 03195 break; 03196 case 'T': 03197 res = ast_say_date_with_format_en(chan, time, ints, lang, "HMS", timezone); 03198 break; 03199 case ' ': 03200 case ' ': 03201 /* Just ignore spaces and tabs */ 03202 break; 03203 default: 03204 /* Unknown character */ 03205 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 03206 } 03207 /* Jump out on DTMF */ 03208 if (res) { 03209 break; 03210 } 03211 } 03212 return res; 03213 } 03214 03215 /* Danish syntax */ 03216 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) 03217 { 03218 struct tm tm; 03219 int res=0, offset, sndoffset; 03220 char sndfile[256], nextmsg[256]; 03221 03222 if (!format) 03223 format = "A dBY HMS"; 03224 03225 ast_localtime(&time,&tm,timezone); 03226 03227 for (offset=0 ; format[offset] != '\0' ; offset++) { 03228 if (option_debug) 03229 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 03230 switch (format[offset]) { 03231 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 03232 case '\'': 03233 /* Literal name of a sound file */ 03234 sndoffset=0; 03235 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 03236 sndfile[sndoffset] = format[offset]; 03237 sndfile[sndoffset] = '\0'; 03238 res = wait_file(chan,ints,sndfile,lang); 03239 break; 03240 case 'A': 03241 case 'a': 03242 /* Sunday - Saturday */ 03243 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 03244 res = wait_file(chan,ints,nextmsg,lang); 03245 break; 03246 case 'B': 03247 case 'b': 03248 case 'h': 03249 /* January - December */ 03250 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 03251 res = wait_file(chan,ints,nextmsg,lang); 03252 break; 03253 case 'm': 03254 /* Month enumerated */ 03255 res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, "m"); 03256 break; 03257 case 'd': 03258 case 'e': 03259 /* First - Thirtyfirst */ 03260 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, "m"); 03261 break; 03262 case 'Y': 03263 /* Year */ 03264 { 03265 int year = tm.tm_year + 1900; 03266 if (year > 1999) { /* year 2000 and later */ 03267 res = ast_say_number(chan, year, ints, lang, (char *) NULL); 03268 } else { 03269 if (year < 1100) { 03270 /* I'm not going to handle 1100 and prior */ 03271 /* We'll just be silent on the year, instead of bombing out. */ 03272 } else { 03273 /* year 1100 to 1999. will anybody need this?!? */ 03274 /* say 1967 as 'nineteen hundred seven and sixty' */ 03275 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (year / 100) ); 03276 res = wait_file(chan,ints,nextmsg,lang); 03277 if (!res) { 03278 res = wait_file(chan,ints, "digits/hundred",lang); 03279 if (!res && year % 100 != 0) { 03280 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL); 03281 } 03282 } 03283 } 03284 } 03285 } 03286 break; 03287 case 'I': 03288 case 'l': 03289 /* 12-Hour */ 03290 res = wait_file(chan,ints,"digits/oclock",lang); 03291 if (tm.tm_hour == 0) 03292 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 03293 else if (tm.tm_hour > 12) 03294 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 03295 else 03296 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 03297 if (!res) { 03298 res = wait_file(chan,ints,nextmsg,lang); 03299 } 03300 break; 03301 case 'H': 03302 /* 24-Hour, single digit hours preceeded by "oh" (0) */ 03303 if (tm.tm_hour < 10 && tm.tm_hour > 0) { 03304 res = wait_file(chan,ints, "digits/0",lang); 03305 } 03306 /* FALLTRHU */ 03307 case 'k': 03308 /* 24-Hour */ 03309 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL); 03310 break; 03311 case 'M': 03312 /* Minute */ 03313 if (tm.tm_min > 0 || format[offset+ 1 ] == 'S' ) { /* zero 'digits/0' only if seconds follow (kind of a hack) */ 03314 res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); 03315 } 03316 if ( !res && format[offset + 1] == 'S' ) { /* minutes only if seconds follow (kind of a hack) */ 03317 if (tm.tm_min == 1) { 03318 res = wait_file(chan,ints,"digits/minute",lang); 03319 } else { 03320 res = wait_file(chan,ints,"digits/minutes",lang); 03321 } 03322 } 03323 break; 03324 case 'P': 03325 case 'p': 03326 /* AM/PM */ 03327 if (tm.tm_hour > 11) 03328 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 03329 else 03330 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 03331 res = wait_file(chan,ints,nextmsg,lang); 03332 break; 03333 case 'Q': 03334 /* Shorthand for "Today", "Yesterday", or AdBY */ 03335 /* XXX As emphasized elsewhere, this should the native way in your 03336 * language to say the date, with changes in what you say, depending 03337 * upon how recent the date is. XXX */ 03338 { 03339 struct timeval now; 03340 struct tm tmnow; 03341 time_t beg_today, tt; 03342 03343 gettimeofday(&now,NULL); 03344 tt = now.tv_sec; 03345 ast_localtime(&tt,&tmnow,timezone); 03346 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03347 /* In any case, it saves not having to do ast_mktime() */ 03348 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03349 if (beg_today < time) { 03350 /* Today */ 03351 res = wait_file(chan,ints, "digits/today",lang); 03352 } else if (beg_today - 86400 < time) { 03353 /* Yesterday */ 03354 res = wait_file(chan,ints, "digits/yesterday",lang); 03355 } else { 03356 res = ast_say_date_with_format_da(chan, time, ints, lang, "AdBY", timezone); 03357 } 03358 } 03359 break; 03360 case 'q': 03361 /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */ 03362 /* XXX As emphasized elsewhere, this should the native way in your 03363 * language to say the date, with changes in what you say, depending 03364 * upon how recent the date is. XXX */ 03365 { 03366 struct timeval now; 03367 struct tm tmnow; 03368 time_t beg_today, tt; 03369 03370 gettimeofday(&now,NULL); 03371 tt = now.tv_sec; 03372 ast_localtime(&tt,&tmnow,timezone); 03373 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03374 /* In any case, it saves not having to do ast_mktime() */ 03375 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03376 if (beg_today < time) { 03377 /* Today */ 03378 } else if ((beg_today - 86400) < time) { 03379 /* Yesterday */ 03380 res = wait_file(chan,ints, "digits/yesterday",lang); 03381 } else if (beg_today - 86400 * 6 < time) { 03382 /* Within the last week */ 03383 res = ast_say_date_with_format_da(chan, time, ints, lang, "A", timezone); 03384 } else { 03385 res = ast_say_date_with_format_da(chan, time, ints, lang, "AdBY", timezone); 03386 } 03387 } 03388 break; 03389 case 'R': 03390 res = ast_say_date_with_format_da(chan, time, ints, lang, "HM", timezone); 03391 break; 03392 case 'S': 03393 /* Seconds */ 03394 res = wait_file(chan,ints, "digits/and",lang); 03395 if (!res) { 03396 res = ast_say_number(chan, tm.tm_sec, ints, lang, "f"); 03397 if (!res) { 03398 res = wait_file(chan,ints, "digits/seconds",lang); 03399 } 03400 } 03401 break; 03402 case 'T': 03403 res = ast_say_date_with_format_da(chan, time, ints, lang, "HMS", timezone); 03404 break; 03405 case ' ': 03406 case ' ': 03407 /* Just ignore spaces and tabs */ 03408 break; 03409 default: 03410 /* Unknown character */ 03411 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 03412 } 03413 /* Jump out on DTMF */ 03414 if (res) { 03415 break; 03416 } 03417 } 03418 return res; 03419 } 03420 03421 /* German syntax */ 03422 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) 03423 { 03424 struct tm tm; 03425 int res=0, offset, sndoffset; 03426 char sndfile[256], nextmsg[256]; 03427 03428 if (!format) 03429 format = "A dBY HMS"; 03430 03431 ast_localtime(&time,&tm,timezone); 03432 03433 for (offset=0 ; format[offset] != '\0' ; offset++) { 03434 if (option_debug) 03435 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 03436 switch (format[offset]) { 03437 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 03438 case '\'': 03439 /* Literal name of a sound file */ 03440 sndoffset=0; 03441 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 03442 sndfile[sndoffset] = format[offset]; 03443 sndfile[sndoffset] = '\0'; 03444 res = wait_file(chan,ints,sndfile,lang); 03445 break; 03446 case 'A': 03447 case 'a': 03448 /* Sunday - Saturday */ 03449 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 03450 res = wait_file(chan,ints,nextmsg,lang); 03451 break; 03452 case 'B': 03453 case 'b': 03454 case 'h': 03455 /* January - December */ 03456 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 03457 res = wait_file(chan,ints,nextmsg,lang); 03458 break; 03459 case 'm': 03460 /* Month enumerated */ 03461 res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, "m"); 03462 break; 03463 case 'd': 03464 case 'e': 03465 /* First - Thirtyfirst */ 03466 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, "m"); 03467 break; 03468 case 'Y': 03469 /* Year */ 03470 { 03471 int year = tm.tm_year + 1900; 03472 if (year > 1999) { /* year 2000 and later */ 03473 res = ast_say_number(chan, year, ints, lang, (char *) NULL); 03474 } else { 03475 if (year < 1100) { 03476 /* I'm not going to handle 1100 and prior */ 03477 /* We'll just be silent on the year, instead of bombing out. */ 03478 } else { 03479 /* year 1100 to 1999. will anybody need this?!? */ 03480 /* say 1967 as 'neunzehn hundert sieben und sechzig' */ 03481 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (year / 100) ); 03482 res = wait_file(chan,ints,nextmsg,lang); 03483 if (!res) { 03484 res = wait_file(chan,ints, "digits/hundred",lang); 03485 if (!res && year % 100 != 0) { 03486 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL); 03487 } 03488 } 03489 } 03490 } 03491 } 03492 break; 03493 case 'I': 03494 case 'l': 03495 /* 12-Hour */ 03496 if (tm.tm_hour == 0) 03497 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 03498 else if (tm.tm_hour > 12) 03499 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 03500 else 03501 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 03502 res = wait_file(chan,ints,nextmsg,lang); 03503 if (!res) { 03504 res = wait_file(chan,ints,"digits/oclock",lang); 03505 } 03506 break; 03507 case 'H': 03508 case 'k': 03509 /* 24-Hour */ 03510 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL); 03511 if (!res) { 03512 res = wait_file(chan,ints,"digits/oclock",lang); 03513 } 03514 break; 03515 case 'M': 03516 /* Minute */ 03517 if (tm.tm_min > 0 || format[offset+ 1 ] == 'S' ) { /* zero 'digits/0' only if seconds follow (kind of a hack) */ 03518 res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); 03519 } 03520 if ( !res && format[offset + 1] == 'S' ) { /* minutes only if seconds follow (kind of a hack) */ 03521 if (tm.tm_min == 1) { 03522 res = wait_file(chan,ints,"digits/minute",lang); 03523 } else { 03524 res = wait_file(chan,ints,"digits/minutes",lang); 03525 } 03526 } 03527 break; 03528 case 'P': 03529 case 'p': 03530 /* AM/PM */ 03531 if (tm.tm_hour > 11) 03532 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 03533 else 03534 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 03535 res = wait_file(chan,ints,nextmsg,lang); 03536 break; 03537 case 'Q': 03538 /* Shorthand for "Today", "Yesterday", or AdBY */ 03539 /* XXX As emphasized elsewhere, this should the native way in your 03540 * language to say the date, with changes in what you say, depending 03541 * upon how recent the date is. XXX */ 03542 { 03543 struct timeval now; 03544 struct tm tmnow; 03545 time_t beg_today, tt; 03546 03547 gettimeofday(&now,NULL); 03548 tt = now.tv_sec; 03549 ast_localtime(&tt,&tmnow,timezone); 03550 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03551 /* In any case, it saves not having to do ast_mktime() */ 03552 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03553 if (beg_today < time) { 03554 /* Today */ 03555 res = wait_file(chan,ints, "digits/today",lang); 03556 } else if (beg_today - 86400 < time) { 03557 /* Yesterday */ 03558 res = wait_file(chan,ints, "digits/yesterday",lang); 03559 } else { 03560 res = ast_say_date_with_format_de(chan, time, ints, lang, "AdBY", timezone); 03561 } 03562 } 03563 break; 03564 case 'q': 03565 /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */ 03566 /* XXX As emphasized elsewhere, this should the native way in your 03567 * language to say the date, with changes in what you say, depending 03568 * upon how recent the date is. XXX */ 03569 { 03570 struct timeval now; 03571 struct tm tmnow; 03572 time_t beg_today, tt; 03573 03574 gettimeofday(&now,NULL); 03575 tt = now.tv_sec; 03576 ast_localtime(&tt,&tmnow,timezone); 03577 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03578 /* In any case, it saves not having to do ast_mktime() */ 03579 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03580 if (beg_today < time) { 03581 /* Today */ 03582 } else if ((beg_today - 86400) < time) { 03583 /* Yesterday */ 03584 res = wait_file(chan,ints, "digits/yesterday",lang); 03585 } else if (beg_today - 86400 * 6 < time) { 03586 /* Within the last week */ 03587 res = ast_say_date_with_format_de(chan, time, ints, lang, "A", timezone); 03588 } else { 03589 res = ast_say_date_with_format_de(chan, time, ints, lang, "AdBY", timezone); 03590 } 03591 } 03592 break; 03593 case 'R': 03594 res = ast_say_date_with_format_de(chan, time, ints, lang, "HM", timezone); 03595 break; 03596 case 'S': 03597 /* Seconds */ 03598 res = wait_file(chan,ints, "digits/and",lang); 03599 if (!res) { 03600 res = ast_say_number(chan, tm.tm_sec, ints, lang, "f"); 03601 if (!res) { 03602 res = wait_file(chan,ints, "digits/seconds",lang); 03603 } 03604 } 03605 break; 03606 case 'T': 03607 res = ast_say_date_with_format_de(chan, time, ints, lang, "HMS", timezone); 03608 break; 03609 case ' ': 03610 case ' ': 03611 /* Just ignore spaces and tabs */ 03612 break; 03613 default: 03614 /* Unknown character */ 03615 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 03616 } 03617 /* Jump out on DTMF */ 03618 if (res) { 03619 break; 03620 } 03621 } 03622 return res; 03623 } 03624 03625 /* TODO: this probably is not the correct format for doxygen remarks */ 03626 03627 /** ast_say_date_with_format_he Say formatted date in Hebrew 03628 * 03629 * \ref ast_say_date_with_format_en for the details of the options 03630 * 03631 * Changes from the English version: 03632 * 03633 * * don't replicate in here the logic of ast_say_number_full_he 03634 * 03635 * * year is always 4-digit (because it's simpler) 03636 * 03637 * * added c, x, and X. Mainly for my tests 03638 * 03639 * * The standard "long" format used in Hebrew is AdBY, rather than ABdY 03640 * 03641 * TODO: 03642 * * A "ha" is missing in the standard date format, before the 'd'. 03643 * * The numbers of 3000--19000 are not handled well 03644 **/ 03645 #define IL_DATE_STR "AdBY" 03646 #define IL_TIME_STR "IMp" 03647 #define IL_DATE_STR_FULL IL_DATE_STR " 'digits/at' " IL_TIME_STR 03648 int ast_say_date_with_format_he(struct ast_channel *chan, time_t time, 03649 const char *ints, const char *lang, const char *format, 03650 const char *timezone) 03651 { 03652 /* TODO: This whole function is cut&paste from 03653 * ast_say_date_with_format_en . Is that considered acceptable? 03654 **/ 03655 struct tm tm; 03656 int res=0, offset, sndoffset; 03657 char sndfile[256], nextmsg[256]; 03658 03659 if (!format) 03660 format = IL_DATE_STR_FULL; 03661 03662 ast_localtime(&time,&tm,timezone); 03663 03664 for (offset=0 ; format[offset] != '\0' ; offset++) { 03665 if (option_debug) 03666 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 03667 switch (format[offset]) { 03668 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 03669 case '\'': 03670 /* Literal name of a sound file */ 03671 sndoffset=0; 03672 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 03673 sndfile[sndoffset] = format[offset]; 03674 sndfile[sndoffset] = '\0'; 03675 res = wait_file(chan,ints,sndfile,lang); 03676 break; 03677 case 'A': 03678 case 'a': 03679 /* Sunday - Saturday */ 03680 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 03681 res = wait_file(chan,ints,nextmsg,lang); 03682 break; 03683 case 'B': 03684 case 'b': 03685 case 'h': 03686 /* January - December */ 03687 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 03688 res = wait_file(chan,ints,nextmsg,lang); 03689 break; 03690 case 'd': 03691 case 'e': /* Day of the month */ 03692 /* I'm not sure exactly what the parameters 03693 * audiofd and ctrlfd to 03694 * ast_say_number_full_he mean, but it seems 03695 * safe to pass -1 there. 03696 * 03697 * At least in one of the pathes :-( 03698 */ 03699 res = ast_say_number_full_he(chan, tm.tm_mday, 03700 ints, lang, "m", -1, -1 03701 ); 03702 break; 03703 case 'Y': /* Year */ 03704 res = ast_say_number_full_he(chan, tm.tm_year+1900, 03705 ints, lang, "f", -1, -1 03706 ); 03707 break; 03708 case 'I': 03709 case 'l': /* 12-Hour */ 03710 { 03711 int hour = tm.tm_hour; 03712 hour = hour%12; 03713 if (hour == 0) hour=12; 03714 03715 res = ast_say_number_full_he(chan, hour, 03716 ints, lang, "f", -1, -1 03717 ); 03718 } 03719 break; 03720 case 'H': 03721 case 'k': /* 24-Hour */ 03722 /* With 'H' there is an 'oh' after a single- 03723 * digit hour */ 03724 if ((format[offset] == 'H') && 03725 (tm.tm_hour <10)&&(tm.tm_hour>0) 03726 ) { /* e.g. oh-eight */ 03727 res = wait_file(chan,ints, "digits/oh",lang); 03728 } 03729 03730 res = ast_say_number_full_he(chan, tm.tm_hour, 03731 ints, lang, "f", -1, -1 03732 ); 03733 break; 03734 case 'M': /* Minute */ 03735 res = ast_say_number_full_he(chan, tm.tm_min, 03736 ints, lang,"f", -1, -1 03737 ); 03738 break; 03739 case 'P': 03740 case 'p': 03741 /* AM/PM */ 03742 if (tm.tm_hour > 11) 03743 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 03744 else 03745 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 03746 res = wait_file(chan,ints,nextmsg,lang); 03747 break; 03748 case 'Q': 03749 /* Shorthand for "Today", "Yesterday", or "date" */ 03750 case 'q': 03751 /* Shorthand for "" (today), "Yesterday", A 03752 * (weekday), or "date" */ 03753 /* XXX As emphasized elsewhere, this should the native way in your 03754 * language to say the date, with changes in what you say, depending 03755 * upon how recent the date is. XXX */ 03756 { 03757 struct timeval now; 03758 struct tm tmnow; 03759 time_t beg_today, tt; 03760 char todo = format[offset]; /* The letter to format*/ 03761 03762 gettimeofday(&now,NULL); 03763 tt = now.tv_sec; 03764 ast_localtime(&tt,&tmnow,timezone); 03765 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03766 /* In any case, it saves not having to do ast_mktime() */ 03767 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03768 if (beg_today < time) { 03769 /* Today */ 03770 if (todo == 'Q') { 03771 res = wait_file(chan, 03772 ints, 03773 "digits/today", 03774 lang); 03775 } 03776 } else if (beg_today - 86400 < time) { 03777 /* Yesterday */ 03778 res = wait_file(chan,ints, "digits/yesterday",lang); 03779 } else if ((todo != 'Q') && 03780 (beg_today - 86400 * 6 < time)) 03781 { 03782 /* Within the last week */ 03783 res = ast_say_date_with_format_he(chan, 03784 time, ints, lang, 03785 "A", timezone); 03786 } else { 03787 res = ast_say_date_with_format_he(chan, 03788 time, ints, lang, 03789 IL_DATE_STR, timezone); 03790 } 03791 } 03792 break; 03793 case 'R': 03794 res = ast_say_date_with_format_he(chan, time, ints, lang, "HM", timezone); 03795 break; 03796 case 'S': /* Seconds */ 03797 res = ast_say_number_full_he(chan, tm.tm_sec, 03798 ints, lang, "f", -1, -1 03799 ); 03800 break; 03801 case 'T': 03802 res = ast_say_date_with_format_he(chan, time, ints, lang, "HMS", timezone); 03803 break; 03804 /* c, x, and X seem useful for testing. Not sure 03805 * if thiey're good for the general public */ 03806 case 'c': 03807 res = ast_say_date_with_format_he(chan, time, 03808 ints, lang, IL_DATE_STR_FULL, timezone); 03809 break; 03810 case 'x': 03811 res = ast_say_date_with_format_he(chan, time, 03812 ints, lang, IL_DATE_STR, timezone); 03813 break; 03814 case 'X': /* Currently not locale-dependent...*/ 03815 res = ast_say_date_with_format_he(chan, time, 03816 ints, lang, IL_TIME_STR, timezone); 03817 break; 03818 case ' ': 03819 case ' ': 03820 /* Just ignore spaces and tabs */ 03821 break; 03822 default: 03823 /* Unknown character */ 03824 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 03825 } 03826 /* Jump out on DTMF */ 03827 if (res) { 03828 break; 03829 } 03830 } 03831 return res; 03832 } 03833 03834 03835 /* Spanish syntax */ 03836 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) 03837 { 03838 struct tm tm; 03839 int res=0, offset, sndoffset; 03840 char sndfile[256], nextmsg[256]; 03841 03842 if (format == NULL) 03843 format = "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y 'digits/at' IMp"; 03844 03845 ast_localtime(&time,&tm,timezone); 03846 03847 for (offset=0 ; format[offset] != '\0' ; offset++) { 03848 if (option_debug) 03849 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 03850 switch (format[offset]) { 03851 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 03852 case '\'': 03853 /* Literal name of a sound file */ 03854 sndoffset=0; 03855 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 03856 sndfile[sndoffset] = format[offset]; 03857 sndfile[sndoffset] = '\0'; 03858 snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile); 03859 res = wait_file(chan,ints,nextmsg,lang); 03860 break; 03861 case 'A': 03862 case 'a': 03863 /* Sunday - Saturday */ 03864 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 03865 res = wait_file(chan,ints,nextmsg,lang); 03866 break; 03867 case 'B': 03868 case 'b': 03869 case 'h': 03870 /* January - December */ 03871 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 03872 res = wait_file(chan,ints,nextmsg,lang); 03873 break; 03874 case 'm': 03875 /* First - Twelfth */ 03876 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1); 03877 res = wait_file(chan,ints,nextmsg,lang); 03878 break; 03879 case 'd': 03880 case 'e': 03881 /* First - Thirtyfirst */ 03882 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03883 break; 03884 case 'Y': 03885 /* Year */ 03886 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 03887 break; 03888 case 'I': 03889 case 'l': 03890 /* 12-Hour */ 03891 if (tm.tm_hour == 0) 03892 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 03893 else if (tm.tm_hour > 12) 03894 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 03895 else 03896 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 03897 res = wait_file(chan,ints,nextmsg,lang); 03898 break; 03899 case 'H': 03900 case 'k': 03901 /* 24-Hour */ 03902 res = ast_say_number(chan, tm.tm_hour, ints, lang, NULL); 03903 break; 03904 case 'M': 03905 /* Minute */ 03906 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03907 break; 03908 case 'P': 03909 case 'p': 03910 /* AM/PM */ 03911 if (tm.tm_hour > 18) 03912 res = wait_file(chan, ints, "digits/p-m", lang); 03913 else if (tm.tm_hour > 12) 03914 res = wait_file(chan, ints, "digits/afternoon", lang); 03915 else if (tm.tm_hour) 03916 res = wait_file(chan, ints, "digits/a-m", lang); 03917 break; 03918 case 'Q': 03919 /* Shorthand for "Today", "Yesterday", or ABdY */ 03920 /* XXX As emphasized elsewhere, this should the native way in your 03921 * language to say the date, with changes in what you say, depending 03922 * upon how recent the date is. XXX */ 03923 { 03924 struct timeval now; 03925 struct tm tmnow; 03926 time_t beg_today, tt; 03927 03928 gettimeofday(&now,NULL); 03929 tt = now.tv_sec; 03930 ast_localtime(&tt,&tmnow,timezone); 03931 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03932 /* In any case, it saves not having to do ast_mktime() */ 03933 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03934 if (beg_today < time) { 03935 /* Today */ 03936 res = wait_file(chan,ints, "digits/today",lang); 03937 } else if (beg_today - 86400 < time) { 03938 /* Yesterday */ 03939 res = wait_file(chan,ints, "digits/yesterday",lang); 03940 } else { 03941 res = ast_say_date_with_format_es(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone); 03942 } 03943 } 03944 break; 03945 case 'q': 03946 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 03947 /* XXX As emphasized elsewhere, this should the native way in your 03948 * language to say the date, with changes in what you say, depending 03949 * upon how recent the date is. XXX */ 03950 { 03951 struct timeval now; 03952 struct tm tmnow; 03953 time_t beg_today, tt; 03954 03955 gettimeofday(&now,NULL); 03956 tt = now.tv_sec; 03957 ast_localtime(&tt,&tmnow,timezone); 03958 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03959 /* In any case, it saves not having to do ast_mktime() */ 03960 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03961 if (beg_today < time) { 03962 /* Today */ 03963 res = wait_file(chan,ints, "digits/today",lang); 03964 } else if ((beg_today - 86400) < time) { 03965 /* Yesterday */ 03966 res = wait_file(chan,ints, "digits/yesterday",lang); 03967 } else if (beg_today - 86400 * 6 < time) { 03968 /* Within the last week */ 03969 res = ast_say_date_with_format_es(chan, time, ints, lang, "A", timezone); 03970 } else { 03971 res = ast_say_date_with_format_es(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone); 03972 } 03973 } 03974 break; 03975 case 'R': 03976 res = ast_say_date_with_format_es(chan, time, ints, lang, "H 'digits/y' M", timezone); 03977 break; 03978 case 'S': 03979 /* Seconds */ 03980 if (tm.tm_sec == 0) { 03981 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03982 res = wait_file(chan,ints,nextmsg,lang); 03983 } else if (tm.tm_sec < 10) { 03984 res = wait_file(chan,ints, "digits/oh",lang); 03985 if (!res) { 03986 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03987 res = wait_file(chan,ints,nextmsg,lang); 03988 } 03989 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 03990 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03991 res = wait_file(chan,ints,nextmsg,lang); 03992 } else { 03993 int ten, one; 03994 ten = (tm.tm_sec / 10) * 10; 03995 one = (tm.tm_sec % 10); 03996 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 03997 res = wait_file(chan,ints,nextmsg,lang); 03998 if (!res) { 03999 /* Fifty, not fifty-zero */ 04000 if (one != 0) { 04001 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 04002 res = wait_file(chan,ints,nextmsg,lang); 04003 } 04004 } 04005 } 04006 break; 04007 case 'T': 04008 res = ast_say_date_with_format_es(chan, time, ints, lang, "HMS", timezone); 04009 break; 04010 case ' ': 04011 case ' ': 04012 /* Just ignore spaces and tabs */ 04013 break; 04014 default: 04015 /* Unknown character */ 04016 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 04017 } 04018 /* Jump out on DTMF */ 04019 if (res) { 04020 break; 04021 } 04022 } 04023 return res; 04024 } 04025 04026 /* French syntax 04027 oclock = heure 04028 */ 04029 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) 04030 { 04031 struct tm tm; 04032 int res=0, offset, sndoffset; 04033 char sndfile[256], nextmsg[256]; 04034 04035 if (format == NULL) 04036 format = "AdBY 'digits/at' IMp"; 04037 04038 ast_localtime(&time,&tm,timezone); 04039 04040 for (offset=0 ; format[offset] != '\0' ; offset++) { 04041 if (option_debug) 04042 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 04043 switch (format[offset]) { 04044 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 04045 case '\'': 04046 /* Literal name of a sound file */ 04047 sndoffset=0; 04048 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 04049 sndfile[sndoffset] = format[offset]; 04050 sndfile[sndoffset] = '\0'; 04051 res = wait_file(chan,ints,sndfile,lang); 04052 break; 04053 case 'A': 04054 case 'a': 04055 /* Sunday - Saturday */ 04056 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 04057 res = wait_file(chan,ints,nextmsg,lang); 04058 break; 04059 case 'B': 04060 case 'b': 04061 case 'h': 04062 /* January - December */ 04063 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 04064 res = wait_file(chan,ints,nextmsg,lang); 04065 break; 04066 case 'm': 04067 /* First - Twelfth */ 04068 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1); 04069 res = wait_file(chan,ints,nextmsg,lang); 04070 break; 04071 case 'd': 04072 case 'e': 04073 /* First */ 04074 if (tm.tm_mday == 1) { 04075 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 04076 res = wait_file(chan,ints,nextmsg,lang); 04077 } else { 04078 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); 04079 } 04080 break; 04081 case 'Y': 04082 /* Year */ 04083 if (tm.tm_year > 99) { 04084 res = wait_file(chan,ints, "digits/2",lang); 04085 if (!res) { 04086 res = wait_file(chan,ints, "digits/thousand",lang); 04087 } 04088 if (tm.tm_year > 100) { 04089 if (!res) { 04090 res = ast_say_number(chan, tm.tm_year - 100, ints, lang, (char * ) NULL); 04091 } 04092 } 04093 } else { 04094 if (tm.tm_year < 1) { 04095 /* I'm not going to handle 1900 and prior */ 04096 /* We'll just be silent on the year, instead of bombing out. */ 04097 } else { 04098 res = wait_file(chan,ints, "digits/thousand",lang); 04099 if (!res) { 04100 wait_file(chan,ints, "digits/9",lang); 04101 wait_file(chan,ints, "digits/hundred",lang); 04102 res = ast_say_number(chan, tm.tm_year, ints, lang, (char * ) NULL); 04103 } 04104 } 04105 } 04106 break; 04107 case 'I': 04108 case 'l': 04109 /* 12-Hour */ 04110 if (tm.tm_hour == 0) 04111 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 04112 else if (tm.tm_hour > 12) 04113 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 04114 else 04115 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 04116 res = wait_file(chan,ints,nextmsg,lang); 04117 if (!res) 04118 res = wait_file(chan,ints, "digits/oclock",lang); 04119 break; 04120 case 'H': 04121 case 'k': 04122 /* 24-Hour */ 04123 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char * ) NULL); 04124 if (!res) 04125 res = wait_file(chan,ints, "digits/oclock",lang); 04126 break; 04127 case 'M': 04128 /* Minute */ 04129 if (tm.tm_min == 0) { 04130 break; 04131 } 04132 res = ast_say_number(chan, tm.tm_min, ints, lang, (char * ) NULL); 04133 break; 04134 case 'P': 04135 case 'p': 04136 /* AM/PM */ 04137 if (tm.tm_hour > 11) 04138 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 04139 else 04140 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 04141 res = wait_file(chan,ints,nextmsg,lang); 04142 break; 04143 case 'Q': 04144 /* Shorthand for "Today", "Yesterday", or AdBY */ 04145 /* XXX As emphasized elsewhere, this should the native way in your 04146 * language to say the date, with changes in what you say, depending 04147 * upon how recent the date is. XXX */ 04148 { 04149 struct timeval now; 04150 struct tm tmnow; 04151 time_t beg_today, tt; 04152 04153 gettimeofday(&now,NULL); 04154 tt = now.tv_sec; 04155 ast_localtime(&tt,&tmnow,timezone); 04156 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 04157 /* In any case, it saves not having to do ast_mktime() */ 04158 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 04159 if (beg_today < time) { 04160 /* Today */ 04161 res = wait_file(chan,ints, "digits/today",lang); 04162 } else if (beg_today - 86400 < time) { 04163 /* Yesterday */ 04164 res = wait_file(chan,ints, "digits/yesterday",lang); 04165 } else { 04166 res = ast_say_date_with_format_fr(chan, time, ints, lang, "AdBY", timezone); 04167 } 04168 } 04169 break; 04170 case 'q': 04171 /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */ 04172 /* XXX As emphasized elsewhere, this should the native way in your 04173 * language to say the date, with changes in what you say, depending 04174 * upon how recent the date is. XXX */ 04175 { 04176 struct timeval now; 04177 struct tm tmnow; 04178 time_t beg_today, tt; 04179 04180 gettimeofday(&now,NULL); 04181 tt = now.tv_sec; 04182 ast_localtime(&tt,&tmnow,timezone); 04183 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 04184 /* In any case, it saves not having to do ast_mktime() */ 04185 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 04186 if (beg_today < time) { 04187 /* Today */ 04188 } else if ((beg_today - 86400) < time) { 04189 /* Yesterday */ 04190 res = wait_file(chan,ints, "digits/yesterday",lang); 04191 } else if (beg_today - 86400 * 6 < time) { 04192 /* Within the last week */ 04193 res = ast_say_date_with_format_fr(chan, time, ints, lang, "A", timezone); 04194 } else { 04195 res = ast_say_date_with_format_fr(chan, time, ints, lang, "AdBY", timezone); 04196 } 04197 } 04198 break; 04199 case 'R': 04200 res = ast_say_date_with_format_fr(chan, time, ints, lang, "HM", timezone); 04201 break; 04202 case 'S': 04203 /* Seconds */ 04204 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char * ) NULL); 04205 if (!res) { 04206 res = wait_file(chan,ints, "digits/second",lang); 04207 } 04208 break; 04209 case 'T': 04210 res = ast_say_date_with_format_fr(chan, time, ints, lang, "HMS", timezone); 04211 break; 04212 case ' ': 04213 case ' ': 04214 /* Just ignore spaces and tabs */ 04215 break; 04216 default: 04217 /* Unknown character */ 04218 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 04219 } 04220 /* Jump out on DTMF */ 04221 if (res) { 04222 break; 04223 } 04224 } 04225 return res; 04226 } 04227 04228 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) 04229 { 04230 struct tm tm; 04231 int res=0, offset, sndoffset; 04232 char sndfile[256], nextmsg[256]; 04233 04234 if (format == NULL) 04235 format = "AdB 'digits/at' IMp"; 04236 04237 ast_localtime(&time,&tm,timezone); 04238 04239 for (offset=0 ; format[offset] != '\0' ; offset++) { 04240 if (option_debug) 04241 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 04242 switch (format[offset]) { 04243 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 04244 case '\'': 04245 /* Literal name of a sound file */ 04246 sndoffset=0; 04247 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 04248 sndfile[sndoffset] = format[offset]; 04249 sndfile[sndoffset] = '\0'; 04250 res = wait_file(chan,ints,sndfile,lang); 04251 break; 04252 case 'A': 04253 case 'a': 04254 /* Sunday - Saturday */ 04255 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 04256 res = wait_file(chan,ints,nextmsg,lang); 04257 break; 04258 case 'B': 04259 case 'b': 04260 case 'h': 04261 /* January - December */ 04262 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 04263 res = wait_file(chan,ints,nextmsg,lang); 04264 break; 04265 case 'm': 04266 /* First - Twelfth */ 04267 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1); 04268 res = wait_file(chan,ints,nextmsg,lang); 04269 break; 04270 case 'd': 04271 case 'e': 04272 /* First day of the month is spelled as ordinal */ 04273 if (tm.tm_mday == 1) { 04274 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 04275 res = wait_file(chan,ints,nextmsg,lang); 04276 } else { 04277 if (!res) { 04278 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 04279 } 04280 } 04281 break; 04282 case 'Y': 04283 /* Year */ 04284 if (tm.tm_year > 99) { 04285 res = wait_file(chan,ints, "digits/ore-2000",lang); 04286 if (tm.tm_year > 100) { 04287 if (!res) { 04288 /* This works until the end of 2021 */ 04289 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); 04290 res = wait_file(chan,ints,nextmsg,lang); 04291 } 04292 } 04293 } else { 04294 if (tm.tm_year < 1) { 04295 /* I'm not going to handle 1900 and prior */ 04296 /* We'll just be silent on the year, instead of bombing out. */ 04297 } else { 04298 res = wait_file(chan,ints, "digits/ore-1900",lang); 04299 if ((!res) && (tm.tm_year != 0)) { 04300 if (tm.tm_year <= 21) { 04301 /* 1910 - 1921 */ 04302 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 04303 res = wait_file(chan,ints,nextmsg,lang); 04304 } else { 04305 /* 1922 - 1999, but sounds badly in 1928, 1931, 1938, etc... */ 04306 int ten, one; 04307 ten = tm.tm_year / 10; 04308 one = tm.tm_year % 10; 04309 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); 04310 res = wait_file(chan,ints,nextmsg,lang); 04311 if (!res) { 04312 if (one != 0) { 04313 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 04314 res = wait_file(chan,ints,nextmsg,lang); 04315 } 04316 } 04317 } 04318 } 04319 } 04320 } 04321 break; 04322 case 'I': 04323 case 'l': 04324 /* 12-Hour */ 04325 if (tm.tm_hour == 0) 04326 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 04327 else if (tm.tm_hour > 12) 04328 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 04329 else 04330 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 04331 res = wait_file(chan,ints,nextmsg,lang); 04332 break; 04333 case 'H': 04334 case 'k': 04335 /* 24-Hour */ 04336 if (tm.tm_hour == 0) { 04337 res = wait_file(chan,ints, "digits/ore-mezzanotte",lang); 04338 } else if (tm.tm_hour == 1) { 04339 res = wait_file(chan,ints, "digits/ore-una",lang); 04340 } else { 04341 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL); 04342 } 04343 break; 04344 case 'M': 04345 /* Minute */ 04346 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 04347 break; 04348 case 'P': 04349 case 'p': 04350 /* AM/PM */ 04351 if (tm.tm_hour > 11) 04352 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 04353 else 04354 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 04355 res = wait_file(chan,ints,nextmsg,lang); 04356 break; 04357 case 'Q': 04358 /* Shorthand for "Today", "Yesterday", or ABdY */ 04359 /* XXX As emphasized elsewhere, this should the native way in your 04360 * language to say the date, with changes in what you say, depending 04361 * upon how recent the date is. XXX */ 04362 { 04363 struct timeval now; 04364 struct tm tmnow; 04365 time_t beg_today, tt; 04366 04367 gettimeofday(&now,NULL); 04368 tt = now.tv_sec; 04369 ast_localtime(&tt,&tmnow,timezone); 04370 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 04371 /* In any case, it saves not having to do ast_mktime() */ 04372 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 04373 if (beg_today < time) { 04374 /* Today */ 04375 res = wait_file(chan,ints, "digits/today",lang); 04376 } else if (beg_today - 86400 < time) { 04377 /* Yesterday */ 04378 res = wait_file(chan,ints, "digits/yesterday",lang); 04379 } else { 04380 res = ast_say_date_with_format_it(chan, time, ints, lang, "AdB", timezone); 04381 } 04382 } 04383 break; 04384 case 'q': 04385 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 04386 { 04387 struct timeval now; 04388 struct tm tmnow; 04389 time_t beg_today, tt; 04390 04391 gettimeofday(&now,NULL); 04392 tt = now.tv_sec; 04393 ast_localtime(&tt,&tmnow,timezone); 04394 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 04395 /* In any case, it saves not having to do ast_mktime() */ 04396 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 04397 if (beg_today < time) { 04398 /* Today */ 04399 } else if ((beg_today - 86400) < time) { 04400 /* Yesterday */ 04401 res = wait_file(chan,ints, "digits/yesterday",lang); 04402 } else if (beg_today - 86400 * 6 < time) { 04403 /* Within the last week */ 04404 res = ast_say_date_with_format_it(chan, time, ints, lang, "A", timezone); 04405 } else { 04406 res = ast_say_date_with_format_it(chan, time, ints, lang, "AdB", timezone); 04407 } 04408 } 04409 break; 04410 case 'R': 04411 res = ast_say_date_with_format_it(chan, time, ints, lang, "HM", timezone); 04412 break; 04413 case 'S': 04414 /* Seconds */ 04415 if (tm.tm_sec == 0) { 04416 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 04417 res = wait_file(chan,ints,nextmsg,lang); 04418 } else if (tm.tm_sec < 10) { 04419 res = wait_file(chan,ints, "digits/oh",lang); 04420 if (!res) { 04421 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 04422 res = wait_file(chan,ints,nextmsg,lang); 04423 } 04424 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 04425 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 04426 res = wait_file(chan,ints,nextmsg,lang); 04427 } else { 04428 int ten, one; 04429 ten = (tm.tm_sec / 10) * 10; 04430 one = (tm.tm_sec % 10); 04431 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 04432 res = wait_file(chan,ints,nextmsg,lang); 04433 if (!res) { 04434 /* Fifty, not fifty-zero */ 04435 if (one != 0) { 04436 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 04437 res = wait_file(chan,ints,nextmsg,lang); 04438 } 04439 } 04440 } 04441 break; 04442 case 'T': 04443 res = ast_say_date_with_format_it(chan, time, ints, lang, "HMS", timezone); 04444 break; 04445 case ' ': 04446 case ' ': 04447 /* Just ignore spaces and tabs */ 04448 break; 04449 default: 04450 /* Unknown character */ 04451 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 04452 } 04453 /* Jump out on DTMF */ 04454 if (res) { 04455 break; 04456 } 04457 } 04458 return res; 04459 } 04460 04461 /* Dutch syntax */ 04462 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) 04463 { 04464 struct tm tm; 04465 int res=0, offset, sndoffset; 04466 char sndfile[256], nextmsg[256]; 04467 04468 if (format == NULL) 04469 format = "ABdY 'digits/at' IMp"; 04470 04471 ast_localtime(&time,&tm,timezone); 04472 04473 for (offset=0 ; format[offset] != '\0' ; offset++) { 04474 if (option_debug) 04475 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 04476 switch (format[offset]) { 04477 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 04478 case '\'': 04479 /* Literal name of a sound file */ 04480 sndoffset=0; 04481 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 04482 sndfile[sndoffset] = format[offset]; 04483 sndfile[sndoffset] = '\0'; 04484 res = wait_file(chan,ints,sndfile,lang); 04485 break; 04486 case 'A': 04487 case 'a': 04488 /* Sunday - Saturday */ 04489 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 04490 res = wait_file(chan,ints,nextmsg,lang); 04491 break; 04492 case 'B': 04493 case 'b': 04494 case 'h': 04495 /* January - December */ 04496 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 04497 res = wait_file(chan,ints,nextmsg,lang); 04498 break; 04499 case 'm': 04500 /* First - Twelfth */ 04501 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1); 04502 res = wait_file(chan,ints,nextmsg,lang); 04503 break; 04504 case 'd': 04505 case 'e': 04506 /* First - Thirtyfirst */ 04507 res = ast_say_number(chan, tm.tm_mday, ints, lang, NULL); 04508 break; 04509 case 'Y': 04510 /* Year */ 04511 if (tm.tm_year > 99) { 04512 res = wait_file(chan,ints, "digits/2",lang); 04513 if (!res) { 04514 res = wait_file(chan,ints, "digits/thousand",lang); 04515 } 04516 if (tm.tm_year > 100) { 04517 if (!res) { 04518 /* This works until the end of 2020 */ 04519 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); 04520 res = wait_file(chan,ints,nextmsg,lang); 04521 } 04522 } 04523 } else { 04524 if (tm.tm_year < 1) { 04525 /* I'm not going to handle 1900 and prior */ 04526 /* We'll just be silent on the year, instead of bombing out. */ 04527 } else { 04528 res = wait_file(chan,ints, "digits/19",lang); 04529 if (!res) { 04530 if (tm.tm_year <= 9) { 04531 /* 1901 - 1909 */ 04532 res = wait_file(chan,ints, "digits/oh",lang); 04533 if (!res) { 04534 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 04535 res = wait_file(chan,ints,nextmsg,lang); 04536 } 04537 } else if (tm.tm_year <= 20) { 04538 /* 1910 - 1920 */ 04539 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 04540 res = wait_file(chan,ints,nextmsg,lang); 04541 } else { 04542 /* 1921 - 1999 */ 04543 int ten, one; 04544 ten = tm.tm_year / 10; 04545 one = tm.tm_year % 10; 04546 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); 04547 res = wait_file(chan,ints,nextmsg,lang); 04548 if (!res) { 04549 if (one != 0) { 04550 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 04551 res = wait_file(chan,ints,nextmsg,lang); 04552 } 04553 } 04554 } 04555 } 04556 } 04557 } 04558 break; 04559 case 'I': 04560 case 'l': 04561 /* 12-Hour */ 04562 if (tm.tm_hour == 0) 04563 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 04564 else if (tm.tm_hour > 12) 04565 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 04566 else 04567 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 04568 res = wait_file(chan,ints,nextmsg,lang); 04569 break; 04570 case 'H': 04571 case 'k': 04572 /* 24-Hour */ 04573 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL); 04574 if (!res) { 04575 res = wait_file(chan,ints, "digits/nl-uur",lang); 04576 } 04577 break; 04578 case 'M': 04579 /* Minute */ 04580 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 04581 break; 04582 case 'P': 04583 case 'p': 04584 /* AM/PM */ 04585 if (tm.tm_hour > 11) 04586 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 04587 else 04588 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 04589 res = wait_file(chan,ints,nextmsg,lang); 04590 break; 04591 case 'Q': 04592 /* Shorthand for "Today", "Yesterday", or ABdY */ 04593 /* XXX As emphasized elsewhere, this should the native way in your 04594 * language to say the date, with changes in what you say, depending 04595 * upon how recent the date is. XXX */ 04596 { 04597 struct timeval now; 04598 struct tm tmnow; 04599 time_t beg_today, tt; 04600 04601 gettimeofday(&now,NULL); 04602 tt = now.tv_sec; 04603 ast_localtime(&tt,&tmnow,timezone); 04604 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 04605 /* In any case, it saves not having to do ast_mktime() */ 04606 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 04607 if (beg_today < time) { 04608 /* Today */ 04609 res = wait_file(chan,ints, "digits/today",lang); 04610 } else if (beg_today - 86400 < time) { 04611 /* Yesterday */ 04612 res = wait_file(chan,ints, "digits/yesterday",lang); 04613 } else { 04614 res = ast_say_date_with_format_nl(chan, time, ints, lang, "ABdY", timezone); 04615 } 04616 } 04617 break; 04618 case 'q': 04619 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 04620 { 04621 struct timeval now; 04622 struct tm tmnow; 04623 time_t beg_today, tt; 04624 04625 gettimeofday(&now,NULL); 04626 tt = now.tv_sec; 04627 ast_localtime(&tt,&tmnow,timezone); 04628 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 04629 /* In any case, it saves not having to do ast_mktime() */ 04630 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 04631 if (beg_today < time) { 04632 /* Today */ 04633 } else if ((beg_today - 86400) < time) { 04634 /* Yesterday */ 04635 res = wait_file(chan,ints, "digits/yesterday",lang); 04636 } else if (beg_today - 86400 * 6 < time) { 04637 /* Within the last week */ 04638 res = ast_say_date_with_format_nl(chan, time, ints, lang, "A", timezone); 04639 } else { 04640 res = ast_say_date_with_format_nl(chan, time, ints, lang, "ABdY", timezone); 04641 } 04642 } 04643 break; 04644 case 'R': 04645 res = ast_say_date_with_format_nl(chan, time, ints, lang, "HM", timezone); 04646 break; 04647 case 'S': 04648 /* Seconds */ 04649 if (tm.tm_sec == 0) { 04650 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 04651 res = wait_file(chan,ints,nextmsg,lang); 04652 } else if (tm.tm_sec < 10) { 04653 res = wait_file(chan,ints, "digits/oh",lang); 04654 if (!res) { 04655 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 04656 res = wait_file(chan,ints,nextmsg,lang); 04657 } 04658 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 04659 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 04660 res = wait_file(chan,ints,nextmsg,lang); 04661 } else { 04662 int ten, one; 04663 ten = (tm.tm_sec / 10) * 10; 04664 one = (tm.tm_sec % 10); 04665 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 04666 res = wait_file(chan,ints,nextmsg,lang); 04667 if (!res) { 04668 /* Fifty, not fifty-zero */ 04669 if (one != 0) { 04670 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 04671 res = wait_file(chan,ints,nextmsg,lang); 04672 } 04673 } 04674 } 04675 break; 04676 case 'T': 04677 res = ast_say_date_with_format_nl(chan, time, ints, lang, "HMS", timezone); 04678 break; 04679 case ' ': 04680 case ' ': 04681 /* Just ignore spaces and tabs */ 04682 break; 04683 default: 04684 /* Unknown character */ 04685 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 04686 } 04687 /* Jump out on DTMF */ 04688 if (res) { 04689 break; 04690 } 04691 } 04692 return res; 04693 } 04694 04695 /* Polish syntax */ 04696 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) 04697 { 04698 struct tm tm; 04699 int res=0, offset, sndoffset; 04700 char sndfile[256], nextmsg[256]; 04701 04702 ast_localtime(&thetime, &tm, timezone); 04703 04704 for (offset = 0 ; format[offset] != '\0' ; offset++) { 04705 int remainder; 04706 if (option_debug) 04707 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 04708 switch (format[offset]) { 04709 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 04710 case '\'': 04711 /* Literal name of a sound file */ 04712 sndoffset = 0; 04713 for (sndoffset = 0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 04714 sndfile[sndoffset] = format[offset]; 04715 sndfile[sndoffset] = '\0'; 04716 res = wait_file(chan, ints, sndfile, lang); 04717 break; 04718 case 'A': 04719 case 'a': 04720 /* Sunday - Saturday */ 04721 snprintf(nextmsg, sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 04722 res = wait_file(chan, ints, nextmsg, lang); 04723 break; 04724 case 'B': 04725 case 'b': 04726 case 'h': 04727 /* January - December */ 04728 snprintf(nextmsg, sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 04729 res = wait_file(chan, ints, nextmsg, lang); 04730 break; 04731 case 'm': 04732 /* Month enumerated */ 04733 res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, NULL); 04734 break; 04735 case 'd': 04736 case 'e': 04737 /* First - Thirtyfirst */ 04738 remainder = tm.tm_mday; 04739 if (tm.tm_mday > 30) { 04740 res = wait_file(chan, ints, "digits/h-30", lang); 04741 remainder -= 30; 04742 } 04743 if (tm.tm_mday > 20 && tm.tm_mday < 30) { 04744 res = wait_file(chan, ints, "digits/h-20", lang); 04745 remainder -= 20; 04746 } 04747 if (!res) { 04748 snprintf(nextmsg, sizeof(nextmsg), "digits/h-%d", remainder); 04749 res = wait_file(chan, ints, nextmsg, lang); 04750 } 04751 break; 04752 case 'Y': 04753 /* Year */ 04754 if (tm.tm_year > 100) { 04755 res = wait_file(chan, ints, "digits/2", lang); 04756 if (!res) 04757 res = wait_file(chan, ints, "digits/1000.2",lang); 04758 if (tm.tm_year > 100) { 04759 if (!res) 04760 res = ast_say_enumeration(chan, tm.tm_year - 100, ints, lang, NULL); 04761 } 04762 } else if (tm.tm_year == 100) { 04763 res = wait_file(chan, ints, "digits/h-2000", lang); 04764 } else { 04765 if (tm.tm_year < 1) { 04766 /* I'm not going to handle 1900 and prior */ 04767 /* We'll just be silent on the year, instead of bombing out. */ 04768 break; 04769 } else { 04770 res = wait_file(chan, ints, "digits/1000", lang); 04771 if (!res) { 04772 wait_file(chan, ints, "digits/900", lang); 04773 res = ast_say_enumeration(chan, tm.tm_year, ints, lang, NULL); 04774 } 04775 } 04776 } 04777 if (!res) 04778 wait_file(chan, ints, "digits/year", lang); 04779 break; 04780 case 'I': 04781 case 'l': 04782 /* 12-Hour */ 04783 if (tm.tm_hour == 0) 04784 snprintf(nextmsg, sizeof(nextmsg), "digits/t-12"); 04785 else if (tm.tm_hour > 12) 04786 snprintf(nextmsg, sizeof(nextmsg), "digits/t-%d", tm.tm_hour - 12); 04787 else 04788 snprintf(nextmsg, sizeof(nextmsg), "digits/t-%d", tm.tm_hour); 04789 04790 res = wait_file(chan, ints, nextmsg, lang); 04791 break; 04792 case 'H': 04793 case 'k': 04794 /* 24-Hour */ 04795 if (tm.tm_hour != 0) { 04796 snprintf(nextmsg, sizeof(nextmsg), "digits/t-%d", tm.tm_hour); 04797 res = wait_file(chan, ints, nextmsg, lang); 04798 } else 04799 res = wait_file(chan, ints, "digits/t-24", lang); 04800 break; 04801 case 'M': 04802 case 'N': 04803 /* Minute */ 04804 if (tm.tm_min == 0) { 04805 if (format[offset] == 'M') { 04806 res = wait_file(chan, ints, "digits/oclock", lang); 04807 } else { 04808 res = wait_file(chan, ints, "digits/100", lang); 04809 } 04810 } else 04811 res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); 04812 break; 04813 case 'P': 04814 case 'p': 04815 /* AM/PM */ 04816 if (tm.tm_hour > 11) 04817 snprintf(nextmsg, sizeof(nextmsg), "digits/p-m"); 04818 else 04819 snprintf(nextmsg, sizeof(nextmsg), "digits/a-m"); 04820 res = wait_file(chan, ints, nextmsg, lang); 04821 break; 04822 case 'Q': 04823 /* Shorthand for "Today", "Yesterday", or AdBY */ 04824 { 04825 time_t tv_sec = time(NULL); 04826 struct tm tmnow; 04827 time_t beg_today; 04828 04829 ast_localtime(&tv_sec,&tmnow, timezone); 04830 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 04831 /* In any case, it saves not having to do ast_mktime() */ 04832 beg_today = tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 04833 if (beg_today < thetime) { 04834 /* Today */ 04835 res = wait_file(chan, ints, "digits/today", lang); 04836 } else if (beg_today - 86400 < thetime) { 04837 /* Yesterday */ 04838 res = wait_file(chan, ints, "digits/yesterday", lang); 04839 } else { 04840 res = ast_say_date_with_format(chan, thetime, ints, lang, "AdBY", timezone); 04841 } 04842 } 04843 break; 04844 case 'q': 04845 /* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */ 04846 { 04847 time_t tv_sec = time(NULL); 04848 struct tm tmnow; 04849 time_t beg_today; 04850 04851 ast_localtime(&tv_sec, &tmnow, timezone); 04852 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 04853 /* In any case, it saves not having to do ast_mktime() */ 04854 beg_today = tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 04855 if (beg_today < thetime) { 04856 /* Today */ 04857 } else if ((beg_today - 86400) < thetime) { 04858 /* Yesterday */ 04859 res = wait_file(chan, ints, "digits/yesterday", lang); 04860 } else if (beg_today - 86400 * 6 < thetime) { 04861 /* Within the last week */ 04862 res = ast_say_date_with_format(chan, thetime, ints, lang, "A", timezone); 04863 } else { 04864 res = ast_say_date_with_format(chan, thetime, ints, lang, "AdBY", timezone); 04865 } 04866 } 04867 break; 04868 case 'R': 04869 res = ast_say_date_with_format(chan, thetime, ints, lang, "HM", timezone); 04870 break; 04871 case 'S': 04872 /* Seconds */ 04873 res = wait_file(chan, ints, "digits/and", lang); 04874 if (!res) { 04875 if (tm.tm_sec == 1) { 04876 res = wait_file(chan, ints, "digits/1z", lang); 04877 if (!res) 04878 res = wait_file(chan, ints, "digits/second-a", lang); 04879 } else { 04880 res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); 04881 if (!res) { 04882 int ten, one; 04883 ten = tm.tm_sec / 10; 04884 one = tm.tm_sec % 10; 04885 04886 if (one > 1 && one < 5 && ten != 1) 04887 res = wait_file(chan,ints, "digits/seconds",lang); 04888 else 04889 res = wait_file(chan,ints, "digits/second",lang); 04890 } 04891 } 04892 } 04893 break; 04894 case 'T': 04895 res = ast_say_date_with_format(chan, thetime, ints, lang, "HMS", timezone); 04896 break; 04897 case ' ': 04898 case ' ': 04899 /* Just ignore spaces and tabs */ 04900 break; 04901 default: 04902 /* Unknown character */ 04903 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 04904 } 04905 /* Jump out on DTMF */ 04906 if (res) 04907 break; 04908 } 04909 return res; 04910 } 04911 04912 /* Portuguese syntax */ 04913 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) 04914 { 04915 struct tm tm; 04916 int res=0, offset, sndoffset; 04917 char sndfile[256], nextmsg[256]; 04918 04919 if (format == NULL) 04920 format = "Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/at' IMp"; 04921 04922 ast_localtime(&time,&tm,timezone); 04923 04924 for (offset=0 ; format[offset] != '\0' ; offset++) { 04925 if (option_debug) 04926 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 04927 switch (format[offset]) { 04928 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 04929 case '\'': 04930 /* Literal name of a sound file */ 04931 sndoffset=0; 04932 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 04933 sndfile[sndoffset] = format[offset]; 04934 sndfile[sndoffset] = '\0'; 04935 snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile); 04936 res = wait_file(chan,ints,nextmsg,lang); 04937 break; 04938 case 'A': 04939 case 'a': 04940 /* Sunday - Saturday */ 04941 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 04942 res = wait_file(chan,ints,nextmsg,lang); 04943 break; 04944 case 'B': 04945 case 'b': 04946 case 'h': 04947 /* January - December */ 04948 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 04949 res = wait_file(chan,ints,nextmsg,lang); 04950 break; 04951 case 'm': 04952 /* First - Twelfth */ 04953 if (!strcasecmp(lang, "pt_BR")) { 04954 res = ast_say_number(chan, tm.tm_mon+1, ints, lang, (char *) NULL); 04955 } else { 04956 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1); 04957 res = wait_file(chan,ints,nextmsg,lang); 04958 } 04959 break; 04960 case 'd': 04961 case 'e': 04962 /* First - Thirtyfirst */ 04963 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 04964 break; 04965 case 'Y': 04966 /* Year */ 04967 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 04968 break; 04969 case 'I': 04970 case 'l': 04971 /* 12-Hour */ 04972 if (!strcasecmp(lang, "pt_BR")) { 04973 if (tm.tm_hour == 0) { 04974 if (format[offset] == 'I') 04975 res = wait_file(chan, ints, "digits/pt-a", lang); 04976 if (!res) 04977 res = wait_file(chan, ints, "digits/pt-meianoite", lang); 04978 } else if (tm.tm_hour == 12) { 04979 if (format[offset] == 'I') 04980 res = wait_file(chan, ints, "digits/pt-ao", lang); 04981 if (!res) 04982 res = wait_file(chan, ints, "digits/pt-meiodia", lang); 04983 } else { 04984 if (format[offset] == 'I') { 04985 if ((tm.tm_hour % 12) != 1) 04986 res = wait_file(chan, ints, "digits/pt-as", lang); 04987 else 04988 res = wait_file(chan, ints, "digits/pt-a", lang); 04989 } 04990 if (!res) 04991 res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f"); 04992 if ((!res) && (format[offset] == 'I')) 04993 res = ast_say_date_with_format(chan, time, ints, lang, "P", timezone); 04994 } 04995 } else { 04996 if (tm.tm_hour == 0) { 04997 if (format[offset] == 'I') 04998 res = wait_file(chan, ints, "digits/pt-ah", lang); 04999 if (!res) 05000 res = wait_file(chan, ints, "digits/pt-meianoite", lang); 05001 } 05002 else if (tm.tm_hour == 12) { 05003 if (format[offset] == 'I') 05004 res = wait_file(chan, ints, "digits/pt-ao", lang); 05005 if (!res) 05006 res = wait_file(chan, ints, "digits/pt-meiodia", lang); 05007 } 05008 else { 05009 if (format[offset] == 'I') { 05010 res = wait_file(chan, ints, "digits/pt-ah", lang); 05011 if ((tm.tm_hour % 12) != 1) 05012 if (!res) 05013 res = wait_file(chan, ints, "digits/pt-sss", lang); 05014 } 05015 if (!res) 05016 res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f"); 05017 } 05018 } 05019 break; 05020 case 'H': 05021 case 'k': 05022 /* 24-Hour */ 05023 if (!strcasecmp(lang, "pt_BR")) { 05024 res = ast_say_number(chan, tm.tm_hour, ints, lang, "f"); 05025 if ((!res) && (format[offset] == 'H')) { 05026 if (tm.tm_hour > 1) { 05027 res = wait_file(chan,ints,"digits/hours",lang); 05028 } else { 05029 res = wait_file(chan,ints,"digits/hour",lang); 05030 } 05031 } 05032 } else { 05033 res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL); 05034 if (!res) { 05035 if (tm.tm_hour != 0) { 05036 int remainder = tm.tm_hour; 05037 if (tm.tm_hour > 20) { 05038 res = wait_file(chan,ints, "digits/20",lang); 05039 remainder -= 20; 05040 } 05041 if (!res) { 05042 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 05043 res = wait_file(chan,ints,nextmsg,lang); 05044 } 05045 } 05046 } 05047 } 05048 break; 05049 case 'M': 05050 /* Minute */ 05051 if (!strcasecmp(lang, "pt_BR")) { 05052 res = ast_say_number(chan, tm.tm_min, ints, lang, NULL); 05053 if (!res) { 05054 if (tm.tm_min > 1) { 05055 res = wait_file(chan,ints,"digits/minutes",lang); 05056 } else { 05057 res = wait_file(chan,ints,"digits/minute",lang); 05058 } 05059 } 05060 } else { 05061 if (tm.tm_min == 0) { 05062 res = wait_file(chan, ints, "digits/pt-hora", lang); 05063 if (tm.tm_hour != 1) 05064 if (!res) 05065 res = wait_file(chan, ints, "digits/pt-sss", lang); } else { 05066 res = wait_file(chan,ints,"digits/pt-e",lang); 05067 if (!res) 05068 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05069 } 05070 } 05071 break; 05072 case 'P': 05073 case 'p': 05074 /* AM/PM */ 05075 if (!strcasecmp(lang, "pt_BR")) { 05076 if ((tm.tm_hour != 0) && (tm.tm_hour != 12)) { 05077 res = wait_file(chan, ints, "digits/pt-da", lang); 05078 if (!res) { 05079 if ((tm.tm_hour >= 0) && (tm.tm_hour < 12)) 05080 res = wait_file(chan, ints, "digits/morning", lang); 05081 else if ((tm.tm_hour >= 12) && (tm.tm_hour < 18)) 05082 res = wait_file(chan, ints, "digits/afternoon", lang); 05083 else res = wait_file(chan, ints, "digits/night", lang); 05084 } 05085 } 05086 } else { 05087 if (tm.tm_hour > 12) 05088 res = wait_file(chan, ints, "digits/p-m", lang); 05089 else if (tm.tm_hour && tm.tm_hour < 12) 05090 res = wait_file(chan, ints, "digits/a-m", lang); 05091 } 05092 break; 05093 case 'Q': 05094 /* Shorthand for "Today", "Yesterday", or ABdY */ 05095 /* XXX As emphasized elsewhere, this should the native way in your 05096 * language to say the date, with changes in what you say, depending 05097 * upon how recent the date is. XXX */ 05098 { 05099 struct timeval now; 05100 struct tm tmnow; 05101 time_t beg_today, tt; 05102 05103 gettimeofday(&now,NULL); 05104 tt = now.tv_sec; 05105 ast_localtime(&tt,&tmnow,timezone); 05106 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 05107 /* In any case, it saves not having to do ast_mktime() */ 05108 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 05109 if (beg_today < time) { 05110 /* Today */ 05111 res = wait_file(chan,ints, "digits/today",lang); 05112 } else if (beg_today - 86400 < time) { 05113 /* Yesterday */ 05114 res = wait_file(chan,ints, "digits/yesterday",lang); 05115 } else { 05116 res = ast_say_date_with_format_pt(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone); 05117 } 05118 } 05119 break; 05120 case 'q': 05121 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 05122 /* XXX As emphasized elsewhere, this should the native way in your 05123 * language to say the date, with changes in what you say, depending 05124 * upon how recent the date is. XXX */ 05125 { 05126 struct timeval now; 05127 struct tm tmnow; 05128 time_t beg_today, tt; 05129 05130 gettimeofday(&now,NULL); 05131 tt = now.tv_sec; 05132 ast_localtime(&tt,&tmnow,timezone); 05133 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 05134 /* In any case, it saves not having to do ast_mktime() */ 05135 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 05136 if (beg_today < time) { 05137 /* Today */ 05138 } else if ((beg_today - 86400) < time) { 05139 /* Yesterday */ 05140 res = wait_file(chan,ints, "digits/yesterday",lang); 05141 } else if (beg_today - 86400 * 6 < time) { 05142 /* Within the last week */ 05143 res = ast_say_date_with_format_pt(chan, time, ints, lang, "A", timezone); 05144 } else { 05145 res = ast_say_date_with_format_pt(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone); 05146 } 05147 } 05148 break; 05149 case 'R': 05150 res = ast_say_date_with_format_pt(chan, time, ints, lang, "H 'digits/pt-e' M", timezone); 05151 break; 05152 case 'S': 05153 /* Seconds */ 05154 if (!strcasecmp(lang, "pt_BR")) { 05155 res = ast_say_number(chan, tm.tm_sec, ints, lang, NULL); 05156 if (!res) { 05157 if (tm.tm_sec > 1) { 05158 res = wait_file(chan,ints,"digits/seconds",lang); 05159 } else { 05160 res = wait_file(chan,ints,"digits/second",lang); 05161 } 05162 } 05163 } else { 05164 if (tm.tm_sec == 0) { 05165 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 05166 res = wait_file(chan,ints,nextmsg,lang); 05167 } else if (tm.tm_sec < 10) { 05168 res = wait_file(chan,ints, "digits/oh",lang); 05169 if (!res) { 05170 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 05171 res = wait_file(chan,ints,nextmsg,lang); 05172 } 05173 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 05174 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 05175 res = wait_file(chan,ints,nextmsg,lang); 05176 } else { 05177 int ten, one; 05178 ten = (tm.tm_sec / 10) * 10; 05179 one = (tm.tm_sec % 10); 05180 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 05181 res = wait_file(chan,ints,nextmsg,lang); 05182 if (!res) { 05183 /* Fifty, not fifty-zero */ 05184 if (one != 0) { 05185 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 05186 res = wait_file(chan,ints,nextmsg,lang); 05187 } 05188 } 05189 } 05190 } 05191 break; 05192 case 'T': 05193 res = ast_say_date_with_format_pt(chan, time, ints, lang, "HMS", timezone); 05194 break; 05195 case ' ': 05196 case ' ': 05197 /* Just ignore spaces and tabs */ 05198 break; 05199 default: 05200 /* Unknown character */ 05201 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 05202 } 05203 /* Jump out on DTMF */ 05204 if (res) { 05205 break; 05206 } 05207 } 05208 return res; 05209 } 05210 05211 /* Taiwanese / Chinese syntax */ 05212 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) 05213 { 05214 struct tm tm; 05215 int res=0, offset, sndoffset; 05216 char sndfile[256], nextmsg[256]; 05217 05218 if (format == NULL) 05219 format = "YBdA 'digits/at' HM"; 05220 05221 ast_localtime(&time,&tm,timezone); 05222 05223 for (offset=0 ; format[offset] != '\0' ; offset++) { 05224 if (option_debug) 05225 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 05226 switch (format[offset]) { 05227 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 05228 case '\'': 05229 /* Literal name of a sound file */ 05230 sndoffset=0; 05231 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 05232 sndfile[sndoffset] = format[offset]; 05233 sndfile[sndoffset] = '\0'; 05234 res = wait_file(chan,ints,sndfile,lang); 05235 break; 05236 case 'A': 05237 case 'a': 05238 /* Sunday - Saturday */ 05239 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 05240 res = wait_file(chan,ints,nextmsg,lang); 05241 break; 05242 case 'B': 05243 case 'b': 05244 case 'h': 05245 /* January - December */ 05246 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 05247 res = wait_file(chan,ints,nextmsg,lang); 05248 break; 05249 case 'm': 05250 /* First - Twelfth */ 05251 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1); 05252 res = wait_file(chan,ints,nextmsg,lang); 05253 break; 05254 case 'd': 05255 case 'e': 05256 /* First - Thirtyfirst */ 05257 if (!(tm.tm_mday % 10) || (tm.tm_mday < 10)) { 05258 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 05259 res = wait_file(chan,ints,nextmsg,lang); 05260 } else { 05261 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%dh", tm.tm_mday - (tm.tm_mday % 10)); 05262 res = wait_file(chan,ints,nextmsg,lang); 05263 if (!res) { 05264 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday % 10); 05265 res = wait_file(chan,ints,nextmsg,lang); 05266 } 05267 } 05268 break; 05269 case 'Y': 05270 /* Year */ 05271 if (tm.tm_year > 99) { 05272 res = wait_file(chan,ints, "digits/2",lang); 05273 if (!res) { 05274 res = wait_file(chan,ints, "digits/thousand",lang); 05275 } 05276 if (tm.tm_year > 100) { 05277 if (!res) { 05278 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (tm.tm_year - 100) / 10); 05279 res = wait_file(chan,ints,nextmsg,lang); 05280 if (!res) { 05281 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (tm.tm_year - 100) % 10); 05282 res = wait_file(chan,ints,nextmsg,lang); 05283 } 05284 } 05285 } 05286 if (!res) { 05287 res = wait_file(chan,ints, "digits/year",lang); 05288 } 05289 } else { 05290 if (tm.tm_year < 1) { 05291 /* I'm not going to handle 1900 and prior */ 05292 /* We'll just be silent on the year, instead of bombing out. */ 05293 } else { 05294 res = wait_file(chan,ints, "digits/1",lang); 05295 if (!res) { 05296 res = wait_file(chan,ints, "digits/9",lang); 05297 } 05298 if (!res) { 05299 if (tm.tm_year <= 9) { 05300 /* 1901 - 1909 */ 05301 res = wait_file(chan,ints, "digits/0",lang); 05302 if (!res) { 05303 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 05304 res = wait_file(chan,ints,nextmsg,lang); 05305 } 05306 } else { 05307 /* 1910 - 1999 */ 05308 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year / 10); 05309 res = wait_file(chan,ints,nextmsg,lang); 05310 if (!res) { 05311 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year % 10); 05312 res = wait_file(chan,ints,nextmsg,lang); 05313 } 05314 } 05315 } 05316 } 05317 if (!res) { 05318 res = wait_file(chan,ints, "digits/year",lang); 05319 } 05320 } 05321 break; 05322 case 'I': 05323 case 'l': 05324 /* 12-Hour */ 05325 if (tm.tm_hour == 0) 05326 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 05327 else if (tm.tm_hour > 12) 05328 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 05329 else 05330 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 05331 res = wait_file(chan,ints,nextmsg,lang); 05332 if (!res) { 05333 res = wait_file(chan,ints, "digits/oclock",lang); 05334 } 05335 break; 05336 case 'H': 05337 case 'k': 05338 /* 24-Hour */ 05339 if (!(tm.tm_hour % 10) || tm.tm_hour < 10) { 05340 if (tm.tm_hour < 10) { 05341 res = wait_file(chan, ints, "digits/0", lang); 05342 } 05343 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 05344 res = wait_file(chan,ints,nextmsg,lang); 05345 } else { 05346 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - (tm.tm_hour % 10)); 05347 res = wait_file(chan,ints,nextmsg,lang); 05348 if (!res) { 05349 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour % 10); 05350 res = wait_file(chan,ints,nextmsg,lang); 05351 } 05352 } 05353 if (!res) { 05354 res = wait_file(chan,ints, "digits/oclock",lang); 05355 } 05356 break; 05357 case 'M': 05358 /* Minute */ 05359 if (!(tm.tm_min % 10) || tm.tm_min < 10) { 05360 if (tm.tm_min < 10) { 05361 res = wait_file(chan, ints, "digits/0", lang); 05362 } 05363 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 05364 res = wait_file(chan,ints,nextmsg,lang); 05365 } else { 05366 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min - (tm.tm_min % 10)); 05367 res = wait_file(chan,ints,nextmsg,lang); 05368 if (!res) { 05369 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min % 10); 05370 res = wait_file(chan,ints,nextmsg,lang); 05371 } 05372 } 05373 if (!res) { 05374 res = wait_file(chan,ints, "digits/minute",lang); 05375 } 05376 break; 05377 case 'P': 05378 case 'p': 05379 /* AM/PM */ 05380 if (tm.tm_hour > 11) 05381 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 05382 else 05383 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 05384 res = wait_file(chan,ints,nextmsg,lang); 05385 break; 05386 case 'Q': 05387 /* Shorthand for "Today", "Yesterday", or ABdY */ 05388 /* XXX As emphasized elsewhere, this should the native way in your 05389 * language to say the date, with changes in what you say, depending 05390 * upon how recent the date is. XXX */ 05391 { 05392 struct timeval now; 05393 struct tm tmnow; 05394 time_t beg_today, tt; 05395 05396 gettimeofday(&now,NULL); 05397 tt = now.tv_sec; 05398 ast_localtime(&tt,&tmnow,timezone); 05399 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 05400 /* In any case, it saves not having to do ast_mktime() */ 05401 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 05402 if (beg_today < time) { 05403 /* Today */ 05404 res = wait_file(chan,ints, "digits/today",lang); 05405 } else if (beg_today - 86400 < time) { 05406 /* Yesterday */ 05407 res = wait_file(chan,ints, "digits/yesterday",lang); 05408 } else { 05409 res = ast_say_date_with_format_tw(chan, time, ints, lang, "YBdA", timezone); 05410 } 05411 } 05412 break; 05413 case 'q': 05414 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 05415 /* XXX As emphasized elsewhere, this should the native way in your 05416 * language to say the date, with changes in what you say, depending 05417 * upon how recent the date is. XXX */ 05418 { 05419 struct timeval now; 05420 struct tm tmnow; 05421 time_t beg_today, tt; 05422 05423 gettimeofday(&now,NULL); 05424 tt = now.tv_sec; 05425 ast_localtime(&tt,&tmnow,timezone); 05426 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 05427 /* In any case, it saves not having to do ast_mktime() */ 05428 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 05429 if (beg_today < time) { 05430 /* Today */ 05431 } else if ((beg_today - 86400) < time) { 05432 /* Yesterday */ 05433 res = wait_file(chan,ints, "digits/yesterday",lang); 05434 } else if (beg_today - 86400 * 6 < time) { 05435 /* Within the last week */ 05436 res = ast_say_date_with_format_tw(chan, time, ints, lang, "A", timezone); 05437 } else { 05438 res = ast_say_date_with_format_tw(chan, time, ints, lang, "YBdA", timezone); 05439 } 05440 } 05441 break; 05442 case 'R': 05443 res = ast_say_date_with_format_tw(chan, time, ints, lang, "HM", timezone); 05444 break; 05445 case 'S': 05446 /* Seconds */ 05447 if (!(tm.tm_sec % 10) || tm.tm_sec < 10) { 05448 if (tm.tm_sec < 10) { 05449 res = wait_file(chan, ints, "digits/0", lang); 05450 } 05451 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 05452 res = wait_file(chan,ints,nextmsg,lang); 05453 } else { 05454 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec - (tm.tm_sec % 10)); 05455 res = wait_file(chan,ints,nextmsg,lang); 05456 if (!res) { 05457 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec % 10); 05458 res = wait_file(chan,ints,nextmsg,lang); 05459 } 05460 } 05461 if (!res) { 05462 res = wait_file(chan,ints, "digits/second",lang); 05463 } 05464 break; 05465 case 'T': 05466 res = ast_say_date_with_format_tw(chan, time, ints, lang, "HMS", timezone); 05467 break; 05468 case ' ': 05469 case ' ': 05470 /* Just ignore spaces and tabs */ 05471 break; 05472 default: 05473 /* Unknown character */ 05474 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 05475 } 05476 /* Jump out on DTMF */ 05477 if (res) { 05478 break; 05479 } 05480 } 05481 return res; 05482 } 05483 05484 static int say_time(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05485 { 05486 if (!strcasecmp(lang, "en") ) { /* English syntax */ 05487 return(ast_say_time_en(chan, t, ints, lang)); 05488 } else if (!strcasecmp(lang, "de") ) { /* German syntax */ 05489 return(ast_say_time_de(chan, t, ints, lang)); 05490 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */ 05491 return(ast_say_time_fr(chan, t, ints, lang)); 05492 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 05493 return(ast_say_time_nl(chan, t, ints, lang)); 05494 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 05495 return(ast_say_time_pt(chan, t, ints, lang)); 05496 } else if (!strcasecmp(lang, "pt_BR") ) { /* Brazilian Portuguese syntax */ 05497 return(ast_say_time_pt_BR(chan, t, ints, lang)); 05498 } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ 05499 } else if (!strcasecmp(lang, "tw") || !strcasecmp(lang, "zh") ) { /* Taiwanese / Chinese syntax */ 05500 return(ast_say_time_tw(chan, t, ints, lang)); 05501 } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */ 05502 return(ast_say_time_gr(chan, t, ints, lang)); 05503 } 05504 05505 /* Default to English */ 05506 return(ast_say_time_en(chan, t, ints, lang)); 05507 } 05508 05509 /* English syntax */ 05510 int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05511 { 05512 struct tm tm; 05513 int res = 0; 05514 int hour, pm=0; 05515 localtime_r(&t,&tm); 05516 hour = tm.tm_hour; 05517 if (!hour) 05518 hour = 12; 05519 else if (hour == 12) 05520 pm = 1; 05521 else if (hour > 12) { 05522 hour -= 12; 05523 pm = 1; 05524 } 05525 if (!res) 05526 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 05527 05528 if (tm.tm_min > 9) { 05529 if (!res) 05530 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05531 } else if (tm.tm_min) { 05532 if (!res) 05533 res = ast_streamfile(chan, "digits/oh", lang); 05534 if (!res) 05535 res = ast_waitstream(chan, ints); 05536 if (!res) 05537 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05538 } else { 05539 if (!res) 05540 res = ast_streamfile(chan, "digits/oclock", lang); 05541 if (!res) 05542 res = ast_waitstream(chan, ints); 05543 } 05544 if (pm) { 05545 if (!res) 05546 res = ast_streamfile(chan, "digits/p-m", lang); 05547 } else { 05548 if (!res) 05549 res = ast_streamfile(chan, "digits/a-m", lang); 05550 } 05551 if (!res) 05552 res = ast_waitstream(chan, ints); 05553 return res; 05554 } 05555 05556 /* German syntax */ 05557 int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05558 { 05559 struct tm tm; 05560 int res = 0; 05561 localtime_r(&t,&tm); 05562 if (!res) 05563 res = ast_say_number(chan, tm.tm_hour, ints, lang, "n"); 05564 if (!res) 05565 res = ast_streamfile(chan, "digits/oclock", lang); 05566 if (!res) 05567 res = ast_waitstream(chan, ints); 05568 if (!res) 05569 if (tm.tm_min > 0) 05570 res = ast_say_number(chan, tm.tm_min, ints, lang, "f"); 05571 return res; 05572 } 05573 05574 /* French syntax */ 05575 int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05576 { 05577 struct tm tm; 05578 int res = 0; 05579 localtime_r(&t,&tm); 05580 05581 res = ast_say_number(chan, tm.tm_hour, ints, lang, "f"); 05582 if (!res) 05583 res = ast_streamfile(chan, "digits/oclock", lang); 05584 if (tm.tm_min) { 05585 if (!res) 05586 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05587 } 05588 return res; 05589 } 05590 05591 /* Dutch syntax */ 05592 int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05593 { 05594 struct tm tm; 05595 int res = 0; 05596 localtime_r(&t,&tm); 05597 if (!res) 05598 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL); 05599 if (!res) 05600 res = ast_streamfile(chan, "digits/nl-uur", lang); 05601 if (!res) 05602 res = ast_waitstream(chan, ints); 05603 if (!res) 05604 if (tm.tm_min > 0) 05605 res = ast_say_number(chan, tm.tm_min, ints, lang, NULL); 05606 return res; 05607 } 05608 05609 /* Portuguese syntax */ 05610 int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05611 { 05612 struct tm tm; 05613 int res = 0; 05614 int hour; 05615 localtime_r(&t,&tm); 05616 hour = tm.tm_hour; 05617 if (!res) 05618 res = ast_say_number(chan, hour, ints, lang, "f"); 05619 if (tm.tm_min) { 05620 if (!res) 05621 res = wait_file(chan, ints, "digits/pt-e", lang); 05622 if (!res) 05623 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05624 } else { 05625 if (!res) 05626 res = wait_file(chan, ints, "digits/pt-hora", lang); 05627 if (tm.tm_hour != 1) 05628 if (!res) 05629 res = wait_file(chan, ints, "digits/pt-sss", lang); 05630 } 05631 if (!res) 05632 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 05633 return res; 05634 } 05635 05636 /* Brazilian Portuguese syntax */ 05637 int ast_say_time_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05638 { 05639 struct tm tm; 05640 int res = 0; 05641 localtime_r(&t,&tm); 05642 05643 res = ast_say_number(chan, tm.tm_hour, ints, lang, "f"); 05644 if (!res) { 05645 if (tm.tm_hour > 1) 05646 res = wait_file(chan, ints, "digits/hours", lang); 05647 else 05648 res = wait_file(chan, ints, "digits/hour", lang); 05649 } 05650 if ((!res) && (tm.tm_min)) { 05651 res = wait_file(chan, ints, "digits/pt-e", lang); 05652 if (!res) 05653 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05654 if (!res) { 05655 if (tm.tm_min > 1) 05656 res = wait_file(chan, ints, "digits/minutes", lang); 05657 else 05658 res = wait_file(chan, ints, "digits/minute", lang); 05659 } 05660 } 05661 return res; 05662 } 05663 05664 /* Taiwanese / Chinese syntax */ 05665 int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05666 { 05667 struct tm tm; 05668 int res = 0; 05669 int hour, pm=0; 05670 localtime_r(&t,&tm); 05671 hour = tm.tm_hour; 05672 if (!hour) 05673 hour = 12; 05674 else if (hour == 12) 05675 pm = 1; 05676 else if (hour > 12) { 05677 hour -= 12; 05678 pm = 1; 05679 } 05680 if (pm) { 05681 if (!res) 05682 res = ast_streamfile(chan, "digits/p-m", lang); 05683 } else { 05684 if (!res) 05685 res = ast_streamfile(chan, "digits/a-m", lang); 05686 } 05687 if (!res) 05688 res = ast_waitstream(chan, ints); 05689 if (!res) 05690 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 05691 if (!res) 05692 res = ast_streamfile(chan, "digits/oclock", lang); 05693 if (!res) 05694 res = ast_waitstream(chan, ints); 05695 if (!res) 05696 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05697 if (!res) 05698 res = ast_streamfile(chan, "digits/minute", lang); 05699 if (!res) 05700 res = ast_waitstream(chan, ints); 05701 return res; 05702 } 05703 05704 static int say_datetime(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05705 { 05706 if (!strcasecmp(lang, "en") ) { /* English syntax */ 05707 return(ast_say_datetime_en(chan, t, ints, lang)); 05708 } else if (!strcasecmp(lang, "de") ) { /* German syntax */ 05709 return(ast_say_datetime_de(chan, t, ints, lang)); 05710 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */ 05711 return(ast_say_datetime_fr(chan, t, ints, lang)); 05712 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 05713 return(ast_say_datetime_nl(chan, t, ints, lang)); 05714 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 05715 return(ast_say_datetime_pt(chan, t, ints, lang)); 05716 } else if (!strcasecmp(lang, "pt_BR") ) { /* Brazilian Portuguese syntax */ 05717 return(ast_say_datetime_pt_BR(chan, t, ints, lang)); 05718 } else if (!strcasecmp(lang, "tw") || !strcasecmp(lang, "zh") ) { /* Taiwanese / Chinese syntax */ 05719 return(ast_say_datetime_tw(chan, t, ints, lang)); 05720 } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */ 05721 return(ast_say_datetime_gr(chan, t, ints, lang)); 05722 } 05723 05724 /* Default to English */ 05725 return(ast_say_datetime_en(chan, t, ints, lang)); 05726 } 05727 05728 /* English syntax */ 05729 int ast_say_datetime_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05730 { 05731 struct tm tm; 05732 char fn[256]; 05733 int res = 0; 05734 int hour, pm=0; 05735 localtime_r(&t,&tm); 05736 if (!res) { 05737 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 05738 res = ast_streamfile(chan, fn, lang); 05739 if (!res) 05740 res = ast_waitstream(chan, ints); 05741 } 05742 if (!res) { 05743 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 05744 res = ast_streamfile(chan, fn, lang); 05745 if (!res) 05746 res = ast_waitstream(chan, ints); 05747 } 05748 if (!res) 05749 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 05750 05751 hour = tm.tm_hour; 05752 if (!hour) 05753 hour = 12; 05754 else if (hour == 12) 05755 pm = 1; 05756 else if (hour > 12) { 05757 hour -= 12; 05758 pm = 1; 05759 } 05760 if (!res) 05761 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 05762 05763 if (tm.tm_min > 9) { 05764 if (!res) 05765 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05766 } else if (tm.tm_min) { 05767 if (!res) 05768 res = ast_streamfile(chan, "digits/oh", lang); 05769 if (!res) 05770 res = ast_waitstream(chan, ints); 05771 if (!res) 05772 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05773 } else { 05774 if (!res) 05775 res = ast_streamfile(chan, "digits/oclock", lang); 05776 if (!res) 05777 res = ast_waitstream(chan, ints); 05778 } 05779 if (pm) { 05780 if (!res) 05781 res = ast_streamfile(chan, "digits/p-m", lang); 05782 } else { 05783 if (!res) 05784 res = ast_streamfile(chan, "digits/a-m", lang); 05785 } 05786 if (!res) 05787 res = ast_waitstream(chan, ints); 05788 if (!res) 05789 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 05790 return res; 05791 } 05792 05793 /* German syntax */ 05794 int ast_say_datetime_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05795 { 05796 struct tm tm; 05797 int res = 0; 05798 localtime_r(&t,&tm); 05799 res = ast_say_date(chan, t, ints, lang); 05800 if (!res) 05801 ast_say_time(chan, t, ints, lang); 05802 return res; 05803 05804 } 05805 05806 /* French syntax */ 05807 int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05808 { 05809 struct tm tm; 05810 char fn[256]; 05811 int res = 0; 05812 localtime_r(&t,&tm); 05813 05814 if (!res) 05815 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 05816 05817 if (!res) { 05818 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 05819 res = ast_streamfile(chan, fn, lang); 05820 if (!res) 05821 res = ast_waitstream(chan, ints); 05822 } 05823 if (!res) { 05824 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 05825 res = ast_streamfile(chan, fn, lang); 05826 if (!res) 05827 res = ast_waitstream(chan, ints); 05828 } 05829 05830 if (!res) 05831 res = ast_say_number(chan, tm.tm_hour, ints, lang, "f"); 05832 if (!res) 05833 res = ast_streamfile(chan, "digits/oclock", lang); 05834 if (tm.tm_min > 0) { 05835 if (!res) 05836 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05837 } 05838 if (!res) 05839 res = ast_waitstream(chan, ints); 05840 if (!res) 05841 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 05842 return res; 05843 } 05844 05845 /* Dutch syntax */ 05846 int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05847 { 05848 struct tm tm; 05849 int res = 0; 05850 localtime_r(&t,&tm); 05851 res = ast_say_date(chan, t, ints, lang); 05852 if (!res) { 05853 res = ast_streamfile(chan, "digits/nl-om", lang); 05854 if (!res) 05855 res = ast_waitstream(chan, ints); 05856 } 05857 if (!res) 05858 ast_say_time(chan, t, ints, lang); 05859 return res; 05860 } 05861 05862 /* Portuguese syntax */ 05863 int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05864 { 05865 struct tm tm; 05866 char fn[256]; 05867 int res = 0; 05868 int hour, pm=0; 05869 localtime_r(&t,&tm); 05870 if (!res) { 05871 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 05872 res = ast_streamfile(chan, fn, lang); 05873 if (!res) 05874 res = ast_waitstream(chan, ints); 05875 } 05876 if (!res) { 05877 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 05878 res = ast_streamfile(chan, fn, lang); 05879 if (!res) 05880 res = ast_waitstream(chan, ints); 05881 } 05882 if (!res) 05883 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 05884 05885 hour = tm.tm_hour; 05886 if (!hour) 05887 hour = 12; 05888 else if (hour == 12) 05889 pm = 1; 05890 else if (hour > 12) { 05891 hour -= 12; 05892 pm = 1; 05893 } 05894 if (!res) 05895 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 05896 05897 if (tm.tm_min > 9) { 05898 if (!res) 05899 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05900 } else if (tm.tm_min) { 05901 if (!res) 05902 res = ast_streamfile(chan, "digits/oh", lang); 05903 if (!res) 05904 res = ast_waitstream(chan, ints); 05905 if (!res) 05906 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05907 } else { 05908 if (!res) 05909 res = ast_streamfile(chan, "digits/oclock", lang); 05910 if (!res) 05911 res = ast_waitstream(chan, ints); 05912 } 05913 if (pm) { 05914 if (!res) 05915 res = ast_streamfile(chan, "digits/p-m", lang); 05916 } else { 05917 if (!res) 05918 res = ast_streamfile(chan, "digits/a-m", lang); 05919 } 05920 if (!res) 05921 res = ast_waitstream(chan, ints); 05922 if (!res) 05923 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 05924 return res; 05925 } 05926 05927 /* Brazilian Portuguese syntax */ 05928 int ast_say_datetime_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05929 { 05930 struct tm tm; 05931 int res = 0; 05932 localtime_r(&t,&tm); 05933 res = ast_say_date(chan, t, ints, lang); 05934 if (!res) 05935 res = ast_say_time(chan, t, ints, lang); 05936 return res; 05937 } 05938 05939 /* Taiwanese / Chinese syntax */ 05940 int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05941 { 05942 struct tm tm; 05943 char fn[256]; 05944 int res = 0; 05945 int hour, pm=0; 05946 localtime_r(&t,&tm); 05947 if (!res) 05948 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 05949 if (!res) { 05950 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 05951 res = ast_streamfile(chan, fn, lang); 05952 if (!res) 05953 res = ast_waitstream(chan, ints); 05954 } 05955 if (!res) 05956 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 05957 if (!res) { 05958 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 05959 res = ast_streamfile(chan, fn, lang); 05960 if (!res) 05961 res = ast_waitstream(chan, ints); 05962 } 05963 05964 hour = tm.tm_hour; 05965 if (!hour) 05966 hour = 12; 05967 else if (hour == 12) 05968 pm = 1; 05969 else if (hour > 12) { 05970 hour -= 12; 05971 pm = 1; 05972 } 05973 if (pm) { 05974 if (!res) 05975 res = ast_streamfile(chan, "digits/p-m", lang); 05976 } else { 05977 if (!res) 05978 res = ast_streamfile(chan, "digits/a-m", lang); 05979 } 05980 if (!res) 05981 res = ast_waitstream(chan, ints); 05982 if (!res) 05983 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 05984 if (!res) 05985 res = ast_streamfile(chan, "digits/oclock", lang); 05986 if (!res) 05987 res = ast_waitstream(chan, ints); 05988 if (!res) 05989 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 05990 if (!res) 05991 res = ast_streamfile(chan, "digits/minute", lang); 05992 if (!res) 05993 res = ast_waitstream(chan, ints); 05994 return res; 05995 } 05996 05997 static int say_datetime_from_now(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 05998 { 05999 if (!strcasecmp(lang, "en") ) { /* English syntax */ 06000 return(ast_say_datetime_from_now_en(chan, t, ints, lang)); 06001 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */ 06002 return(ast_say_datetime_from_now_fr(chan, t, ints, lang)); 06003 } else if (!strcasecmp(lang, "pt") || !strcasecmp(lang, "pt_BR")) { /* Portuguese syntax */ 06004 return(ast_say_datetime_from_now_pt(chan, t, ints, lang)); 06005 } 06006 06007 /* Default to English */ 06008 return(ast_say_datetime_from_now_en(chan, t, ints, lang)); 06009 } 06010 06011 /* English syntax */ 06012 int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 06013 { 06014 int res=0; 06015 time_t nowt; 06016 int daydiff; 06017 struct tm tm; 06018 struct tm now; 06019 char fn[256]; 06020 06021 time(&nowt); 06022 06023 localtime_r(&t,&tm); 06024 localtime_r(&nowt,&now); 06025 daydiff = now.tm_yday - tm.tm_yday; 06026 if ((daydiff < 0) || (daydiff > 6)) { 06027 /* Day of month and month */ 06028 if (!res) { 06029 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 06030 res = ast_streamfile(chan, fn, lang); 06031 if (!res) 06032 res = ast_waitstream(chan, ints); 06033 } 06034 if (!res) 06035 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 06036 06037 } else if (daydiff) { 06038 /* Just what day of the week */ 06039 if (!res) { 06040 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 06041 res = ast_streamfile(chan, fn, lang); 06042 if (!res) 06043 res = ast_waitstream(chan, ints); 06044 } 06045 } /* Otherwise, it was today */ 06046 if (!res) 06047 res = ast_say_time(chan, t, ints, lang); 06048 return res; 06049 } 06050 06051 /* French syntax */ 06052 int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 06053 { 06054 int res=0; 06055 time_t nowt; 06056 int daydiff; 06057 struct tm tm; 06058 struct tm now; 06059 char fn[256]; 06060 06061 time(&nowt); 06062 06063 localtime_r(&t,&tm); 06064 localtime_r(&nowt,&now); 06065 daydiff = now.tm_yday - tm.tm_yday; 06066 if ((daydiff < 0) || (daydiff > 6)) { 06067 /* Day of month and month */ 06068 if (!res) { 06069 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 06070 res = ast_streamfile(chan, fn, lang); 06071 if (!res) 06072 res = ast_waitstream(chan, ints); 06073 } 06074 if (!res) 06075 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 06076 06077 } else if (daydiff) { 06078 /* Just what day of the week */ 06079 if (!res) { 06080 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 06081 res = ast_streamfile(chan, fn, lang); 06082 if (!res) 06083 res = ast_waitstream(chan, ints); 06084 } 06085 } /* Otherwise, it was today */ 06086 if (!res) 06087 res = ast_say_time(chan, t, ints, lang); 06088 return res; 06089 } 06090 06091 /* Portuguese syntax */ 06092 int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 06093 { 06094 int res=0; 06095 time_t nowt; 06096 int daydiff; 06097 struct tm tm; 06098 struct tm now; 06099 char fn[256]; 06100 06101 time(&nowt); 06102 06103 localtime_r(&t,&tm); 06104 localtime_r(&nowt,&now); 06105 daydiff = now.tm_yday - tm.tm_yday; 06106 if ((daydiff < 0) || (daydiff > 6)) { 06107 /* Day of month and month */ 06108 if (!res) 06109 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 06110 if (!res) 06111 res = wait_file(chan, ints, "digits/pt-de", lang); 06112 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 06113 if (!res) 06114 res = wait_file(chan, ints, fn, lang); 06115 06116 } else if (daydiff) { 06117 /* Just what day of the week */ 06118 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 06119 if (!res) 06120 res = wait_file(chan, ints, fn, lang); 06121 } /* Otherwise, it was today */ 06122 if (!strcasecmp(lang, "pt_BR")) { 06123 if (tm.tm_hour > 1) { 06124 snprintf(fn, sizeof(fn), "digits/pt-as"); 06125 } else { 06126 snprintf(fn, sizeof(fn), "digits/pt-a"); 06127 } 06128 if (!res) 06129 res = wait_file(chan, ints, fn, lang); 06130 } else { 06131 snprintf(fn, sizeof(fn), "digits/pt-ah"); 06132 if (!res) 06133 res = wait_file(chan, ints, fn, lang); 06134 if (tm.tm_hour != 1) 06135 if (!res) 06136 res = wait_file(chan, ints, "digits/pt-sss", lang); 06137 if (!res) 06138 res = ast_say_time(chan, t, ints, lang); 06139 } 06140 return res; 06141 } 06142 06143 06144 /*********************************** GREEK SUPPORT ***************************************/ 06145 06146 06147 /* 06148 * digits/female-[1..4] : "Mia, dyo , treis, tessereis" 06149 */ 06150 static int gr_say_number_female(int num, struct ast_channel *chan, const char *ints, const char *lang){ 06151 int tmp; 06152 int left; 06153 int res; 06154 char fn[256] = ""; 06155 06156 /* ast_log(LOG_DEBUG, "\n\n Saying number female %s %d \n\n",lang, num); */ 06157 if (num < 5) { 06158 snprintf(fn, sizeof(fn), "digits/female-%d", num); 06159 res = wait_file(chan, ints, fn, lang); 06160 } else if (num < 13) { 06161 res = ast_say_number(chan, num, ints, lang, (char *) NULL); 06162 } else if (num <100 ) { 06163 tmp = (num/10) * 10; 06164 left = num - tmp; 06165 snprintf(fn, sizeof(fn), "digits/%d", tmp); 06166 res = ast_streamfile(chan, fn, lang); 06167 if (!res) 06168 res = ast_waitstream(chan, ints); 06169 if (left) 06170 gr_say_number_female(left, chan, ints, lang); 06171 06172 } else { 06173 return -1; 06174 } 06175 return res; 06176 } 06177 06178 06179 06180 /* 06181 * A list of the files that you need to create 06182 -> digits/xilia = "xilia" 06183 -> digits/myrio = "ekatomyrio" 06184 -> digits/thousands = "xiliades" 06185 -> digits/millions = "ektatomyria" 06186 -> digits/[1..12] :: A pronunciation of th digits form 1 to 12 e.g. "tria" 06187 -> digits/[10..100] :: A pronunciation of the tens from 10 to 90 06188 e,g 80 = "ogdonta" 06189 Here we must note that we use digits/tens/100 to utter "ekato" 06190 and digits/hundred-100 to utter "ekaton" 06191 -> digits/hundred-[100...1000] :: A pronunciation of hundreds from 100 to 1000 e.g 400 = 06192 "terakosia". Here again we use hundreds/1000 for "xilia" 06193 and digits/thousnds for "xiliades" 06194 */ 06195 06196 static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char *ints, const char *language,int audiofd, int ctrlfd) 06197 { 06198 int res = 0; 06199 char fn[256] = ""; 06200 int i=0; 06201 06202 06203 if (!num) { 06204 snprintf(fn, sizeof(fn), "digits/0"); 06205 res = ast_streamfile(chan, fn, chan->language); 06206 if (!res) 06207 return ast_waitstream(chan, ints); 06208 } 06209 06210 while (!res && num ) { 06211 i++; 06212 if (num < 13) { 06213 snprintf(fn, sizeof(fn), "digits/%d", num); 06214 num = 0; 06215 } else if (num <= 100) { 06216 /* 13 < num <= 100 */ 06217 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 06218 num -= ((num / 10) * 10); 06219 } else if (num < 200) { 06220 /* 100 < num < 200 */ 06221 snprintf(fn, sizeof(fn), "digits/hundred-100"); 06222 num -= ((num / 100) * 100); 06223 }else if (num < 1000) { 06224 /* 200 < num < 1000 */ 06225 snprintf(fn, sizeof(fn), "digits/hundred-%d", (num/100)*100); 06226 num -= ((num / 100) * 100); 06227 }else if (num < 2000){ 06228 snprintf(fn, sizeof(fn), "digits/xilia"); 06229 num -= ((num / 1000) * 1000); 06230 } 06231 else { 06232 /* num > 1000 */ 06233 if (num < 1000000) { 06234 res = ast_say_number_full_gr(chan, (num / 1000), ints, chan->language, audiofd, ctrlfd); 06235 if (res) 06236 return res; 06237 num = num % 1000; 06238 snprintf(fn, sizeof(fn), "digits/thousands"); 06239 } else { 06240 if (num < 1000000000) { /* 1,000,000,000 */ 06241 res = ast_say_number_full_gr(chan, (num / 1000000), ints, chan->language ,audiofd, ctrlfd); 06242 if (res) 06243 return res; 06244 num = num % 1000000; 06245 snprintf(fn, sizeof(fn), "digits/millions"); 06246 } else { 06247 if (option_debug) 06248 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 06249 res = -1; 06250 } 06251 } 06252 } 06253 if (!res) { 06254 if (!ast_streamfile(chan, fn, language)) { 06255 if ((audiofd > -1) && (ctrlfd > -1)) 06256 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 06257 else 06258 res = ast_waitstream(chan, ints); 06259 } 06260 ast_stopstream(chan); 06261 } 06262 } 06263 return res; 06264 } 06265 06266 06267 /* 06268 * The format is weekday - day - month -year 06269 * 06270 * A list of the files that you need to create 06271 * digits/day-[1..7] : "Deytera .. Paraskeyh" 06272 * digits/months/1..12 : "Ianouariou .. Dekembriou" 06273 Attention the months are in 06274 "gekinh klhsh" 06275 */ 06276 06277 06278 static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 06279 { 06280 struct tm tm; 06281 06282 char fn[256]; 06283 int res = 0; 06284 06285 06286 ast_localtime(&t,&tm,NULL); 06287 /* W E E K - D A Y */ 06288 if (!res) { 06289 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 06290 res = ast_streamfile(chan, fn, lang); 06291 if (!res) 06292 res = ast_waitstream(chan, ints); 06293 } 06294 /* D A Y */ 06295 if (!res) { 06296 gr_say_number_female(tm.tm_mday, chan, ints, lang); 06297 } 06298 /* M O N T H */ 06299 if (!res) { 06300 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 06301 res = ast_streamfile(chan, fn, lang); 06302 if (!res) 06303 res = ast_waitstream(chan, ints); 06304 } 06305 /* Y E A R */ 06306 if (!res) 06307 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 06308 return res; 06309 } 06310 06311 06312 06313 /* A list of the files that you need to create 06314 * digits/female/1..4 : "Mia, dyo , treis, tesseris " 06315 * digits/kai : "KAI" 06316 * didgits : "h wra" 06317 * digits/p-m : "meta meshmbrias" 06318 * digits/a-m : "pro meshmbrias" 06319 */ 06320 06321 static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 06322 { 06323 06324 struct tm tm; 06325 int res = 0; 06326 int hour, pm=0; 06327 06328 localtime_r(&t,&tm); 06329 hour = tm.tm_hour; 06330 06331 if (!hour) 06332 hour = 12; 06333 else if (hour == 12) 06334 pm = 1; 06335 else if (hour > 12) { 06336 hour -= 12; 06337 pm = 1; 06338 } 06339 06340 res = gr_say_number_female(hour, chan, ints, lang); 06341 if (tm.tm_min) { 06342 if (!res) 06343 res = ast_streamfile(chan, "digits/kai", lang); 06344 if (!res) 06345 res = ast_waitstream(chan, ints); 06346 if (!res) 06347 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 06348 } else { 06349 if (!res) 06350 res = ast_streamfile(chan, "digits/hwra", lang); 06351 if (!res) 06352 res = ast_waitstream(chan, ints); 06353 } 06354 if (pm) { 06355 if (!res) 06356 res = ast_streamfile(chan, "digits/p-m", lang); 06357 } else { 06358 if (!res) 06359 res = ast_streamfile(chan, "digits/a-m", lang); 06360 } 06361 if (!res) 06362 res = ast_waitstream(chan, ints); 06363 return res; 06364 } 06365 06366 06367 06368 static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang) 06369 { 06370 struct tm tm; 06371 char fn[256]; 06372 int res = 0; 06373 localtime_r(&t,&tm); 06374 06375 06376 /* W E E K - D A Y */ 06377 if (!res) { 06378 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 06379 res = ast_streamfile(chan, fn, lang); 06380 if (!res) 06381 res = ast_waitstream(chan, ints); 06382 } 06383 /* D A Y */ 06384 if (!res) { 06385 gr_say_number_female(tm.tm_mday, chan, ints, lang); 06386 } 06387 /* M O N T H */ 06388 if (!res) { 06389 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 06390 res = ast_streamfile(chan, fn, lang); 06391 if (!res) 06392 res = ast_waitstream(chan, ints); 06393 } 06394 06395 res = ast_say_time_gr(chan, t, ints, lang); 06396 return res; 06397 } 06398 06399 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) 06400 { 06401 06402 struct tm tm; 06403 int res=0, offset, sndoffset; 06404 char sndfile[256], nextmsg[256]; 06405 06406 if (!format) 06407 format = "AdBY 'digits/at' IMp"; 06408 06409 ast_localtime(&time,&tm,timezone); 06410 06411 for (offset=0 ; format[offset] != '\0' ; offset++) { 06412 if (option_debug) 06413 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 06414 switch (format[offset]) { 06415 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 06416 case '\'': 06417 /* Literal name of a sound file */ 06418 sndoffset=0; 06419 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 06420 sndfile[sndoffset] = format[offset]; 06421 sndfile[sndoffset] = '\0'; 06422 res = wait_file(chan,ints,sndfile,lang); 06423 break; 06424 case 'A': 06425 case 'a': 06426 /* Sunday - Saturday */ 06427 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 06428 res = wait_file(chan,ints,nextmsg,lang); 06429 break; 06430 case 'B': 06431 case 'b': 06432 case 'h': 06433 /* January - December */ 06434 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 06435 res = wait_file(chan,ints,nextmsg,lang); 06436 break; 06437 case 'd': 06438 case 'e': 06439 /* first - thirtyfirst */ 06440 gr_say_number_female(tm.tm_mday, chan, ints, lang); 06441 break; 06442 case 'Y': 06443 /* Year */ 06444 06445 ast_say_number_full_gr(chan, 1900+tm.tm_year, ints, chan->language, -1, -1); 06446 break; 06447 case 'I': 06448 case 'l': 06449 /* 12-Hour */ 06450 if (tm.tm_hour == 0) 06451 gr_say_number_female(12, chan, ints, lang); 06452 else if (tm.tm_hour > 12) 06453 gr_say_number_female(tm.tm_hour - 12, chan, ints, lang); 06454 else 06455 gr_say_number_female(tm.tm_hour, chan, ints, lang); 06456 break; 06457 case 'H': 06458 case 'k': 06459 /* 24-Hour */ 06460 gr_say_number_female(tm.tm_hour, chan, ints, lang); 06461 break; 06462 case 'M': 06463 /* Minute */ 06464 if (tm.tm_min) { 06465 if (!res) 06466 res = ast_streamfile(chan, "digits/kai", lang); 06467 if (!res) 06468 res = ast_waitstream(chan, ints); 06469 if (!res) 06470 res = ast_say_number_full_gr(chan, tm.tm_min, ints, lang, -1, -1); 06471 } else { 06472 if (!res) 06473 res = ast_streamfile(chan, "digits/oclock", lang); 06474 if (!res) 06475 res = ast_waitstream(chan, ints); 06476 } 06477 break; 06478 case 'P': 06479 case 'p': 06480 /* AM/PM */ 06481 if (tm.tm_hour > 11) 06482 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 06483 else 06484 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 06485 res = wait_file(chan,ints,nextmsg,lang); 06486 break; 06487 case 'Q': 06488 /* Shorthand for "Today", "Yesterday", or ABdY */ 06489 /* XXX As emphasized elsewhere, this should the native way in your 06490 * language to say the date, with changes in what you say, depending 06491 * upon how recent the date is. XXX */ 06492 { 06493 struct timeval now; 06494 struct tm tmnow; 06495 time_t beg_today, tt; 06496 06497 gettimeofday(&now,NULL); 06498 tt = now.tv_sec; 06499 ast_localtime(&tt,&tmnow,timezone); 06500 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 06501 /* In any case, it saves not having to do ast_mktime() */ 06502 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 06503 if (beg_today < time) { 06504 /* Today */ 06505 res = wait_file(chan,ints, "digits/today",lang); 06506 } else if (beg_today - 86400 < time) { 06507 /* Yesterday */ 06508 res = wait_file(chan,ints, "digits/yesterday",lang); 06509 } else { 06510 res = ast_say_date_with_format_gr(chan, time, ints, lang, "AdBY", timezone); 06511 } 06512 } 06513 break; 06514 case 'q': 06515 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 06516 /* XXX As emphasized elsewhere, this should the native way in your 06517 * language to say the date, with changes in what you say, depending 06518 * upon how recent the date is. XXX */ 06519 { 06520 struct timeval now; 06521 struct tm tmnow; 06522 time_t beg_today, tt; 06523 06524 gettimeofday(&now,NULL); 06525 tt = now.tv_sec; 06526 ast_localtime(&tt,&tmnow,timezone); 06527 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 06528 /* In any case, it saves not having to do ast_mktime() */ 06529 beg_today = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 06530 if (beg_today < time) { 06531 /* Today */ 06532 } else if ((beg_today - 86400) < time) { 06533 /* Yesterday */ 06534 res = wait_file(chan,ints, "digits/yesterday",lang); 06535 } else if (beg_today - 86400 * 6 < time) { 06536 /* Within the last week */ 06537 res = ast_say_date_with_format_gr(chan, time, ints, lang, "A", timezone); 06538 } else { 06539 res = ast_say_date_with_format_gr(chan, time, ints, lang, "AdBY", timezone); 06540 } 06541 } 06542 break; 06543 case 'R': 06544 res = ast_say_date_with_format_gr(chan, time, ints, lang, "HM", timezone); 06545 break; 06546 case 'S': 06547 /* Seconds */ 06548 snprintf(nextmsg,sizeof(nextmsg), "digits/kai"); 06549 res = wait_file(chan,ints,nextmsg,lang); 06550 if (!res) 06551 res = ast_say_number_full_gr(chan, tm.tm_sec, ints, lang, -1, -1); 06552 if (!res) 06553 snprintf(nextmsg,sizeof(nextmsg), "digits/seconds"); 06554 res = wait_file(chan,ints,nextmsg,lang); 06555 break; 06556 case 'T': 06557 res = ast_say_date_with_format_gr(chan, time, ints, lang, "HMS", timezone); 06558 break; 06559 case ' ': 06560 case ' ': 06561 /* Just ignore spaces and tabs */ 06562 break; 06563 default: 06564 /* Unknown character */ 06565 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 06566 } 06567 /* Jump out on DTMF */ 06568 if (res) { 06569 break; 06570 } 06571 } 06572 return res; 06573 } 06574 06575 /* 06576 * remap the 'say' functions to use those in this file 06577 */ 06578 static void __attribute__((constructor)) __say_init(void) 06579 { 06580 ast_say_number_full = say_number_full; 06581 ast_say_enumeration_full = say_enumeration_full; 06582 ast_say_digit_str_full = say_digit_str_full; 06583 ast_say_character_str_full = say_character_str_full; 06584 ast_say_phonetic_str_full = say_phonetic_str_full; 06585 ast_say_datetime = say_datetime; 06586 ast_say_time = say_time; 06587 ast_say_date = say_date; 06588 ast_say_datetime_from_now = say_datetime_from_now; 06589 ast_say_date_with_format = say_date_with_format; 06590 }