Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

say.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * Say numbers and dates (maybe words one day too) 00005 * 00006 * Copyright (C) 1999, Mark Spencer 00007 * 00008 * Mark Spencer <markster@linux-support.net> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License 00012 */ 00013 00014 #include <sys/types.h> 00015 #include <string.h> 00016 #include <stdlib.h> 00017 #include <netinet/in.h> 00018 #include <time.h> 00019 #include <ctype.h> 00020 #include <math.h> 00021 #include <asterisk/file.h> 00022 #include <asterisk/channel.h> 00023 #include <asterisk/logger.h> 00024 #include <asterisk/say.h> 00025 #include <asterisk/lock.h> 00026 #include <asterisk/localtime.h> 00027 #include <asterisk/utils.h> 00028 #include "asterisk.h" 00029 #include <stdio.h> 00030 00031 00032 /* Forward declaration */ 00033 static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang); 00034 00035 int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang) 00036 { 00037 /* XXX Merge with full version? XXX */ 00038 char fn[256] = ""; 00039 int num = 0; 00040 int res = 0; 00041 while(fn2[num] && !res) { 00042 fn[0] = '\0'; 00043 switch (fn2[num]) { 00044 case ('*'): 00045 snprintf(fn, sizeof(fn), "digits/star"); 00046 break; 00047 case ('#'): 00048 snprintf(fn, sizeof(fn), "digits/pound"); 00049 break; 00050 default: 00051 if((fn2[num] >= '0') && (fn2[num] <= '9')){ /* Must be in {0-9} */ 00052 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); 00053 } 00054 } 00055 if(!ast_strlen_zero(fn)){ /* if length == 0, then skip this digit as it is invalid */ 00056 res = ast_streamfile(chan, fn, lang); 00057 if (!res) 00058 res = ast_waitstream(chan, ints); 00059 ast_stopstream(chan); 00060 } 00061 num++; 00062 } 00063 return res; 00064 } 00065 00066 int ast_say_character_str(struct ast_channel *chan, char *fn2, char *ints, char *lang) 00067 { 00068 /* XXX Merge with full version? XXX */ 00069 char fn[256] = ""; 00070 char ltr; 00071 int num = 0; 00072 int res = 0; 00073 while(fn2[num] && !res) { 00074 fn[0] = '\0'; 00075 switch (fn2[num]) { 00076 case ('*'): 00077 snprintf(fn, sizeof(fn), "digits/star"); 00078 break; 00079 case ('#'): 00080 snprintf(fn, sizeof(fn), "digits/pound"); 00081 break; 00082 case ('0'): 00083 case ('1'): 00084 case ('2'): 00085 case ('3'): 00086 case ('4'): 00087 case ('5'): 00088 case ('6'): 00089 case ('7'): 00090 case ('8'): 00091 case ('9'): 00092 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); 00093 break; 00094 case ('!'): 00095 strncpy(fn, "letters/exclaimation-point", sizeof(fn)); 00096 break; 00097 case ('@'): 00098 strncpy(fn, "letters/at", sizeof(fn)); 00099 break; 00100 case ('$'): 00101 strncpy(fn, "letters/dollar", sizeof(fn)); 00102 break; 00103 case ('-'): 00104 strncpy(fn, "letters/dash", sizeof(fn)); 00105 break; 00106 case ('.'): 00107 strncpy(fn, "letters/dot", sizeof(fn)); 00108 break; 00109 case ('='): 00110 strncpy(fn, "letters/equals", sizeof(fn)); 00111 break; 00112 case ('+'): 00113 strncpy(fn, "letters/plus", sizeof(fn)); 00114 break; 00115 case ('/'): 00116 strncpy(fn, "letters/slash", sizeof(fn)); 00117 break; 00118 case (' '): 00119 strncpy(fn, "letters/space", sizeof(fn)); 00120 break; 00121 default: 00122 ltr = fn2[num]; 00123 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */ 00124 snprintf(fn, sizeof(fn), "letters/%c", ltr); 00125 } 00126 if(!ast_strlen_zero(fn)) { /* if length == 0, then skip this digit as it is invalid */ 00127 res = ast_streamfile(chan, fn, lang); 00128 if (!res) 00129 res = ast_waitstream(chan, ints); 00130 } ast_stopstream(chan); 00131 num++; 00132 } 00133 return res; 00134 } 00135 00136 int ast_say_phonetic_str(struct ast_channel *chan, char *fn2, char *ints, char *lang) 00137 { 00138 /* XXX Merge with full version? XXX */ 00139 char fn[256] = ""; 00140 char ltr; 00141 int num = 0; 00142 int res = 0; 00143 int temp; 00144 int play; 00145 char hex[3]; 00146 /* while(fn2[num] && !res) { */ 00147 while(fn2[num]) { 00148 play=1; 00149 switch (fn2[num]) { 00150 case ('*'): 00151 snprintf(fn, sizeof(fn), "digits/star"); 00152 break; 00153 case ('#'): 00154 snprintf(fn, sizeof(fn), "digits/pound"); 00155 break; 00156 case ('0'): 00157 case ('1'): 00158 case ('2'): 00159 case ('3'): 00160 case ('4'): 00161 case ('5'): 00162 case ('6'): 00163 case ('7'): 00164 case ('8'): 00165 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); 00166 break; 00167 case ('!'): 00168 strncpy(fn, "exclaimation-point", sizeof(fn)); 00169 break; 00170 case ('@'): 00171 strncpy(fn, "at", sizeof(fn)); 00172 break; 00173 case ('$'): 00174 strncpy(fn, "dollar", sizeof(fn)); 00175 break; 00176 case ('-'): 00177 strncpy(fn, "dash", sizeof(fn)); 00178 break; 00179 case ('.'): 00180 strncpy(fn, "dot", sizeof(fn)); 00181 break; 00182 case ('='): 00183 strncpy(fn, "equals", sizeof(fn)); 00184 break; 00185 case ('+'): 00186 strncpy(fn, "plus", sizeof(fn)); 00187 break; 00188 case ('/'): 00189 strncpy(fn, "slash", sizeof(fn)); 00190 break; 00191 case (' '): 00192 strncpy(fn, "space", sizeof(fn)); 00193 break; 00194 case ('%'): 00195 play=0; 00196 /* check if we have 2 chars after the % */ 00197 if (strlen(fn2) > num+2) 00198 { 00199 hex[0]=fn2[num+1]; 00200 hex[1]=fn2[num+2]; 00201 hex[2]='\0'; 00202 if (sscanf(hex,"%x", &temp)) 00203 { /* Hex to char convertion successfull */ 00204 fn2[num+2]=temp; 00205 num++; 00206 if (temp==37) 00207 { /* If it is a percent, play it now */ 00208 strncpy(fn, "percent", sizeof(fn)); 00209 num++; 00210 play=1; 00211 } 00212 /* check for invalid characters */ 00213 if ((temp<32) || (temp>126)) 00214 { 00215 num++; 00216 } 00217 } 00218 } 00219 else 00220 num++; 00221 break; 00222 default: /* '9' falls through to here, too */ 00223 ltr = tolower(fn2[num]); 00224 snprintf(fn, sizeof(fn), "phonetic/%c_p", ltr); 00225 } 00226 if (play) 00227 { 00228 res = ast_streamfile(chan, fn, lang); 00229 if (!res) 00230 res = ast_waitstream(chan, ints); 00231 ast_stopstream(chan); 00232 } 00233 num++; 00234 } 00235 return res; 00236 } 00237 00238 int ast_say_digit_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd) 00239 { 00240 char fn[256] = ""; 00241 int num = 0; 00242 int res = 0; 00243 while(fn2[num] && !res) { 00244 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); 00245 res = ast_streamfile(chan, fn, lang); 00246 if (!res) 00247 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00248 ast_stopstream(chan); 00249 num++; 00250 } 00251 return res; 00252 } 00253 00254 int ast_say_character_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd) 00255 { 00256 char fn[256] = ""; 00257 char ltr; 00258 int num = 0; 00259 int res = 0; 00260 while(fn2[num] && !res) { 00261 switch (fn2[num]) { 00262 case ('*'): 00263 snprintf(fn, sizeof(fn), "digits/star"); 00264 break; 00265 case ('#'): 00266 snprintf(fn, sizeof(fn), "digits/pound"); 00267 break; 00268 case ('0'): 00269 case ('1'): 00270 case ('2'): 00271 case ('3'): 00272 case ('4'): 00273 case ('5'): 00274 case ('6'): 00275 case ('7'): 00276 case ('8'): 00277 case ('9'): 00278 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); 00279 break; 00280 case ('!'): 00281 strncpy(fn, "exclaimation-point", sizeof(fn)); 00282 break; 00283 case ('@'): 00284 strncpy(fn, "at", sizeof(fn)); 00285 break; 00286 case ('$'): 00287 strncpy(fn, "dollar", sizeof(fn)); 00288 break; 00289 case ('-'): 00290 strncpy(fn, "dash", sizeof(fn)); 00291 break; 00292 case ('.'): 00293 strncpy(fn, "dot", sizeof(fn)); 00294 break; 00295 case ('='): 00296 strncpy(fn, "equals", sizeof(fn)); 00297 break; 00298 case ('+'): 00299 strncpy(fn, "plus", sizeof(fn)); 00300 break; 00301 case ('/'): 00302 strncpy(fn, "slash", sizeof(fn)); 00303 break; 00304 case (' '): 00305 strncpy(fn, "space", sizeof(fn)); 00306 break; 00307 default: 00308 ltr = fn2[num]; 00309 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */ 00310 snprintf(fn, sizeof(fn), "letters/%c", ltr); 00311 } 00312 /* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */ 00313 res = ast_streamfile(chan, fn, lang); 00314 if (!res) 00315 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00316 ast_stopstream(chan); 00317 num++; 00318 } 00319 return res; 00320 } 00321 00322 int ast_say_phonetic_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd) 00323 { 00324 char fn[256] = ""; 00325 char ltr; 00326 int num = 0; 00327 int res = 0; 00328 while(fn2[num] && !res) { 00329 switch (fn2[num]) { 00330 case ('*'): 00331 snprintf(fn, sizeof(fn), "digits/star"); 00332 break; 00333 case ('#'): 00334 snprintf(fn, sizeof(fn), "digits/pound"); 00335 break; 00336 case ('0'): 00337 case ('1'): 00338 case ('2'): 00339 case ('3'): 00340 case ('4'): 00341 case ('5'): 00342 case ('6'): 00343 case ('7'): 00344 case ('8'): 00345 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); 00346 break; 00347 case ('!'): 00348 strncpy(fn, "exclaimation-point", sizeof(fn)); 00349 break; 00350 case ('@'): 00351 strncpy(fn, "at", sizeof(fn)); 00352 break; 00353 case ('$'): 00354 strncpy(fn, "dollar", sizeof(fn)); 00355 break; 00356 case ('-'): 00357 strncpy(fn, "dash", sizeof(fn)); 00358 break; 00359 case ('.'): 00360 strncpy(fn, "dot", sizeof(fn)); 00361 break; 00362 case ('='): 00363 strncpy(fn, "equals", sizeof(fn)); 00364 break; 00365 case ('+'): 00366 strncpy(fn, "plus", sizeof(fn)); 00367 break; 00368 case ('/'): 00369 strncpy(fn, "slash", sizeof(fn)); 00370 break; 00371 case (' '): 00372 strncpy(fn, "space", sizeof(fn)); 00373 break; 00374 default: /* '9' falls here... */ 00375 ltr = fn2[num]; 00376 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */ 00377 snprintf(fn, sizeof(fn), "phonetic/%c", ltr); 00378 } 00379 /* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */ 00380 res = ast_streamfile(chan, fn, lang); 00381 if (!res) 00382 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00383 ast_stopstream(chan); 00384 num++; 00385 } 00386 return res; 00387 } 00388 00389 int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang) 00390 { 00391 /* XXX Should I be merged with say_digits_full XXX */ 00392 char fn2[256]; 00393 snprintf(fn2, sizeof(fn2), "%d", num); 00394 return ast_say_digit_str(chan, fn2, ints, lang); 00395 } 00396 00397 int ast_say_digits_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd) 00398 { 00399 char fn2[256]; 00400 snprintf(fn2, sizeof(fn2), "%d", num); 00401 return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd); 00402 } 00403 00404 /* Forward declarations */ 00405 /* Syntaxes supported, not really language codes. 00406 da - Danish 00407 de - German 00408 en - English 00409 es - Spanish, Mexican 00410 fr - French 00411 it - Italian 00412 nl - Dutch 00413 pl - Polish 00414 pt - Portuguese 00415 se - Swedish 00416 tw - Taiwanese 00417 00418 Gender: 00419 For Portuguese, French & Spanish, we're using m & f options to saynumber() to indicate if the gender is masculine or feminine. 00420 For Danish, we're using c & n options to saynumber() to indicate if the gender is commune or neutrum. 00421 This still needs to be implemented for German (although the option is passed to the function, it currently does nothing with it). 00422 00423 Date/Time functions currently have less languages supported than saynumber(). 00424 00425 Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK 00426 00427 See contrib/i18n.testsuite.conf for some examples of the different syntaxes 00428 00429 Portuguese sound files needed for Time/Date functions: 00430 pt-ah 00431 pt-ao 00432 pt-de 00433 pt-e 00434 pt-ora 00435 pt-meianoite 00436 pt-meiodia 00437 pt-sss 00438 00439 Spanish sound files needed for Time/Date functions: 00440 es-de 00441 es-el 00442 00443 */ 00444 00445 /* Forward declarations of language specific variants of ast_say_number_full */ 00446 static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); 00447 static int ast_say_number_full_da(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); 00448 static int ast_say_number_full_de(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); 00449 static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); 00450 static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); 00451 static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); 00452 static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); 00453 static int ast_say_number_full_pl(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); 00454 static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); 00455 static int ast_say_number_full_se(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); 00456 static int ast_say_number_full_tw(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); 00457 static int ast_say_number_full_cz(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); 00458 00459 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */ 00460 static int ast_say_date_en(struct ast_channel *chan, time_t t, char *ints, char *lang); 00461 static int ast_say_date_nl(struct ast_channel *chan, time_t t, char *ints, char *lang); 00462 static int ast_say_date_pt(struct ast_channel *chan, time_t t, char *ints, char *lang); 00463 00464 static int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); 00465 static int ast_say_date_with_format_de(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); 00466 static int ast_say_date_with_format_es(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); 00467 static int ast_say_date_with_format_nl(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); 00468 static int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); 00469 static int ast_say_date_with_format_tw(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone); 00470 00471 static int ast_say_time_en(struct ast_channel *chan, time_t t, char *ints, char *lang); 00472 static int ast_say_time_nl(struct ast_channel *chan, time_t t, char *ints, char *lang); 00473 static int ast_say_time_pt(struct ast_channel *chan, time_t t, char *ints, char *lang); 00474 static int ast_say_time_tw(struct ast_channel *chan, time_t t, char *ints, char *lang); 00475 00476 static int ast_say_datetime_en(struct ast_channel *chan, time_t t, char *ints, char *lang); 00477 static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, char *ints, char *lang); 00478 static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, char *ints, char *lang); 00479 static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, char *ints, char *lang); 00480 00481 static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, char *ints, char *lang); 00482 static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, char *ints, char *lang); 00483 00484 static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang) 00485 { 00486 int res; 00487 if ((res = ast_streamfile(chan, file, lang))) 00488 ast_log(LOG_WARNING, "Unable to play message %s\n", file); 00489 if (!res) 00490 res = ast_waitstream(chan, ints); 00491 return res; 00492 } 00493 00494 /*--- ast_say_number_full: call language-specific functions */ 00495 /* Called from AGI */ 00496 int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 00497 { 00498 if (!strcasecmp(language,"en") ) { /* English syntax */ 00499 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd)); 00500 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */ 00501 return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd)); 00502 } else if (!strcasecmp(language, "de") ) { /* German syntax */ 00503 return(ast_say_number_full_de(chan, num, ints, language, options, audiofd, ctrlfd)); 00504 } else if (!strcasecmp(language, "es") || !strcasecmp(language, "mx")) { /* Spanish syntax */ 00505 return(ast_say_number_full_es(chan, num, ints, language, options, audiofd, ctrlfd)); 00506 } else if (!strcasecmp(language, "fr") ) { /* French syntax */ 00507 return(ast_say_number_full_fr(chan, num, ints, language, options, audiofd, ctrlfd)); 00508 } else if (!strcasecmp(language, "it") ) { /* Italian syntax */ 00509 return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd)); 00510 } else if (!strcasecmp(language, "nl") ) { /* Dutch syntax */ 00511 return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd)); 00512 } else if (!strcasecmp(language, "pl") ) { /* Polish syntax */ 00513 return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd)); 00514 } else if (!strcasecmp(language, "pt") ) { /* Portuguese syntax */ 00515 return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd)); 00516 } else if (!strcasecmp(language, "se") ) { /* Swedish syntax */ 00517 return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd)); 00518 } else if (!strcasecmp(language, "tw")) { /* Taiwanese syntax */ 00519 return(ast_say_number_full_tw(chan, num, ints, language, audiofd, ctrlfd)); 00520 } else if (!strcasecmp(language, "cz") ) { /* Czech syntax */ 00521 return(ast_say_number_full_cz(chan, num, ints, language, options, audiofd, ctrlfd)); 00522 } 00523 00524 /* Default to english */ 00525 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd)); 00526 } 00527 00528 /*--- ast_say_number: call language-specific functions without file descriptors */ 00529 int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language, char *options) 00530 { 00531 return(ast_say_number_full(chan, num, ints, language, options, -1, -1)); 00532 } 00533 00534 /*--- ast_say_number_full_en: English syntax */ 00535 /* This is the default syntax, if no other syntax defined in this file is used */ 00536 static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) 00537 { 00538 int res = 0; 00539 int playh = 0; 00540 char fn[256] = ""; 00541 if (!num) 00542 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00543 00544 while(!res && (num || playh)) { 00545 if (playh) { 00546 snprintf(fn, sizeof(fn), "digits/hundred"); 00547 playh = 0; 00548 } else if (num < 20) { 00549 snprintf(fn, sizeof(fn), "digits/%d", num); 00550 num = 0; 00551 } else if (num < 100) { 00552 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 00553 num -= ((num / 10) * 10); 00554 } else { 00555 if (num < 1000){ 00556 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 00557 playh++; 00558 num -= ((num / 100) * 100); 00559 } else { 00560 if (num < 1000000) { /* 1,000,000 */ 00561 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd); 00562 if (res) 00563 return res; 00564 num = num % 1000; 00565 snprintf(fn, sizeof(fn), "digits/thousand"); 00566 } else { 00567 if (num < 1000000000) { /* 1,000,000,000 */ 00568 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd); 00569 if (res) 00570 return res; 00571 num = num % 1000000; 00572 snprintf(fn, sizeof(fn), "digits/million"); 00573 } else { 00574 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00575 res = -1; 00576 } 00577 } 00578 } 00579 } 00580 if (!res) { 00581 if(!ast_streamfile(chan, fn, language)) { 00582 if (audiofd && ctrlfd) 00583 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00584 else 00585 res = ast_waitstream(chan, ints); 00586 } 00587 ast_stopstream(chan); 00588 00589 } 00590 00591 } 00592 return res; 00593 } 00594 00595 /*--- ast_say_number_full_da: Danish syntax */ 00596 /* New files: 00597 In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and" 00598 */ 00599 static int ast_say_number_full_da(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 00600 { 00601 int res = 0; 00602 int playh = 0; 00603 int playa = 0; 00604 int cn = 1; /* +1 = Commune; -1 = Neutrum */ 00605 char fn[256] = ""; 00606 if (!num) 00607 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00608 00609 if (options && !strncasecmp(options, "n",1)) cn = -1; 00610 00611 while(!res && (num || playh || playa )) { 00612 /* The grammar for Danish numbers is the same as for English except 00613 * for the following: 00614 * - 1 exists in both commune ("en", file "1N") and neutrum ("et", file "1") 00615 * - numbers 20 through 99 are said in reverse order, i.e. 21 is 00616 * "one-and twenty" and 68 is "eight-and sixty". 00617 * - "million" is different in singular and plural form 00618 * - numbers > 1000 with zero as the third digit from last have an 00619 * "and" before the last two digits, i.e. 2034 is "two thousand and 00620 * four-and thirty" and 1000012 is "one million and twelve". 00621 */ 00622 if (playh) { 00623 snprintf(fn, sizeof(fn), "digits/hundred"); 00624 playh = 0; 00625 } else if (playa) { 00626 snprintf(fn, sizeof(fn), "digits/and"); 00627 playa = 0; 00628 } else if (num == 1 && cn == -1) { 00629 snprintf(fn, sizeof(fn), "digits/1N"); 00630 num = 0; 00631 } else if (num < 20) { 00632 snprintf(fn, sizeof(fn), "digits/%d", num); 00633 num = 0; 00634 } else if (num < 100) { 00635 int ones = num % 10; 00636 if (ones) { 00637 snprintf(fn, sizeof(fn), "digits/%d-and", ones); 00638 num -= ones; 00639 } else { 00640 snprintf(fn, sizeof(fn), "digits/%d", num); 00641 num = 0; 00642 } 00643 } else { 00644 if (num < 1000) { 00645 int hundreds = num / 100; 00646 if (hundreds == 1) 00647 snprintf(fn, sizeof(fn), "digits/1N"); 00648 else 00649 snprintf(fn, sizeof(fn), "digits/%d", (num / 100)); 00650 00651 playh++; 00652 num -= 100 * hundreds; 00653 if (num) 00654 playa++; 00655 00656 } else { 00657 if (num < 1000000) { 00658 res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd); 00659 if (res) 00660 return res; 00661 num = num % 1000; 00662 snprintf(fn, sizeof(fn), "digits/thousand"); 00663 } else { 00664 if (num < 1000000000) { 00665 int millions = num / 1000000; 00666 res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd); 00667 if (res) 00668 return res; 00669 if (millions == 1) 00670 snprintf(fn, sizeof(fn), "digits/million"); 00671 else 00672 snprintf(fn, sizeof(fn), "digits/millions"); 00673 num = num % 1000000; 00674 } else { 00675 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00676 res = -1; 00677 } 00678 } 00679 if (num && num < 100) 00680 playa++; 00681 } 00682 } 00683 if (!res) { 00684 if(!ast_streamfile(chan, fn, language)) { 00685 if (audiofd && ctrlfd) 00686 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00687 else 00688 res = ast_waitstream(chan, ints); 00689 } 00690 ast_stopstream(chan); 00691 } 00692 } 00693 return res; 00694 } 00695 00696 /*--- ast_say_number_full_de: German syntax */ 00697 /* New files: 00698 In addition to English, the following sounds are required: 00699 "millions" 00700 "1-and" through "9-and" 00701 "1F" (eine) 00702 "1N" (ein) 00703 NB "1" is recorded as 'eins' 00704 */ 00705 static int ast_say_number_full_de(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 00706 { 00707 int res = 0; 00708 int playh = 0; 00709 int t = 0; 00710 int mf = 1; /* +1 = Male, Neutrum; -1 = Female */ 00711 char fn[256] = ""; 00712 char fna[256] = ""; 00713 if (!num) 00714 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00715 00716 if (options && (!strncasecmp(options, "f",1))) 00717 mf = -1; 00718 00719 while(!res && (num || playh)) { 00720 /* The grammar for German numbers is the same as for English except 00721 * for the following: 00722 * - numbers 20 through 99 are said in reverse order, i.e. 21 is 00723 * "one-and twenty" and 68 is "eight-and sixty". 00724 * - "one" varies according to gender 00725 * - 100 is 'hundert', however all other instances are 'ein hundert' 00726 * - 1000 is 'tausend', however all other instances are 'ein tausend' 00727 * - 1000000 is always 'ein million' 00728 * - "million" is different in singular and plural form 00729 */ 00730 if (playh) { 00731 snprintf(fn, sizeof(fn), "digits/hundred"); 00732 playh = 0; 00733 } else if (num == 1 && mf == -1) { 00734 snprintf(fn, sizeof(fn), "digits/%dF", num); 00735 num = 0; 00736 } else if (num < 20) { 00737 snprintf(fn, sizeof(fn), "digits/%d", num); 00738 num = 0; 00739 } else if (num < 100) { 00740 int ones = num % 10; 00741 if (ones) { 00742 snprintf(fn, sizeof(fn), "digits/%d-and", ones); 00743 num -= ones; 00744 } else { 00745 snprintf(fn, sizeof(fn), "digits/%d", num); 00746 num = 0; 00747 } 00748 } else if (num == 100) { 00749 snprintf(fn, sizeof(fn), "digits/hundred"); 00750 num = num - 100; 00751 } else if (num < 1000) { 00752 int hundreds = num / 100; 00753 if (hundreds == 1) 00754 snprintf(fn, sizeof(fn), "digits/1N"); 00755 else 00756 snprintf(fn, sizeof(fn), "digits/%d", (num / 100)); 00757 playh++; 00758 num -= 100 * hundreds; 00759 } else if (num == 1000 && t == 0) { 00760 snprintf(fn, sizeof(fn), "digits/thousand"); 00761 num = 0; 00762 } else if (num < 1000000) { 00763 int thousands = num / 1000; 00764 t = 1; 00765 if (thousands == 1) { 00766 snprintf(fn, sizeof(fn), "digits/1N"); 00767 snprintf(fna, sizeof(fna), "digits/thousand"); 00768 } else { 00769 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd); 00770 if (res) 00771 return res; 00772 snprintf(fn, sizeof(fn), "digits/thousand"); 00773 } 00774 num = num % 1000; 00775 } else if (num < 1000000000) { 00776 int millions = num / 1000000; 00777 t = 1; 00778 if (millions == 1) { 00779 snprintf(fn, sizeof(fn), "digits/1N"); 00780 snprintf(fna, sizeof(fna), "digits/million"); 00781 } else { 00782 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd); 00783 if (res) 00784 return res; 00785 snprintf(fn, sizeof(fn), "digits/millions"); 00786 } 00787 num = num % 1000000; 00788 } else { 00789 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00790 res = -1; 00791 } 00792 if (!res) { 00793 if(!ast_streamfile(chan, fn, language)) { 00794 if (audiofd && ctrlfd) 00795 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00796 else 00797 res = ast_waitstream(chan, ints); 00798 } 00799 ast_stopstream(chan); 00800 if(!ast_streamfile(chan, fna, language)) { 00801 if (audiofd && ctrlfd) 00802 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00803 else 00804 res = ast_waitstream(chan, ints); 00805 } 00806 ast_stopstream(chan); 00807 strcpy(fna, ""); 00808 } 00809 } 00810 return res; 00811 } 00812 00813 /*--- ast_say_number_full_es: Spanish syntax */ 00814 /* New files: 00815 Requires a few new audios: 00816 1F.gsm: feminine 'una' 00817 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 00818 */ 00819 static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 00820 { 00821 int res = 0; 00822 int playa = 0; 00823 int mf = 1; /* +1 = Masculin; -1 = Feminin */ 00824 char fn[256] = ""; 00825 if (!num) 00826 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00827 00828 if (options && !strncasecmp(options, "f",1)) 00829 mf = -1; 00830 00831 while (!res && num) { 00832 if (playa) { 00833 snprintf(fn, sizeof(fn), "digits/y"); 00834 playa = 0; 00835 } else if (num == 1) { 00836 if (mf < 0) 00837 snprintf(fn, sizeof(fn), "digits/%dF", num); 00838 else 00839 snprintf(fn, sizeof(fn), "digits/%d", num); 00840 num = 0; 00841 } else if (num < 31) { 00842 snprintf(fn, sizeof(fn), "digits/%d", num); 00843 num = 0; 00844 } else if (num < 100) { 00845 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10); 00846 num -= ((num/10)*10); 00847 if (num) 00848 playa++; 00849 } else if (num == 100) { 00850 snprintf(fn, sizeof(fn), "digits/cien"); 00851 num = 0; 00852 } else { 00853 if (num < 1000) { 00854 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100); 00855 num -= ((num/100)*100); 00856 } else { 00857 if (num < 1000000) { 00858 res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd); 00859 if (res) 00860 return res; 00861 num = num % 1000; 00862 snprintf(fn, sizeof(fn), "digits/mil"); 00863 } else { 00864 if (num < 2147483640) { 00865 res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd); 00866 if (res) 00867 return res; 00868 if ((num/1000000) == 1) { 00869 snprintf(fn, sizeof(fn), "digits/millon"); 00870 } else { 00871 snprintf(fn, sizeof(fn), "digits/millones"); 00872 } 00873 num = num % 1000000; 00874 } else { 00875 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00876 res = -1; 00877 } 00878 } 00879 } 00880 } 00881 00882 if (!res) { 00883 if(!ast_streamfile(chan, fn, language)) { 00884 if (audiofd && ctrlfd) 00885 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00886 else 00887 res = ast_waitstream(chan, ints); 00888 } 00889 ast_stopstream(chan); 00890 00891 } 00892 00893 } 00894 return res; 00895 } 00896 00897 00898 /*--- ast_say_number_full_fr: French syntax */ 00899 /* Extra sounds needed: 00900 1F: feminin 'une' 00901 et: 'and' */ 00902 static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 00903 { 00904 int res = 0; 00905 int playh = 0; 00906 int playa = 0; 00907 int mf = 1; /* +1 = Masculin; -1 = Feminin */ 00908 char fn[256] = ""; 00909 if (!num) 00910 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00911 00912 if (options && !strncasecmp(options, "f",1)) 00913 mf = -1; 00914 00915 while(!res && (num || playh || playa)) { 00916 if (playh) { 00917 snprintf(fn, sizeof(fn), "digits/hundred"); 00918 playh = 0; 00919 } else if (playa) { 00920 snprintf(fn, sizeof(fn), "digits/et"); 00921 playa = 0; 00922 } else if (num == 1) { 00923 if (mf < 0) 00924 snprintf(fn, sizeof(fn), "digits/%dF", num); 00925 else 00926 snprintf(fn, sizeof(fn), "digits/%d", num); 00927 num = 0; 00928 } else if (num < 21) { 00929 snprintf(fn, sizeof(fn), "digits/%d", num); 00930 num = 0; 00931 } else if (num < 70) { 00932 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10); 00933 if ((num % 10) == 1) playa++; 00934 num = num % 10; 00935 } else if (num < 80) { 00936 snprintf(fn, sizeof(fn), "digits/60"); 00937 if ((num % 10) == 1) playa++; 00938 num = num - 60; 00939 } else if (num < 100) { 00940 snprintf(fn, sizeof(fn), "digits/80"); 00941 num = num - 80; 00942 } else if (num < 200) { 00943 snprintf(fn, sizeof(fn), "digits/hundred"); 00944 num = num - 100; 00945 } else if (num < 1000) { 00946 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 00947 playh++; 00948 num = num % 100; 00949 } else if (num < 2000) { 00950 snprintf(fn, sizeof(fn), "digits/thousand"); 00951 num = num - 1000; 00952 } else if (num < 1000000) { 00953 res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd); 00954 if (res) 00955 return res; 00956 snprintf(fn, sizeof(fn), "digits/thousand"); 00957 num = num % 1000; 00958 } else if (num < 1000000000) { 00959 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd); 00960 if (res) 00961 return res; 00962 snprintf(fn, sizeof(fn), "digits/million"); 00963 num = num % 1000000; 00964 } else { 00965 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 00966 res = -1; 00967 } 00968 if (!res) { 00969 if(!ast_streamfile(chan, fn, language)) { 00970 if (audiofd && ctrlfd) 00971 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 00972 else 00973 res = ast_waitstream(chan, ints); 00974 } 00975 ast_stopstream(chan); 00976 } 00977 } 00978 return res; 00979 } 00980 00981 /*--- ast_say_number_full_it: Italian */ 00982 static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) 00983 { 00984 int res = 0; 00985 int playh = 0; 00986 int tempnum = 0; 00987 char fn[256] = ""; 00988 00989 if (!num) 00990 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 00991 00992 /* 00993 Italian support 00994 00995 Like english, numbers up to 20 are a single 'word', and others 00996 compound, but with exceptions. 00997 For example 21 is not twenty-one, but there is a single word in 'it'. 00998 Idem for 28 (ie when a the 2nd part of a compund number 00999 starts with a vowel) 01000 01001 There are exceptions also for hundred, thousand and million. 01002 In english 100 = one hundred, 200 is two hundred. 01003 In italian 100 = cento , like to say hundred (without one), 01004 200 and more are like english. 01005 01006 Same applies for thousand: 01007 1000 is one thousand in en, 2000 is two thousand. 01008 In it we have 1000 = mille , 2000 = 2 mila 01009 01010 For million(s) we use the plural, if more than one 01011 Also, one million is abbreviated in it, like on-million, 01012 or 'un milione', not 'uno milione'. 01013 So the right file is provided. 01014 */ 01015 01016 while(!res && (num || playh)) { 01017 if (playh) { 01018 snprintf(fn, sizeof(fn), "digits/hundred"); 01019 playh = 0; 01020 } else if (num < 20) { 01021 snprintf(fn, sizeof(fn), "digits/%d", num); 01022 num = 0; 01023 } else if (num == 21) { 01024 snprintf(fn, sizeof(fn), "digits/%d", num); 01025 num = 0; 01026 } else if (num == 28) { 01027 snprintf(fn, sizeof(fn), "digits/%d", num); 01028 num = 0; 01029 } else if (num == 31) { 01030 snprintf(fn, sizeof(fn), "digits/%d", num); 01031 num = 0; 01032 } else if (num == 38) { 01033 snprintf(fn, sizeof(fn), "digits/%d", num); 01034 num = 0; 01035 } else if (num == 41) { 01036 snprintf(fn, sizeof(fn), "digits/%d", num); 01037 num = 0; 01038 } else if (num == 48) { 01039 snprintf(fn, sizeof(fn), "digits/%d", num); 01040 num = 0; 01041 } else if (num == 51) { 01042 snprintf(fn, sizeof(fn), "digits/%d", num); 01043 num = 0; 01044 } else if (num == 58) { 01045 snprintf(fn, sizeof(fn), "digits/%d", num); 01046 num = 0; 01047 } else if (num == 61) { 01048 snprintf(fn, sizeof(fn), "digits/%d", num); 01049 num = 0; 01050 } else if (num == 68) { 01051 snprintf(fn, sizeof(fn), "digits/%d", num); 01052 num = 0; 01053 } else if (num == 71) { 01054 snprintf(fn, sizeof(fn), "digits/%d", num); 01055 num = 0; 01056 } else if (num == 78) { 01057 snprintf(fn, sizeof(fn), "digits/%d", num); 01058 num = 0; 01059 } else if (num == 81) { 01060 snprintf(fn, sizeof(fn), "digits/%d", num); 01061 num = 0; 01062 } else if (num == 88) { 01063 snprintf(fn, sizeof(fn), "digits/%d", num); 01064 num = 0; 01065 } else if (num == 91) { 01066 snprintf(fn, sizeof(fn), "digits/%d", num); 01067 num = 0; 01068 } else if (num == 98) { 01069 snprintf(fn, sizeof(fn), "digits/%d", num); 01070 num = 0; 01071 } else if (num < 100) { 01072 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 01073 num -= ((num / 10) * 10); 01074 } else { 01075 if (num < 1000) { 01076 if ((num / 100) > 1) { 01077 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 01078 playh++; 01079 } else { 01080 snprintf(fn, sizeof(fn), "digits/hundred"); 01081 } 01082 num -= ((num / 100) * 100); 01083 } else { 01084 if (num < 1000000) { /* 1,000,000 */ 01085 if ((num/1000) > 1) 01086 res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd); 01087 if (res) 01088 return res; 01089 tempnum = num; 01090 num = num % 1000; 01091 if ((tempnum / 1000) < 2) 01092 snprintf(fn, sizeof(fn), "digits/thousand"); 01093 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */ 01094 snprintf(fn, sizeof(fn), "digits/thousands"); 01095 } else { 01096 if (num < 1000000000) { /* 1,000,000,000 */ 01097 if ((num / 1000000) > 1) 01098 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd); 01099 if (res) 01100 return res; 01101 tempnum = num; 01102 num = num % 1000000; 01103 if ((tempnum / 1000000) < 2) 01104 snprintf(fn, sizeof(fn), "digits/million"); 01105 else 01106 snprintf(fn, sizeof(fn), "digits/millions"); 01107 } else { 01108 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01109 res = -1; 01110 } 01111 } 01112 } 01113 } 01114 if (!res) { 01115 if(!ast_streamfile(chan, fn, language)) { 01116 if (audiofd && ctrlfd) 01117 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01118 else 01119 res = ast_waitstream(chan, ints); 01120 } 01121 ast_stopstream(chan); 01122 } 01123 } 01124 return res; 01125 } 01126 01127 /*--- ast_say_number_full_nl: dutch syntax */ 01128 /* New files: digits/nl-en 01129 */ 01130 static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) 01131 { 01132 int res = 0; 01133 int playh = 0; 01134 int units = 0; 01135 char fn[256] = ""; 01136 if (!num) 01137 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01138 while (!res && (num || playh )) { 01139 if (playh) { 01140 snprintf(fn, sizeof(fn), "digits/hundred"); 01141 playh = 0; 01142 } else if (num < 20) { 01143 snprintf(fn, sizeof(fn), "digits/%d", num); 01144 num = 0; 01145 } else if (num < 100) { 01146 units = num % 10; 01147 if (units > 0) { 01148 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd); 01149 if (res) 01150 return res; 01151 num = num - units; 01152 snprintf(fn, sizeof(fn), "digits/nl-en"); 01153 } else { 01154 snprintf(fn, sizeof(fn), "digits/%d", num - units); 01155 num = 0; 01156 } 01157 } else { 01158 if (num < 1000) { 01159 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 01160 playh++; 01161 num -= ((num / 100) * 100); 01162 } else { 01163 if (num < 1000000) { /* 1,000,000 */ 01164 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd); 01165 if (res) 01166 return res; 01167 num = num % 1000; 01168 snprintf(fn, sizeof(fn), "digits/thousand"); 01169 } else { 01170 if (num < 1000000000) { /* 1,000,000,000 */ 01171 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd); 01172 if (res) 01173 return res; 01174 num = num % 1000000; 01175 snprintf(fn, sizeof(fn), "digits/million"); 01176 } else { 01177 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01178 res = -1; 01179 } 01180 } 01181 } 01182 } 01183 01184 if (!res) { 01185 if(!ast_streamfile(chan, fn, language)) { 01186 if (audiofd && ctrlfd) 01187 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01188 else 01189 res = ast_waitstream(chan, ints); 01190 } 01191 ast_stopstream(chan); 01192 } 01193 } 01194 return res; 01195 } 01196 01197 static int exp10_int(int power) 01198 { 01199 int x, res= 1; 01200 for (x=0;x<power;x++) 01201 res *= 10; 01202 return res; 01203 } 01204 01205 typedef struct { 01206 char *separator_dziesiatek; 01207 char *cyfry[10]; 01208 char *cyfry2[10]; 01209 char *setki[10]; 01210 char *dziesiatki[10]; 01211 char *nastki[10]; 01212 char *rzedy[3][3]; 01213 } odmiana; 01214 01215 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad) 01216 { 01217 if (rzad==0) 01218 return ""; 01219 01220 if (i==1) 01221 return odm->rzedy[rzad - 1][0]; 01222 if ((i > 21 || i < 11) && i%10 > 1 && i%10 < 5) 01223 return odm->rzedy[rzad - 1][1]; 01224 else 01225 return odm->rzedy[rzad - 1][2]; 01226 } 01227 01228 static char* pl_append(char* buffer, char* str) 01229 { 01230 strcpy(buffer, str); 01231 buffer += strlen(str); 01232 return buffer; 01233 } 01234 01235 static void pl_odtworz_plik(struct ast_channel *chan, char *language, int audiofd, int ctrlfd, char *ints, char *fn) 01236 { 01237 char file_name[255] = "digits/"; 01238 strcat(file_name, fn); 01239 ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name); 01240 if (!ast_streamfile(chan, file_name, language)) { 01241 if (audiofd && ctrlfd) 01242 ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01243 else 01244 ast_waitstream(chan, ints); 01245 } 01246 ast_stopstream(chan); 01247 } 01248 01249 static void powiedz(struct ast_channel *chan, char *language, int audiofd, int ctrlfd, char *ints, odmiana *odm, int rzad, int i) 01250 { 01251 /* Initialise variables to allow compilation on Debian-stable, etc */ 01252 int m1000E6 = 0; 01253 int i1000E6 = 0; 01254 int m1000E3 = 0; 01255 int i1000E3 = 0; 01256 int m1000 = 0; 01257 int i1000 = 0; 01258 int m100 = 0; 01259 int i100 = 0; 01260 01261 if (i == 0 && rzad > 0) { 01262 return; 01263 } 01264 if (i == 0) { 01265 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]); 01266 } 01267 01268 m1000E6 = i % 1000000000; 01269 i1000E6 = i / 1000000000; 01270 01271 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6); 01272 01273 m1000E3 = m1000E6 % 1000000; 01274 i1000E3 = m1000E6 / 1000000; 01275 01276 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3); 01277 01278 m1000 = m1000E3 % 1000; 01279 i1000 = m1000E3 / 1000; 01280 01281 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000); 01282 01283 m100 = m1000 % 100; 01284 i100 = m1000 / 100; 01285 01286 if (i100>0) 01287 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]); 01288 01289 if ( m100 > 0 && m100 <=9 ) { 01290 if (m1000>0) 01291 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]); 01292 else 01293 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]); 01294 } else if (m100 % 10 == 0) { 01295 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]); 01296 } else if (m100 <= 19 ) { 01297 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]); 01298 } else if (m100 != 0) { 01299 if (odm->separator_dziesiatek[0]==' ') { 01300 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]); 01301 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]); 01302 } else { 01303 char buf[10]; 01304 char *b = buf; 01305 b = pl_append(b, odm->dziesiatki[m100 / 10]); 01306 b = pl_append(b, odm->separator_dziesiatek); 01307 b = pl_append(b, odm->cyfry2[m100 % 10]); 01308 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf); 01309 } 01310 } 01311 01312 if (rzad > 0) { 01313 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad)); 01314 } 01315 } 01316 01317 /* ast_say_number_full_pl: Polish syntax */ 01318 static int ast_say_number_full_pl(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 01319 /* 01320 Sounds needed: 01321 0 zero 01322 1 jeden 01323 10 dziesiec 01324 100 sto 01325 1000 tysiac 01326 1000000 milion 01327 1000000000 miliard 01328 1000000000.2 miliardy 01329 1000000000.5 miliardow 01330 1000000.2 miliony 01331 1000000.5 milionow 01332 1000.2 tysiace 01333 1000.5 tysiecy 01334 100m stu 01335 10m dziesieciu 01336 11 jedenascie 01337 11m jedenastu 01338 12 dwanascie 01339 12m dwunastu 01340 13 trzynascie 01341 13m trzynastu 01342 14 czternascie 01343 14m czternastu 01344 15 pietnascie 01345 15m pietnastu 01346 16 szesnascie 01347 16m szesnastu 01348 17 siedemnascie 01349 17m siedemnastu 01350 18 osiemnascie 01351 18m osiemnastu 01352 19 dziewietnascie 01353 19m dziewietnastu 01354 1z jedna 01355 2 dwie 01356 20 dwadziescia 01357 200 dwiescie 01358 200m dwustu 01359 20m dwudziestu 01360 2-1m dwaj 01361 2-2m dwoch 01362 2z dwie 01363 3 trzy 01364 30 trzydziesci 01365 300 trzysta 01366 300m trzystu 01367 30m trzydziestu 01368 3-1m trzej 01369 3-2m trzech 01370 4 cztery 01371 40 czterdziesci 01372 400 czterysta 01373 400m czterystu 01374 40m czterdziestu 01375 4-1m czterej 01376 4-2m czterech 01377 5 piec 01378 50 piecdziesiat 01379 500 piecset 01380 500m pieciuset 01381 50m piedziesieciu 01382 5m pieciu 01383 6 szesc 01384 60 szescdziesiat 01385 600 szescset 01386 600m szesciuset 01387 60m szescdziesieciu 01388 6m szesciu 01389 7 siedem 01390 70 siedemdziesiat 01391 700 siedemset 01392 700m siedmiuset 01393 70m siedemdziesieciu 01394 7m siedmiu 01395 8 osiem 01396 80 osiemdziesiat 01397 800 osiemset 01398 800m osmiuset 01399 80m osiemdziesieciu 01400 8m osmiu 01401 9 dziewiec 01402 90 dziewiecdziesiat 01403 900 dziewiecset 01404 900m dziewieciuset 01405 90m dziewiedziesieciu 01406 9m dziewieciu 01407 and combinations of eg.: 20_1, 30m_3m, etc... 01408 01409 */ 01410 { 01411 char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"}; 01412 01413 char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"}; 01414 01415 char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m", /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"}; 01416 01417 char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"}; 01418 01419 char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"}; 01420 01421 char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"}; 01422 01423 char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"}; 01424 01425 char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"}; 01426 01427 char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"}; 01428 01429 char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"}; 01430 01431 char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"}; 01432 01433 char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"}; 01434 01435 char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}}; 01436 01437 /* Initialise variables to allow compilation on Debian-stable, etc */ 01438 odmiana *o; 01439 01440 static odmiana *odmiana_nieosobowa = NULL; 01441 static odmiana *odmiana_meska = NULL; 01442 static odmiana *odmiana_zenska = NULL; 01443 01444 if (odmiana_nieosobowa == NULL) { 01445 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana)); 01446 01447 odmiana_nieosobowa->separator_dziesiatek = "_"; 01448 01449 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry)); 01450 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry)); 01451 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki)); 01452 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki)); 01453 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki)); 01454 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy)); 01455 } 01456 01457 if (odmiana_zenska == NULL) { 01458 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana)); 01459 01460 odmiana_zenska->separator_dziesiatek = "_"; 01461 01462 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry)); 01463 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry)); 01464 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki)); 01465 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki)); 01466 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki)); 01467 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy)); 01468 } 01469 01470 if (odmiana_meska == NULL) { 01471 odmiana_meska = (odmiana *) malloc(sizeof(odmiana)); 01472 01473 odmiana_meska->separator_dziesiatek = "_"; 01474 01475 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry)); 01476 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry)); 01477 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki)); 01478 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki)); 01479 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki)); 01480 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy)); 01481 } 01482 01483 if (options) { 01484 if (strncasecmp(options, "f", 1) == 0) 01485 o = odmiana_zenska; 01486 else if (strncasecmp(options, "m", 1) == 0) 01487 o = odmiana_meska; 01488 else 01489 o = odmiana_nieosobowa; 01490 } else 01491 o = odmiana_nieosobowa; 01492 01493 powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num); 01494 return 0; 01495 } 01496 01497 /* ast_say_number_full_pt: Portuguese syntax */ 01498 /* Extra sounds needed: */ 01499 /* For feminin all sound files end with F */ 01500 /* 100E for 100+ something */ 01501 /* 1000000S for plural */ 01502 /* pt-e for 'and' */ 01503 static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 01504 { 01505 int res = 0; 01506 int playh = 0; 01507 int mf = 1; /* +1 = Masculin; -1 = Feminin */ 01508 char fn[256] = ""; 01509 01510 if (!num) 01511 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01512 01513 if (options && !strncasecmp(options, "f",1)) 01514 mf = -1; 01515 01516 while(!res && num ) { 01517 if (num < 20) { 01518 if ((num == 1 || num == 2) && (mf < 0)) 01519 snprintf(fn, sizeof(fn), "digits/%dF", num); 01520 else 01521 snprintf(fn, sizeof(fn), "digits/%d", num); 01522 num = 0; 01523 } else if (num < 100) { 01524 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10); 01525 if (num % 10) 01526 playh = 1; 01527 num = num % 10; 01528 } else if (num < 1000) { 01529 if (num == 100) 01530 snprintf(fn, sizeof(fn), "digits/100"); 01531 else if (num < 200) 01532 snprintf(fn, sizeof(fn), "digits/100E"); 01533 else { 01534 if (mf < 0 && num > 199) 01535 snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100); 01536 else 01537 snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100); 01538 if (num % 100) 01539 playh = 1; 01540 } 01541 num = num % 100; 01542 } else if (num < 1000000) { 01543 if (num > 1999) { 01544 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd); 01545 if (res) 01546 return res; 01547 } 01548 snprintf(fn, sizeof(fn), "digits/1000"); 01549 if ((num % 1000) && ((num % 1000) < 100 || !(num % 100))) 01550 playh = 1; 01551 num = num % 1000; 01552 } else if (num < 1000000000) { 01553 res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd ); 01554 if (res) 01555 return res; 01556 if (num < 2000000) 01557 snprintf(fn, sizeof(fn), "digits/1000000"); 01558 else 01559 snprintf(fn, sizeof(fn), "digits/1000000S"); 01560 01561 if ((num % 1000000) && 01562 // no thousands 01563 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) || 01564 // no hundreds and below 01565 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) ) 01566 playh = 1; 01567 num = num % 1000000; 01568 } 01569 if (!res && playh) { 01570 res = wait_file(chan, ints, "digits/pt-e", language); 01571 ast_stopstream(chan); 01572 playh = 0; 01573 } 01574 if (!res) { 01575 if(!ast_streamfile(chan, fn, language)) { 01576 if (audiofd && ctrlfd) 01577 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); else 01578 res = ast_waitstream(chan, ints); 01579 } 01580 ast_stopstream(chan); 01581 } 01582 } 01583 return res; 01584 } 01585 01586 /*--- ast_say_number_full_se: Swedish/Norwegian syntax */ 01587 static int ast_say_number_full_se(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 01588 { 01589 int res = 0; 01590 int playh = 0; 01591 char fn[256] = ""; 01592 int cn = 1; /* +1 = Commune; -1 = Neutrum */ 01593 if (!num) 01594 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01595 if (options && !strncasecmp(options, "n",1)) cn = -1; 01596 01597 while(!res && (num || playh)) { 01598 if (playh) { 01599 snprintf(fn, sizeof(fn), "digits/hundred"); 01600 playh = 0; 01601 } else 01602 if (num < 20) { 01603 snprintf(fn, sizeof(fn), "digits/%d", num); 01604 num = 0; 01605 } else 01606 if (num < 100) { 01607 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 01608 num -= ((num / 10) * 10); 01609 } else 01610 if (num == 1 && cn == -1) { /* En eller ett? */ 01611 snprintf(fn, sizeof(fn), "digits/1N"); 01612 num = 0; 01613 } else { 01614 if (num < 1000){ 01615 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 01616 playh++; 01617 num -= ((num / 100) * 100); 01618 } else { 01619 if (num < 1000000) { /* 1,000,000 */ 01620 res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd); 01621 if (res) 01622 return res; 01623 num = num % 1000; 01624 snprintf(fn, sizeof(fn), "digits/thousand"); 01625 } else { 01626 if (num < 1000000000) { /* 1,000,000,000 */ 01627 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd); 01628 if (res) 01629 return res; 01630 num = num % 1000000; 01631 snprintf(fn, sizeof(fn), "digits/million"); 01632 } else { 01633 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01634 res = -1; 01635 } 01636 } 01637 } 01638 } 01639 if (!res) { 01640 if(!ast_streamfile(chan, fn, language)) { 01641 if (audiofd && ctrlfd) 01642 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01643 else 01644 res = ast_waitstream(chan, ints); 01645 } 01646 ast_stopstream(chan); 01647 01648 } 01649 01650 } 01651 return res; 01652 } 01653 01654 01655 /*--- ast_say_number_full_tw: Taiwanese syntax */ 01656 static int ast_say_number_full_tw(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) 01657 { 01658 int res = 0; 01659 int playh = 0; 01660 char fn[256] = ""; 01661 if (!num) 01662 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01663 01664 while(!res && (num || playh)) { 01665 if (playh) { 01666 snprintf(fn, sizeof(fn), "digits/hundred"); 01667 playh = 0; 01668 } else if (num < 10) { 01669 snprintf(fn, sizeof(fn), "digits/%d", num); 01670 num = 0; 01671 } else if (num < 100) { 01672 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 01673 num -= ((num / 10) * 10); 01674 } else { 01675 if (num < 1000){ 01676 snprintf(fn, sizeof(fn), "digits/%d", (num/100)); 01677 playh++; 01678 num -= ((num / 100) * 100); 01679 } else { 01680 if (num < 1000000) { /* 1,000,000 */ 01681 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd); 01682 if (res) 01683 return res; 01684 num = num % 1000; 01685 snprintf(fn, sizeof(fn), "digits/thousand"); 01686 } else { 01687 if (num < 1000000000) { /* 1,000,000,000 */ 01688 res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd); 01689 if (res) 01690 return res; 01691 num = num % 1000000; 01692 snprintf(fn, sizeof(fn), "digits/million"); 01693 } else { 01694 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); 01695 res = -1; 01696 } 01697 } 01698 } 01699 } 01700 if (!res) { 01701 if(!ast_streamfile(chan, fn, language)) { 01702 if (audiofd && ctrlfd) 01703 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01704 else 01705 res = ast_waitstream(chan, ints); 01706 } 01707 ast_stopstream(chan); 01708 01709 } 01710 } 01711 return res; 01712 } 01713 01714 /*--- ast_say_number_full_cz: Czech syntax */ 01715 /* files needed: 01716 * 1m,2m - gender male 01717 * 1w,2w - gender female 01718 * 3,4,...,20 01719 * 30,40,...,90 01720 * 01721 * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set 01722 * 01723 * for each number 10^(3n + 3) exist 3 files represented as: 01724 * 1 tousand = jeden tisic = 1_E3 01725 * 2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3 01726 * 5,6,... tousands = pet,sest,... tisic = 5_E3 01727 * 01728 * million = _E6 01729 * miliard = _E9 01730 * etc... 01731 * 01732 * tousand, milion are gender male, so 1 and 2 is 1m 2m 01733 * miliard is gender female, so 1 and 2 is 1w 2w 01734 */ 01735 01736 static int ast_say_number_full_cz(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) 01737 { 01738 int res = 0; 01739 int playh = 0; 01740 char fn[256] = ""; 01741 01742 int hundered = 0; 01743 int left = 0; 01744 int length = 0; 01745 01746 /* options - w = woman, m = man, n = neutral. Defaultl is woman */ 01747 if (!options) 01748 options = "w"; 01749 01750 if (!num) 01751 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); 01752 01753 while(!res && (num || playh)) { 01754 if (num < 3 ) { 01755 snprintf(fn, sizeof(fn), "digits/%d%c",num,options[0]); 01756 playh = 0; 01757 num = 0; 01758 } else if (num < 20) { 01759 snprintf(fn, sizeof(fn), "digits/%d",num); 01760 playh = 0; 01761 num = 0; 01762 } else if (num < 100) { 01763 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); 01764 num -= ((num / 10) * 10); 01765 } else if (num < 1000) { 01766 hundered = num / 100; 01767 if ( hundered == 1 ) { 01768 snprintf(fn, sizeof(fn), "digits/1sto"); 01769 } else if ( hundered == 2 ) { 01770 snprintf(fn, sizeof(fn), "digits/2ste"); 01771 } else { 01772 res = ast_say_number_full_cz(chan,hundered,ints,language,options,audiofd,ctrlfd); 01773 if (res) 01774 return res; 01775 if ( hundered == 3 || hundered == 4) { 01776 snprintf(fn, sizeof(fn), "digits/sta"); 01777 } else if ( hundered > 4 ) { 01778 snprintf(fn, sizeof(fn), "digits/set"); 01779 } 01780 } 01781 num -= (hundered * 100); 01782 } else { /* num > 1000 */ 01783 length = (int)log10(num)+1; 01784 while ( (length % 3 ) != 1 ) { 01785 length--; 01786 } 01787 left = num / (exp10_int(length-1)); 01788 if ( left == 2 ) { 01789 switch (length-1) { 01790 case 9: options = "w"; /* 1,000,000,000 gender female */ 01791 break; 01792 default : options = "m"; /* others are male */ 01793 } 01794 } 01795 if ( left > 1 ) { /* we dont say "one thousand" but only thousand */ 01796 res = ast_say_number_full_cz(chan,left,ints,language,options,audiofd,ctrlfd); 01797 if (res) 01798 return res; 01799 } 01800 if ( left >= 5 ) { /* >= 5 have the same declesion */ 01801 snprintf(fn, sizeof(fn), "digits/5_E%d",length-1); 01802 } else if ( left >= 2 && left <= 4 ) { 01803 snprintf(fn, sizeof(fn), "digits/2-4_E%d",length-1); 01804 } else { /* left == 1 */ 01805 snprintf(fn, sizeof(fn), "digits/1_E%d",length-1); 01806 } 01807 num -= left * (exp10_int(length-1)); 01808 } 01809 if (!res) { 01810 if(!ast_streamfile(chan, fn, language)) { 01811 if (audiofd && ctrlfd) { 01812 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 01813 } else { 01814 res = ast_waitstream(chan, ints); 01815 } 01816 } 01817 ast_stopstream(chan); 01818 } 01819 } 01820 return res; 01821 } 01822 01823 01824 int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang) 01825 { 01826 if (!strcasecmp(lang,"en") ) { /* English syntax */ 01827 return(ast_say_date_en(chan, t, ints, lang)); 01828 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 01829 return(ast_say_date_nl(chan, t, ints, lang)); 01830 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 01831 return(ast_say_date_pt(chan, t, ints, lang)); 01832 } 01833 01834 /* Default to English */ 01835 return(ast_say_date_en(chan, t, ints, lang)); 01836 } 01837 01838 /* English syntax */ 01839 int ast_say_date_en(struct ast_channel *chan, time_t t, char *ints, char *lang) 01840 { 01841 struct tm tm; 01842 char fn[256]; 01843 int res = 0; 01844 ast_localtime(&t,&tm,NULL); 01845 if (!res) { 01846 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 01847 res = ast_streamfile(chan, fn, lang); 01848 if (!res) 01849 res = ast_waitstream(chan, ints); 01850 } 01851 if (!res) { 01852 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 01853 res = ast_streamfile(chan, fn, lang); 01854 if (!res) 01855 res = ast_waitstream(chan, ints); 01856 } 01857 if (!res) 01858 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); 01859 if (!res) 01860 res = ast_waitstream(chan, ints); 01861 if (!res) 01862 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 01863 return res; 01864 } 01865 01866 /* Dutch syntax */ 01867 int ast_say_date_nl(struct ast_channel *chan, time_t t, char *ints, char *lang) 01868 { 01869 struct tm tm; 01870 char fn[256]; 01871 int res = 0; 01872 ast_localtime(&t,&tm,NULL); 01873 if (!res) { 01874 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 01875 res = ast_streamfile(chan, fn, lang); 01876 if (!res) 01877 res = ast_waitstream(chan, ints); 01878 } 01879 if (!res) 01880 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); 01881 if (!res) { 01882 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 01883 res = ast_streamfile(chan, fn, lang); 01884 if (!res) 01885 res = ast_waitstream(chan, ints); 01886 } 01887 if (!res) 01888 res = ast_waitstream(chan, ints); 01889 if (!res) 01890 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 01891 return res; 01892 } 01893 01894 /* Portuguese syntax */ 01895 int ast_say_date_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) 01896 { 01897 struct tm tm; 01898 char fn[256]; 01899 int res = 0; 01900 ast_localtime(&t,&tm,NULL); 01901 localtime_r(&t,&tm); 01902 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 01903 if (!res) 01904 res = wait_file(chan, ints, fn, lang); 01905 if (!res) 01906 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 01907 if (!res) 01908 res = wait_file(chan, ints, "digits/pt-de", lang); 01909 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 01910 if (!res) 01911 res = wait_file(chan, ints, fn, lang); 01912 if (!res) 01913 res = wait_file(chan, ints, "digits/pt-de", lang); 01914 if (!res) 01915 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 01916 01917 return res; 01918 } 01919 01920 int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 01921 { 01922 if (!strcasecmp(lang, "en") ) { /* English syntax */ 01923 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone)); 01924 } else if (!strcasecmp(lang, "de") ) { /* German syntax */ 01925 return(ast_say_date_with_format_de(chan, time, ints, lang, format, timezone)); 01926 } else if (!strcasecmp(lang, "es") || !strcasecmp(lang, "mx")) { /* Spanish syntax */ 01927 return(ast_say_date_with_format_es(chan, time, ints, lang, format, timezone)); 01928 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 01929 return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone)); 01930 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 01931 return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone)); 01932 } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ 01933 return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone)); 01934 } 01935 01936 /* Default to English */ 01937 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone)); 01938 } 01939 01940 /* English syntax */ 01941 int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 01942 { 01943 struct tm tm; 01944 int res=0, offset, sndoffset; 01945 char sndfile[256], nextmsg[256]; 01946 01947 ast_localtime(&time,&tm,timezone); 01948 01949 for (offset=0 ; format[offset] != '\0' ; offset++) { 01950 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 01951 switch (format[offset]) { 01952 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 01953 case '\'': 01954 /* Literal name of a sound file */ 01955 sndoffset=0; 01956 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 01957 sndfile[sndoffset] = format[offset]; 01958 sndfile[sndoffset] = '\0'; 01959 res = wait_file(chan,ints,sndfile,lang); 01960 break; 01961 case 'A': 01962 case 'a': 01963 /* Sunday - Saturday */ 01964 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 01965 res = wait_file(chan,ints,nextmsg,lang); 01966 break; 01967 case 'B': 01968 case 'b': 01969 case 'h': 01970 /* January - December */ 01971 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 01972 res = wait_file(chan,ints,nextmsg,lang); 01973 break; 01974 case 'd': 01975 case 'e': 01976 /* First - Thirtyfirst */ 01977 if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) { 01978 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 01979 res = wait_file(chan,ints,nextmsg,lang); 01980 } else if (tm.tm_mday == 31) { 01981 /* "Thirty" and "first" */ 01982 res = wait_file(chan,ints, "digits/30",lang); 01983 if (!res) { 01984 res = wait_file(chan,ints, "digits/h-1",lang); 01985 } 01986 } else { 01987 /* Between 21 and 29 - two sounds */ 01988 res = wait_file(chan,ints, "digits/20",lang); 01989 if (!res) { 01990 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20); 01991 res = wait_file(chan,ints,nextmsg,lang); 01992 } 01993 } 01994 break; 01995 case 'Y': 01996 /* Year */ 01997 if (tm.tm_year > 99) { 01998 res = wait_file(chan,ints, "digits/2",lang); 01999 if (!res) { 02000 res = wait_file(chan,ints, "digits/thousand",lang); 02001 } 02002 if (tm.tm_year > 100) { 02003 if (!res) { 02004 /* This works until the end of 2020 */ 02005 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); 02006 res = wait_file(chan,ints,nextmsg,lang); 02007 } 02008 } 02009 } else { 02010 if (tm.tm_year < 1) { 02011 /* I'm not going to handle 1900 and prior */ 02012 /* We'll just be silent on the year, instead of bombing out. */ 02013 } else { 02014 res = wait_file(chan,ints, "digits/19",lang); 02015 if (!res) { 02016 if (tm.tm_year <= 9) { 02017 /* 1901 - 1909 */ 02018 res = wait_file(chan,ints, "digits/oh",lang); 02019 if (!res) { 02020 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02021 res = wait_file(chan,ints,nextmsg,lang); 02022 } 02023 } else if (tm.tm_year <= 20) { 02024 /* 1910 - 1920 */ 02025 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02026 res = wait_file(chan,ints,nextmsg,lang); 02027 } else { 02028 /* 1921 - 1999 */ 02029 int ten, one; 02030 ten = tm.tm_year / 10; 02031 one = tm.tm_year % 10; 02032 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); 02033 res = wait_file(chan,ints,nextmsg,lang); 02034 if (!res) { 02035 if (one != 0) { 02036 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02037 res = wait_file(chan,ints,nextmsg,lang); 02038 } 02039 } 02040 } 02041 } 02042 } 02043 } 02044 break; 02045 case 'I': 02046 case 'l': 02047 /* 12-Hour */ 02048 if (tm.tm_hour == 0) 02049 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 02050 else if (tm.tm_hour > 12) 02051 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 02052 else 02053 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 02054 res = wait_file(chan,ints,nextmsg,lang); 02055 break; 02056 case 'H': 02057 case 'k': 02058 /* 24-Hour */ 02059 if (format[offset] == 'H') { 02060 /* e.g. oh-eight */ 02061 if (tm.tm_hour < 10) { 02062 res = wait_file(chan,ints, "digits/oh",lang); 02063 } 02064 } else { 02065 /* e.g. eight */ 02066 if (tm.tm_hour == 0) { 02067 res = wait_file(chan,ints, "digits/oh",lang); 02068 } 02069 } 02070 if (!res) { 02071 if (tm.tm_hour != 0) { 02072 int remainder = tm.tm_hour; 02073 if (tm.tm_hour > 20) { 02074 res = wait_file(chan,ints, "digits/20",lang); 02075 remainder -= 20; 02076 } 02077 if (!res) { 02078 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 02079 res = wait_file(chan,ints,nextmsg,lang); 02080 } 02081 } 02082 } 02083 break; 02084 case 'M': 02085 /* Minute */ 02086 if (tm.tm_min == 0) { 02087 res = wait_file(chan,ints, "digits/oclock",lang); 02088 } else if (tm.tm_min < 10) { 02089 res = wait_file(chan,ints, "digits/oh",lang); 02090 if (!res) { 02091 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 02092 res = wait_file(chan,ints,nextmsg,lang); 02093 } 02094 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) { 02095 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 02096 res = wait_file(chan,ints,nextmsg,lang); 02097 } else { 02098 int ten, one; 02099 ten = (tm.tm_min / 10) * 10; 02100 one = (tm.tm_min % 10); 02101 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02102 res = wait_file(chan,ints,nextmsg,lang); 02103 if (!res) { 02104 /* Fifty, not fifty-zero */ 02105 if (one != 0) { 02106 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02107 res = wait_file(chan,ints,nextmsg,lang); 02108 } 02109 } 02110 } 02111 break; 02112 case 'P': 02113 case 'p': 02114 /* AM/PM */ 02115 if (tm.tm_hour > 11) 02116 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 02117 else 02118 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 02119 res = wait_file(chan,ints,nextmsg,lang); 02120 break; 02121 case 'Q': 02122 /* Shorthand for "Today", "Yesterday", or ABdY */ 02123 { 02124 struct timeval now; 02125 struct tm tmnow; 02126 time_t beg_today; 02127 02128 gettimeofday(&now,NULL); 02129 ast_localtime(&now.tv_sec,&tmnow,timezone); 02130 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02131 /* In any case, it saves not having to do ast_mktime() */ 02132 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02133 if (beg_today < time) { 02134 /* Today */ 02135 res = wait_file(chan,ints, "digits/today",lang); 02136 } else if (beg_today - 86400 < time) { 02137 /* Yesterday */ 02138 res = wait_file(chan,ints, "digits/yesterday",lang); 02139 } else { 02140 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02141 } 02142 } 02143 break; 02144 case 'q': 02145 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02146 { 02147 struct timeval now; 02148 struct tm tmnow; 02149 time_t beg_today; 02150 02151 gettimeofday(&now,NULL); 02152 ast_localtime(&now.tv_sec,&tmnow,timezone); 02153 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02154 /* In any case, it saves not having to do ast_mktime() */ 02155 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02156 if (beg_today < time) { 02157 /* Today */ 02158 } else if ((beg_today - 86400) < time) { 02159 /* Yesterday */ 02160 res = wait_file(chan,ints, "digits/yesterday",lang); 02161 } else if (beg_today - 86400 * 6 < time) { 02162 /* Within the last week */ 02163 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02164 } else { 02165 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02166 } 02167 } 02168 break; 02169 case 'R': 02170 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); 02171 break; 02172 case 'S': 02173 /* Seconds */ 02174 if (tm.tm_sec == 0) { 02175 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02176 res = wait_file(chan,ints,nextmsg,lang); 02177 } else if (tm.tm_sec < 10) { 02178 res = wait_file(chan,ints, "digits/oh",lang); 02179 if (!res) { 02180 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02181 res = wait_file(chan,ints,nextmsg,lang); 02182 } 02183 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02184 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02185 res = wait_file(chan,ints,nextmsg,lang); 02186 } else { 02187 int ten, one; 02188 ten = (tm.tm_sec / 10) * 10; 02189 one = (tm.tm_sec % 10); 02190 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02191 res = wait_file(chan,ints,nextmsg,lang); 02192 if (!res) { 02193 /* Fifty, not fifty-zero */ 02194 if (one != 0) { 02195 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02196 res = wait_file(chan,ints,nextmsg,lang); 02197 } 02198 } 02199 } 02200 break; 02201 case 'T': 02202 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02203 break; 02204 case ' ': 02205 case ' ': 02206 /* Just ignore spaces and tabs */ 02207 break; 02208 default: 02209 /* Unknown character */ 02210 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02211 } 02212 /* Jump out on DTMF */ 02213 if (res) { 02214 break; 02215 } 02216 } 02217 return res; 02218 } 02219 02220 /* German syntax */ 02221 /* NB This currently is a 100% clone of the English syntax, just getting ready to make changes... */ 02222 int ast_say_date_with_format_de(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02223 { 02224 struct tm tm; 02225 int res=0, offset, sndoffset; 02226 char sndfile[256], nextmsg[256]; 02227 02228 ast_localtime(&time,&tm,timezone); 02229 02230 for (offset=0 ; format[offset] != '\0' ; offset++) { 02231 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02232 switch (format[offset]) { 02233 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02234 case '\'': 02235 /* Literal name of a sound file */ 02236 sndoffset=0; 02237 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02238 sndfile[sndoffset] = format[offset]; 02239 sndfile[sndoffset] = '\0'; 02240 res = wait_file(chan,ints,sndfile,lang); 02241 break; 02242 case 'A': 02243 case 'a': 02244 /* Sunday - Saturday */ 02245 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 02246 res = wait_file(chan,ints,nextmsg,lang); 02247 break; 02248 case 'B': 02249 case 'b': 02250 case 'h': 02251 /* January - December */ 02252 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 02253 res = wait_file(chan,ints,nextmsg,lang); 02254 break; 02255 case 'd': 02256 case 'e': 02257 /* First - Thirtyfirst */ 02258 if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) { 02259 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 02260 res = wait_file(chan,ints,nextmsg,lang); 02261 } else if (tm.tm_mday == 31) { 02262 /* "Thirty" and "first" */ 02263 res = wait_file(chan,ints, "digits/30",lang); 02264 if (!res) { 02265 res = wait_file(chan,ints, "digits/h-1",lang); 02266 } 02267 } else { 02268 /* Between 21 and 29 - two sounds */ 02269 res = wait_file(chan,ints, "digits/20",lang); 02270 if (!res) { 02271 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20); 02272 res = wait_file(chan,ints,nextmsg,lang); 02273 } 02274 } 02275 break; 02276 case 'Y': 02277 /* Year */ 02278 if (tm.tm_year > 99) { 02279 res = wait_file(chan,ints, "digits/2",lang); 02280 if (!res) { 02281 res = wait_file(chan,ints, "digits/thousand",lang); 02282 } 02283 if (tm.tm_year > 100) { 02284 if (!res) { 02285 /* This works until the end of 2020 */ 02286 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); 02287 res = wait_file(chan,ints,nextmsg,lang); 02288 } 02289 } 02290 } else { 02291 if (tm.tm_year < 1) { 02292 /* I'm not going to handle 1900 and prior */ 02293 /* We'll just be silent on the year, instead of bombing out. */ 02294 } else { 02295 res = wait_file(chan,ints, "digits/19",lang); 02296 if (!res) { 02297 if (tm.tm_year <= 9) { 02298 /* 1901 - 1909 */ 02299 res = wait_file(chan,ints, "digits/oh",lang); 02300 if (!res) { 02301 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02302 res = wait_file(chan,ints,nextmsg,lang); 02303 } 02304 } else if (tm.tm_year <= 20) { 02305 /* 1910 - 1920 */ 02306 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02307 res = wait_file(chan,ints,nextmsg,lang); 02308 } else { 02309 /* 1921 - 1999 */ 02310 int ten, one; 02311 ten = tm.tm_year / 10; 02312 one = tm.tm_year % 10; 02313 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); 02314 res = wait_file(chan,ints,nextmsg,lang); 02315 if (!res) { 02316 if (one != 0) { 02317 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02318 res = wait_file(chan,ints,nextmsg,lang); 02319 } 02320 } 02321 } 02322 } 02323 } 02324 } 02325 break; 02326 case 'I': 02327 case 'l': 02328 /* 12-Hour */ 02329 if (tm.tm_hour == 0) 02330 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 02331 else if (tm.tm_hour > 12) 02332 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 02333 else 02334 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 02335 res = wait_file(chan,ints,nextmsg,lang); 02336 break; 02337 case 'H': 02338 case 'k': 02339 /* 24-Hour */ 02340 if (format[offset] == 'H') { 02341 /* e.g. oh-eight */ 02342 if (tm.tm_hour < 10) { 02343 res = wait_file(chan,ints, "digits/oh",lang); 02344 } 02345 } else { 02346 /* e.g. eight */ 02347 if (tm.tm_hour == 0) { 02348 res = wait_file(chan,ints, "digits/oh",lang); 02349 } 02350 } 02351 if (!res) { 02352 if (tm.tm_hour != 0) { 02353 int remainder = tm.tm_hour; 02354 if (tm.tm_hour > 20) { 02355 res = wait_file(chan,ints, "digits/20",lang); 02356 remainder -= 20; 02357 } 02358 if (!res) { 02359 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 02360 res = wait_file(chan,ints,nextmsg,lang); 02361 } 02362 } 02363 } 02364 break; 02365 case 'M': 02366 /* Minute */ 02367 if (tm.tm_min == 0) { 02368 res = wait_file(chan,ints, "digits/oclock",lang); 02369 } else if (tm.tm_min < 10) { 02370 res = wait_file(chan,ints, "digits/oh",lang); 02371 if (!res) { 02372 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 02373 res = wait_file(chan,ints,nextmsg,lang); 02374 } 02375 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) { 02376 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 02377 res = wait_file(chan,ints,nextmsg,lang); 02378 } else { 02379 int ten, one; 02380 ten = (tm.tm_min / 10) * 10; 02381 one = (tm.tm_min % 10); 02382 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02383 res = wait_file(chan,ints,nextmsg,lang); 02384 if (!res) { 02385 /* Fifty, not fifty-zero */ 02386 if (one != 0) { 02387 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02388 res = wait_file(chan,ints,nextmsg,lang); 02389 } 02390 } 02391 } 02392 break; 02393 case 'P': 02394 case 'p': 02395 /* AM/PM */ 02396 if (tm.tm_hour > 11) 02397 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 02398 else 02399 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 02400 res = wait_file(chan,ints,nextmsg,lang); 02401 break; 02402 case 'Q': 02403 /* Shorthand for "Today", "Yesterday", or ABdY */ 02404 { 02405 struct timeval now; 02406 struct tm tmnow; 02407 time_t beg_today; 02408 02409 gettimeofday(&now,NULL); 02410 ast_localtime(&now.tv_sec,&tmnow,timezone); 02411 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02412 /* In any case, it saves not having to do ast_mktime() */ 02413 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02414 if (beg_today < time) { 02415 /* Today */ 02416 res = wait_file(chan,ints, "digits/today",lang); 02417 } else if (beg_today - 86400 < time) { 02418 /* Yesterday */ 02419 res = wait_file(chan,ints, "digits/yesterday",lang); 02420 } else { 02421 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02422 } 02423 } 02424 break; 02425 case 'q': 02426 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02427 { 02428 struct timeval now; 02429 struct tm tmnow; 02430 time_t beg_today; 02431 02432 gettimeofday(&now,NULL); 02433 ast_localtime(&now.tv_sec,&tmnow,timezone); 02434 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02435 /* In any case, it saves not having to do ast_mktime() */ 02436 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02437 if (beg_today < time) { 02438 /* Today */ 02439 } else if ((beg_today - 86400) < time) { 02440 /* Yesterday */ 02441 res = wait_file(chan,ints, "digits/yesterday",lang); 02442 } else if (beg_today - 86400 * 6 < time) { 02443 /* Within the last week */ 02444 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02445 } else { 02446 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02447 } 02448 } 02449 break; 02450 case 'R': 02451 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); 02452 break; 02453 case 'S': 02454 /* Seconds */ 02455 if (tm.tm_sec == 0) { 02456 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02457 res = wait_file(chan,ints,nextmsg,lang); 02458 } else if (tm.tm_sec < 10) { 02459 res = wait_file(chan,ints, "digits/oh",lang); 02460 if (!res) { 02461 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02462 res = wait_file(chan,ints,nextmsg,lang); 02463 } 02464 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02465 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02466 res = wait_file(chan,ints,nextmsg,lang); 02467 } else { 02468 int ten, one; 02469 ten = (tm.tm_sec / 10) * 10; 02470 one = (tm.tm_sec % 10); 02471 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02472 res = wait_file(chan,ints,nextmsg,lang); 02473 if (!res) { 02474 /* Fifty, not fifty-zero */ 02475 if (one != 0) { 02476 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02477 res = wait_file(chan,ints,nextmsg,lang); 02478 } 02479 } 02480 } 02481 break; 02482 case 'T': 02483 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02484 break; 02485 case ' ': 02486 case ' ': 02487 /* Just ignore spaces and tabs */ 02488 break; 02489 default: 02490 /* Unknown character */ 02491 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02492 } 02493 /* Jump out on DTMF */ 02494 if (res) { 02495 break; 02496 } 02497 } 02498 return res; 02499 } 02500 02501 /* Spanish syntax */ 02502 int ast_say_date_with_format_es(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02503 { 02504 struct tm tm; 02505 int res=0, offset, sndoffset; 02506 char sndfile[256], nextmsg[256]; 02507 02508 ast_localtime(&time,&tm,timezone); 02509 02510 for (offset=0 ; format[offset] != '\0' ; offset++) { 02511 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02512 switch (format[offset]) { 02513 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02514 case '\'': 02515 /* Literal name of a sound file */ 02516 sndoffset=0; 02517 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02518 sndfile[sndoffset] = format[offset]; 02519 sndfile[sndoffset] = '\0'; 02520 snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile); 02521 res = wait_file(chan,ints,nextmsg,lang); 02522 break; 02523 case 'A': 02524 case 'a': 02525 /* Sunday - Saturday */ 02526 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 02527 res = wait_file(chan,ints,nextmsg,lang); 02528 break; 02529 case 'B': 02530 case 'b': 02531 case 'h': 02532 /* January - December */ 02533 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 02534 res = wait_file(chan,ints,nextmsg,lang); 02535 break; 02536 case 'd': 02537 case 'e': 02538 /* First - Thirtyfirst */ 02539 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 02540 break; 02541 case 'Y': 02542 /* Year */ 02543 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 02544 break; 02545 case 'I': 02546 case 'l': 02547 /* 12-Hour */ 02548 if (tm.tm_hour == 0) 02549 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 02550 else if (tm.tm_hour > 12) 02551 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 02552 else 02553 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 02554 res = wait_file(chan,ints,nextmsg,lang); 02555 break; 02556 case 'H': 02557 case 'k': 02558 /* 24-Hour */ 02559 res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL); 02560 if (!res) { 02561 if (tm.tm_hour != 0) { 02562 int remainder = tm.tm_hour; 02563 if (tm.tm_hour > 20) { 02564 res = wait_file(chan,ints, "digits/20",lang); 02565 remainder -= 20; 02566 } 02567 if (!res) { 02568 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 02569 res = wait_file(chan,ints,nextmsg,lang); 02570 } 02571 } 02572 } 02573 break; 02574 case 'M': 02575 /* Minute */ 02576 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 02577 break; 02578 case 'P': 02579 case 'p': 02580 /* AM/PM */ 02581 if (tm.tm_hour > 12) 02582 res = wait_file(chan, ints, "digits/p-m", lang); 02583 else if (tm.tm_hour && tm.tm_hour < 12) 02584 res = wait_file(chan, ints, "digits/a-m", lang); 02585 break; 02586 case 'Q': 02587 /* Shorthand for "Today", "Yesterday", or ABdY */ 02588 { 02589 struct timeval now; 02590 struct tm tmnow; 02591 time_t beg_today; 02592 02593 gettimeofday(&now,NULL); 02594 ast_localtime(&now.tv_sec,&tmnow,timezone); 02595 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02596 /* In any case, it saves not having to do ast_mktime() */ 02597 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02598 if (beg_today < time) { 02599 /* Today */ 02600 res = wait_file(chan,ints, "digits/today",lang); 02601 } else if (beg_today - 86400 < time) { 02602 /* Yesterday */ 02603 res = wait_file(chan,ints, "digits/yesterday",lang); 02604 } else { 02605 res = ast_say_date_with_format(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone); 02606 } 02607 } 02608 break; 02609 case 'q': 02610 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02611 { 02612 struct timeval now; 02613 struct tm tmnow; 02614 time_t beg_today; 02615 02616 gettimeofday(&now,NULL); 02617 ast_localtime(&now.tv_sec,&tmnow,timezone); 02618 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02619 /* In any case, it saves not having to do ast_mktime() */ 02620 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02621 if (beg_today < time) { 02622 /* Today */ 02623 res = wait_file(chan,ints, "digits/today",lang); 02624 } else if ((beg_today - 86400) < time) { 02625 /* Yesterday */ 02626 res = wait_file(chan,ints, "digits/yesterday",lang); 02627 } else if (beg_today - 86400 * 6 < time) { 02628 /* Within the last week */ 02629 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02630 } else { 02631 res = ast_say_date_with_format(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone); 02632 } 02633 } 02634 break; 02635 case 'R': 02636 res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/y' M", timezone); 02637 break; 02638 case 'S': 02639 /* Seconds */ 02640 if (tm.tm_sec == 0) { 02641 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02642 res = wait_file(chan,ints,nextmsg,lang); 02643 } else if (tm.tm_sec < 10) { 02644 res = wait_file(chan,ints, "digits/oh",lang); 02645 if (!res) { 02646 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02647 res = wait_file(chan,ints,nextmsg,lang); 02648 } 02649 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02650 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02651 res = wait_file(chan,ints,nextmsg,lang); 02652 } else { 02653 int ten, one; 02654 ten = (tm.tm_sec / 10) * 10; 02655 one = (tm.tm_sec % 10); 02656 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02657 res = wait_file(chan,ints,nextmsg,lang); 02658 if (!res) { 02659 /* Fifty, not fifty-zero */ 02660 if (one != 0) { 02661 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02662 res = wait_file(chan,ints,nextmsg,lang); 02663 } 02664 } 02665 } 02666 break; 02667 case 'T': 02668 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02669 break; 02670 case ' ': 02671 case ' ': 02672 /* Just ignore spaces and tabs */ 02673 break; 02674 default: 02675 /* Unknown character */ 02676 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02677 } 02678 /* Jump out on DTMF */ 02679 if (res) { 02680 break; 02681 } 02682 } 02683 return res; 02684 } 02685 02686 /* Dutch syntax */ 02687 int ast_say_date_with_format_nl(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02688 { 02689 struct tm tm; 02690 int res=0, offset, sndoffset; 02691 char sndfile[256], nextmsg[256]; 02692 02693 ast_localtime(&time,&tm,timezone); 02694 02695 for (offset=0 ; format[offset] != '\0' ; offset++) { 02696 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02697 switch (format[offset]) { 02698 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02699 case '\'': 02700 /* Literal name of a sound file */ 02701 sndoffset=0; 02702 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02703 sndfile[sndoffset] = format[offset]; 02704 sndfile[sndoffset] = '\0'; 02705 res = wait_file(chan,ints,sndfile,lang); 02706 break; 02707 case 'A': 02708 case 'a': 02709 /* Sunday - Saturday */ 02710 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 02711 res = wait_file(chan,ints,nextmsg,lang); 02712 break; 02713 case 'B': 02714 case 'b': 02715 case 'h': 02716 /* January - December */ 02717 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 02718 res = wait_file(chan,ints,nextmsg,lang); 02719 break; 02720 case 'd': 02721 case 'e': 02722 /* First - Thirtyfirst */ 02723 res = ast_say_number(chan, tm.tm_mday, ints, lang, NULL); 02724 break; 02725 case 'Y': 02726 /* Year */ 02727 if (tm.tm_year > 99) { 02728 res = wait_file(chan,ints, "digits/2",lang); 02729 if (!res) { 02730 res = wait_file(chan,ints, "digits/thousand",lang); 02731 } 02732 if (tm.tm_year > 100) { 02733 if (!res) { 02734 /* This works until the end of 2020 */ 02735 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); 02736 res = wait_file(chan,ints,nextmsg,lang); 02737 } 02738 } 02739 } else { 02740 if (tm.tm_year < 1) { 02741 /* I'm not going to handle 1900 and prior */ 02742 /* We'll just be silent on the year, instead of bombing out. */ 02743 } else { 02744 res = wait_file(chan,ints, "digits/19",lang); 02745 if (!res) { 02746 if (tm.tm_year <= 9) { 02747 /* 1901 - 1909 */ 02748 res = wait_file(chan,ints, "digits/oh",lang); 02749 if (!res) { 02750 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02751 res = wait_file(chan,ints,nextmsg,lang); 02752 } 02753 } else if (tm.tm_year <= 20) { 02754 /* 1910 - 1920 */ 02755 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02756 res = wait_file(chan,ints,nextmsg,lang); 02757 } else { 02758 /* 1921 - 1999 */ 02759 int ten, one; 02760 ten = tm.tm_year / 10; 02761 one = tm.tm_year % 10; 02762 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); 02763 res = wait_file(chan,ints,nextmsg,lang); 02764 if (!res) { 02765 if (one != 0) { 02766 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02767 res = wait_file(chan,ints,nextmsg,lang); 02768 } 02769 } 02770 } 02771 } 02772 } 02773 } 02774 break; 02775 case 'I': 02776 case 'l': 02777 /* 12-Hour */ 02778 if (tm.tm_hour == 0) 02779 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 02780 else if (tm.tm_hour > 12) 02781 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 02782 else 02783 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 02784 res = wait_file(chan,ints,nextmsg,lang); 02785 break; 02786 case 'H': 02787 case 'k': 02788 /* 24-Hour */ 02789 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL); 02790 if (!res) { 02791 res = wait_file(chan,ints, "digits/nl-uur",lang); 02792 } 02793 break; 02794 case 'M': 02795 /* Minute */ 02796 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 02797 break; 02798 case 'P': 02799 case 'p': 02800 /* AM/PM */ 02801 if (tm.tm_hour > 11) 02802 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 02803 else 02804 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 02805 res = wait_file(chan,ints,nextmsg,lang); 02806 break; 02807 case 'Q': 02808 /* Shorthand for "Today", "Yesterday", or ABdY */ 02809 { 02810 struct timeval now; 02811 struct tm tmnow; 02812 time_t beg_today; 02813 02814 gettimeofday(&now,NULL); 02815 ast_localtime(&now.tv_sec,&tmnow,timezone); 02816 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02817 /* In any case, it saves not having to do ast_mktime() */ 02818 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02819 if (beg_today < time) { 02820 /* Today */ 02821 res = wait_file(chan,ints, "digits/today",lang); 02822 } else if (beg_today - 86400 < time) { 02823 /* Yesterday */ 02824 res = wait_file(chan,ints, "digits/yesterday",lang); 02825 } else { 02826 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02827 } 02828 } 02829 break; 02830 case 'q': 02831 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02832 { 02833 struct timeval now; 02834 struct tm tmnow; 02835 time_t beg_today; 02836 02837 gettimeofday(&now,NULL); 02838 ast_localtime(&now.tv_sec,&tmnow,timezone); 02839 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02840 /* In any case, it saves not having to do ast_mktime() */ 02841 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02842 if (beg_today < time) { 02843 /* Today */ 02844 } else if ((beg_today - 86400) < time) { 02845 /* Yesterday */ 02846 res = wait_file(chan,ints, "digits/yesterday",lang); 02847 } else if (beg_today - 86400 * 6 < time) { 02848 /* Within the last week */ 02849 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02850 } else { 02851 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02852 } 02853 } 02854 break; 02855 case 'R': 02856 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); 02857 break; 02858 case 'S': 02859 /* Seconds */ 02860 if (tm.tm_sec == 0) { 02861 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02862 res = wait_file(chan,ints,nextmsg,lang); 02863 } else if (tm.tm_sec < 10) { 02864 res = wait_file(chan,ints, "digits/oh",lang); 02865 if (!res) { 02866 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02867 res = wait_file(chan,ints,nextmsg,lang); 02868 } 02869 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02870 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02871 res = wait_file(chan,ints,nextmsg,lang); 02872 } else { 02873 int ten, one; 02874 ten = (tm.tm_sec / 10) * 10; 02875 one = (tm.tm_sec % 10); 02876 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02877 res = wait_file(chan,ints,nextmsg,lang); 02878 if (!res) { 02879 /* Fifty, not fifty-zero */ 02880 if (one != 0) { 02881 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02882 res = wait_file(chan,ints,nextmsg,lang); 02883 } 02884 } 02885 } 02886 break; 02887 case 'T': 02888 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02889 break; 02890 case ' ': 02891 case ' ': 02892 /* Just ignore spaces and tabs */ 02893 break; 02894 default: 02895 /* Unknown character */ 02896 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02897 } 02898 /* Jump out on DTMF */ 02899 if (res) { 02900 break; 02901 } 02902 } 02903 return res; 02904 } 02905 02906 /* Portuguese syntax */ 02907 int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02908 { 02909 struct tm tm; 02910 int res=0, offset, sndoffset; 02911 char sndfile[256], nextmsg[256]; 02912 02913 ast_localtime(&time,&tm,timezone); 02914 02915 for (offset=0 ; format[offset] != '\0' ; offset++) { 02916 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02917 switch (format[offset]) { 02918 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02919 case '\'': 02920 /* Literal name of a sound file */ 02921 sndoffset=0; 02922 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02923 sndfile[sndoffset] = format[offset]; 02924 sndfile[sndoffset] = '\0'; 02925 snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile); 02926 res = wait_file(chan,ints,nextmsg,lang); 02927 break; 02928 case 'A': 02929 case 'a': 02930 /* Sunday - Saturday */ 02931 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 02932 res = wait_file(chan,ints,nextmsg,lang); 02933 break; 02934 case 'B': 02935 case 'b': 02936 case 'h': 02937 /* January - December */ 02938 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 02939 res = wait_file(chan,ints,nextmsg,lang); 02940 break; 02941 case 'd': 02942 case 'e': 02943 /* First - Thirtyfirst */ 02944 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 02945 break; 02946 case 'Y': 02947 /* Year */ 02948 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 02949 break; 02950 case 'I': 02951 case 'l': 02952 /* 12-Hour */ 02953 if (tm.tm_hour == 0) { 02954 if (format[offset] == 'I') 02955 res = wait_file(chan, ints, "digits/pt-ah", lang); 02956 if (!res) 02957 res = wait_file(chan, ints, "digits/pt-meianoite", lang); 02958 } 02959 else if (tm.tm_hour == 12) { 02960 if (format[offset] == 'I') 02961 res = wait_file(chan, ints, "digits/pt-ao", lang); 02962 if (!res) 02963 res = wait_file(chan, ints, "digits/pt-meiodia", lang); 02964 } 02965 else { 02966 if (format[offset] == 'I') { 02967 res = wait_file(chan, ints, "digits/pt-ah", lang); 02968 if ((tm.tm_hour % 12) != 1) 02969 if (!res) 02970 res = wait_file(chan, ints, "digits/pt-sss", lang); 02971 } 02972 if (!res) 02973 res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f"); 02974 } 02975 break; 02976 case 'H': 02977 case 'k': 02978 /* 24-Hour */ 02979 res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL); 02980 if (!res) { 02981 if (tm.tm_hour != 0) { 02982 int remainder = tm.tm_hour; 02983 if (tm.tm_hour > 20) { 02984 res = wait_file(chan,ints, "digits/20",lang); 02985 remainder -= 20; 02986 } 02987 if (!res) { 02988 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 02989 res = wait_file(chan,ints,nextmsg,lang); 02990 } 02991 } 02992 } 02993 break; 02994 case 'M': 02995 /* Minute */ 02996 if (tm.tm_min == 0) { 02997 res = wait_file(chan, ints, "digits/pt-hora", lang); 02998 if (tm.tm_hour != 1) 02999 if (!res) 03000 res = wait_file(chan, ints, "digits/pt-sss", lang); } else { 03001 res = wait_file(chan,ints,"digits/pt-e",lang); 03002 if (!res) 03003 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03004 } 03005 break; 03006 case 'P': 03007 case 'p': 03008 /* AM/PM */ 03009 if (tm.tm_hour > 12) 03010 res = wait_file(chan, ints, "digits/p-m", lang); 03011 else if (tm.tm_hour && tm.tm_hour < 12) 03012 res = wait_file(chan, ints, "digits/a-m", lang); 03013 break; 03014 case 'Q': 03015 /* Shorthand for "Today", "Yesterday", or ABdY */ 03016 { 03017 struct timeval now; 03018 struct tm tmnow; 03019 time_t beg_today; 03020 03021 gettimeofday(&now,NULL); 03022 ast_localtime(&now.tv_sec,&tmnow,timezone); 03023 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03024 /* In any case, it saves not having to do ast_mktime() */ 03025 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03026 if (beg_today < time) { 03027 /* Today */ 03028 res = wait_file(chan,ints, "digits/today",lang); 03029 } else if (beg_today - 86400 < time) { 03030 /* Yesterday */ 03031 res = wait_file(chan,ints, "digits/yesterday",lang); 03032 } else { 03033 res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone); 03034 } 03035 } 03036 break; 03037 case 'q': 03038 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 03039 { 03040 struct timeval now; 03041 struct tm tmnow; 03042 time_t beg_today; 03043 03044 gettimeofday(&now,NULL); 03045 ast_localtime(&now.tv_sec,&tmnow,timezone); 03046 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03047 /* In any case, it saves not having to do ast_mktime() */ 03048 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03049 if (beg_today < time) { 03050 /* Today */ 03051 } else if ((beg_today - 86400) < time) { 03052 /* Yesterday */ 03053 res = wait_file(chan,ints, "digits/yesterday",lang); 03054 } else if (beg_today - 86400 * 6 < time) { 03055 /* Within the last week */ 03056 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 03057 } else { 03058 res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone); 03059 } 03060 } 03061 break; 03062 case 'R': 03063 res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/pt-e' M", timezone); 03064 break; 03065 case 'S': 03066 /* Seconds */ 03067 if (tm.tm_sec == 0) { 03068 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03069 res = wait_file(chan,ints,nextmsg,lang); 03070 } else if (tm.tm_sec < 10) { 03071 res = wait_file(chan,ints, "digits/oh",lang); 03072 if (!res) { 03073 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03074 res = wait_file(chan,ints,nextmsg,lang); 03075 } 03076 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 03077 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03078 res = wait_file(chan,ints,nextmsg,lang); 03079 } else { 03080 int ten, one; 03081 ten = (tm.tm_sec / 10) * 10; 03082 one = (tm.tm_sec % 10); 03083 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 03084 res = wait_file(chan,ints,nextmsg,lang); 03085 if (!res) { 03086 /* Fifty, not fifty-zero */ 03087 if (one != 0) { 03088 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 03089 res = wait_file(chan,ints,nextmsg,lang); 03090 } 03091 } 03092 } 03093 break; 03094 case 'T': 03095 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 03096 break; 03097 case ' ': 03098 case ' ': 03099 /* Just ignore spaces and tabs */ 03100 break; 03101 default: 03102 /* Unknown character */ 03103 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 03104 } 03105 /* Jump out on DTMF */ 03106 if (res) { 03107 break; 03108 } 03109 } 03110 return res; 03111 } 03112 03113 /* Taiwanese syntax */ 03114 int ast_say_date_with_format_tw(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 03115 { 03116 struct tm tm; 03117 int res=0, offset, sndoffset; 03118 char sndfile[256], nextmsg[256]; 03119 03120 ast_localtime(&time,&tm,timezone); 03121 03122 for (offset=0 ; format[offset] != '\0' ; offset++) { 03123 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 03124 switch (format[offset]) { 03125 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 03126 case '\'': 03127 /* Literal name of a sound file */ 03128 sndoffset=0; 03129 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 03130 sndfile[sndoffset] = format[offset]; 03131 sndfile[sndoffset] = '\0'; 03132 res = wait_file(chan,ints,sndfile,lang); 03133 break; 03134 case 'A': 03135 case 'a': 03136 /* Sunday - Saturday */ 03137 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 03138 res = wait_file(chan,ints,nextmsg,lang); 03139 break; 03140 case 'B': 03141 case 'b': 03142 case 'h': 03143 /* January - December */ 03144 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 03145 res = wait_file(chan,ints,nextmsg,lang); 03146 break; 03147 case 'd': 03148 case 'e': 03149 /* First - Thirtyfirst */ 03150 if (!(tm.tm_mday % 10) || (tm.tm_mday < 10)) { 03151 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 03152 res = wait_file(chan,ints,nextmsg,lang); 03153 } else { 03154 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%dh", tm.tm_mday - (tm.tm_mday % 10)); 03155 res = wait_file(chan,ints,nextmsg,lang); 03156 if(!res) { 03157 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday % 10); 03158 res = wait_file(chan,ints,nextmsg,lang); 03159 } 03160 } 03161 break; 03162 case 'Y': 03163 /* Year */ 03164 if (tm.tm_year > 99) { 03165 res = wait_file(chan,ints, "digits/2",lang); 03166 if (!res) { 03167 res = wait_file(chan,ints, "digits/thousand",lang); 03168 } 03169 if (tm.tm_year > 100) { 03170 if (!res) { 03171 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (tm.tm_year - 100) / 10); 03172 res = wait_file(chan,ints,nextmsg,lang); 03173 if (!res) { 03174 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (tm.tm_year - 100) % 10); 03175 res = wait_file(chan,ints,nextmsg,lang); 03176 } 03177 } 03178 } 03179 if (!res) { 03180 res = wait_file(chan,ints, "digits/year",lang); 03181 } 03182 } else { 03183 if (tm.tm_year < 1) { 03184 /* I'm not going to handle 1900 and prior */ 03185 /* We'll just be silent on the year, instead of bombing out. */ 03186 } else { 03187 res = wait_file(chan,ints, "digits/1",lang); 03188 if (!res) { 03189 res = wait_file(chan,ints, "digits/9",lang); 03190 } 03191 if (!res) { 03192 if (tm.tm_year <= 9) { 03193 /* 1901 - 1909 */ 03194 res = wait_file(chan,ints, "digits/0",lang); 03195 if (!res) { 03196 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 03197 res = wait_file(chan,ints,nextmsg,lang); 03198 } 03199 } else { 03200 /* 1910 - 1999 */ 03201 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year / 10); 03202 res = wait_file(chan,ints,nextmsg,lang); 03203 if (!res) { 03204 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year % 10); 03205 res = wait_file(chan,ints,nextmsg,lang); 03206 } 03207 } 03208 } 03209 } 03210 if (!res) { 03211 res = wait_file(chan,ints, "digits/year",lang); 03212 } 03213 } 03214 break; 03215 case 'I': 03216 case 'l': 03217 /* 12-Hour */ 03218 if (tm.tm_hour == 0) 03219 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 03220 else if (tm.tm_hour > 12) 03221 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 03222 else 03223 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 03224 res = wait_file(chan,ints,nextmsg,lang); 03225 if (!res) { 03226 res = wait_file(chan,ints, "digits/oclock",lang); 03227 } 03228 break; 03229 case 'H': 03230 case 'k': 03231 /* 24-Hour */ 03232 if (!(tm.tm_hour % 10) || tm.tm_hour < 10) { 03233 if (tm.tm_hour < 10) { 03234 res = wait_file(chan, ints, "digits/0", lang); 03235 } 03236 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 03237 res = wait_file(chan,ints,nextmsg,lang); 03238 } else { 03239 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - (tm.tm_hour % 10)); 03240 res = wait_file(chan,ints,nextmsg,lang); 03241 if (!res) { 03242 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour % 10); 03243 res = wait_file(chan,ints,nextmsg,lang); 03244 } 03245 } 03246 if (!res) { 03247 res = wait_file(chan,ints, "digits/oclock",lang); 03248 } 03249 break; 03250 case 'M': 03251 /* Minute */ 03252 if (!(tm.tm_min % 10) || tm.tm_min < 10) { 03253 if (tm.tm_min < 10) { 03254 res = wait_file(chan, ints, "digits/0", lang); 03255 } 03256 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 03257 res = wait_file(chan,ints,nextmsg,lang); 03258 } else { 03259 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min - (tm.tm_min % 10)); 03260 res = wait_file(chan,ints,nextmsg,lang); 03261 if (!res) { 03262 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min % 10); 03263 res = wait_file(chan,ints,nextmsg,lang); 03264 } 03265 } 03266 if (!res) { 03267 res = wait_file(chan,ints, "digits/minute",lang); 03268 } 03269 break; 03270 case 'P': 03271 case 'p': 03272 /* AM/PM */ 03273 if (tm.tm_hour > 11) 03274 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 03275 else 03276 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 03277 res = wait_file(chan,ints,nextmsg,lang); 03278 break; 03279 case 'Q': 03280 /* Shorthand for "Today", "Yesterday", or ABdY */ 03281 { 03282 struct timeval now; 03283 struct tm tmnow; 03284 time_t beg_today; 03285 03286 gettimeofday(&now,NULL); 03287 ast_localtime(&now.tv_sec,&tmnow,timezone); 03288 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03289 /* In any case, it saves not having to do ast_mktime() */ 03290 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03291 if (beg_today < time) { 03292 /* Today */ 03293 res = wait_file(chan,ints, "digits/today",lang); 03294 } else if (beg_today - 86400 < time) { 03295 /* Yesterday */ 03296 res = wait_file(chan,ints, "digits/yesterday",lang); 03297 } else { 03298 res = ast_say_date_with_format(chan, time, ints, lang, "YBdA", timezone); 03299 } 03300 } 03301 break; 03302 case 'q': 03303 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 03304 { 03305 struct timeval now; 03306 struct tm tmnow; 03307 time_t beg_today; 03308 03309 gettimeofday(&now,NULL); 03310 ast_localtime(&now.tv_sec,&tmnow,timezone); 03311 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03312 /* In any case, it saves not having to do ast_mktime() */ 03313 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03314 if (beg_today < time) { 03315 /* Today */ 03316 } else if ((beg_today - 86400) < time) { 03317 /* Yesterday */ 03318 res = wait_file(chan,ints, "digits/yesterday",lang); 03319 } else if (beg_today - 86400 * 6 < time) { 03320 /* Within the last week */ 03321 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 03322 } else { 03323 res = ast_say_date_with_format(chan, time, ints, lang, "YBdA", timezone); 03324 } 03325 } 03326 break; 03327 case 'R': 03328 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); 03329 break; 03330 case 'S': 03331 /* Seconds */ 03332 if (!(tm.tm_sec % 10) || tm.tm_sec < 10) { 03333 if (tm.tm_sec < 10) { 03334 res = wait_file(chan, ints, "digits/0", lang); 03335 } 03336 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03337 res = wait_file(chan,ints,nextmsg,lang); 03338 } else { 03339 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec - (tm.tm_sec % 10)); 03340 res = wait_file(chan,ints,nextmsg,lang); 03341 if (!res) { 03342 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec % 10); 03343 res = wait_file(chan,ints,nextmsg,lang); 03344 } 03345 } 03346 if (!res) { 03347 res = wait_file(chan,ints, "digits/second",lang); 03348 } 03349 break; 03350 case 'T': 03351 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 03352 break; 03353 case ' ': 03354 case ' ': 03355 /* Just ignore spaces and tabs */ 03356 break; 03357 default: 03358 /* Unknown character */ 03359 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 03360 } 03361 /* Jump out on DTMF */ 03362 if (res) { 03363 break; 03364 } 03365 } 03366 return res; 03367 } 03368 03369 03370 int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang) 03371 { 03372 if (!strcasecmp(lang, "en") ) { /* English syntax */ 03373 return(ast_say_time_en(chan, t, ints, lang)); 03374 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 03375 return(ast_say_time_nl(chan, t, ints, lang)); 03376 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 03377 return(ast_say_time_pt(chan, t, ints, lang)); 03378 } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ 03379 return(ast_say_time_tw(chan, t, ints, lang)); 03380 } 03381 03382 /* Default to English */ 03383 return(ast_say_time_en(chan, t, ints, lang)); 03384 } 03385 03386 /* English syntax */ 03387 int ast_say_time_en(struct ast_channel *chan, time_t t, char *ints, char *lang) 03388 { 03389 struct tm tm; 03390 int res = 0; 03391 int hour, pm=0; 03392 localtime_r(&t,&tm); 03393 hour = tm.tm_hour; 03394 if (!hour) 03395 hour = 12; 03396 else if (hour == 12) 03397 pm = 1; 03398 else if (hour > 12) { 03399 hour -= 12; 03400 pm = 1; 03401 } 03402 if (!res) 03403 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03404 03405 if (tm.tm_min > 9) { 03406 if (!res) 03407 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03408 } else if (tm.tm_min) { 03409 if (!res) 03410 res = ast_streamfile(chan, "digits/oh", lang); 03411 if (!res) 03412 res = ast_waitstream(chan, ints); 03413 if (!res) 03414 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03415 } else { 03416 if (!res) 03417 res = ast_streamfile(chan, "digits/oclock", lang); 03418 if (!res) 03419 res = ast_waitstream(chan, ints); 03420 } 03421 if (pm) { 03422 if (!res) 03423 res = ast_streamfile(chan, "digits/p-m", lang); 03424 } else { 03425 if (!res) 03426 res = ast_streamfile(chan, "digits/a-m", lang); 03427 } 03428 if (!res) 03429 res = ast_waitstream(chan, ints); 03430 return res; 03431 } 03432 03433 /* Dutch syntax */ 03434 int ast_say_time_nl(struct ast_channel *chan, time_t t, char *ints, char *lang) 03435 { 03436 struct tm tm; 03437 int res = 0; 03438 int hour; 03439 localtime_r(&t,&tm); 03440 hour = tm.tm_hour; 03441 if (!res) 03442 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03443 03444 if (!res) 03445 res = ast_streamfile(chan, "digits/nl-uur", lang); 03446 if (!res) 03447 res = ast_waitstream(chan, ints); 03448 if (!res) 03449 if (tm.tm_min > 0) 03450 res = ast_say_number(chan, tm.tm_min, ints, lang, NULL); 03451 return res; 03452 } 03453 03454 /* Portuguese syntax */ 03455 int ast_say_time_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) 03456 { 03457 struct tm tm; 03458 int res = 0; 03459 int hour; 03460 localtime_r(&t,&tm); 03461 hour = tm.tm_hour; 03462 if (!res) 03463 res = ast_say_number(chan, hour, ints, lang, "f"); 03464 if (tm.tm_min) { 03465 if (!res) 03466 res = wait_file(chan, ints, "digits/pt-e", lang); 03467 if (!res) 03468 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03469 } else { 03470 if (!res) 03471 res = wait_file(chan, ints, "digits/pt-hora", lang); 03472 if (tm.tm_hour != 1) 03473 if (!res) 03474 res = wait_file(chan, ints, "digits/pt-sss", lang); 03475 } 03476 if (!res) 03477 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03478 return res; 03479 } 03480 03481 /* Taiwanese syntax */ 03482 int ast_say_time_tw(struct ast_channel *chan, time_t t, char *ints, char *lang) 03483 { 03484 struct tm tm; 03485 int res = 0; 03486 int hour, pm=0; 03487 localtime_r(&t,&tm); 03488 hour = tm.tm_hour; 03489 if (!hour) 03490 hour = 12; 03491 else if (hour == 12) 03492 pm = 1; 03493 else if (hour > 12) { 03494 hour -= 12; 03495 pm = 1; 03496 } 03497 if (pm) { 03498 if (!res) 03499 res = ast_streamfile(chan, "digits/p-m", lang); 03500 } else { 03501 if (!res) 03502 res = ast_streamfile(chan, "digits/a-m", lang); 03503 } 03504 if (!res) 03505 res = ast_waitstream(chan, ints); 03506 if (!res) 03507 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03508 if (!res) 03509 res = ast_streamfile(chan, "digits/oclock", lang); 03510 if (!res) 03511 res = ast_waitstream(chan, ints); 03512 if (!res) 03513 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03514 if (!res) 03515 res = ast_streamfile(chan, "digits/minute", lang); 03516 if (!res) 03517 res = ast_waitstream(chan, ints); 03518 return res; 03519 } 03520 03521 03522 int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang) 03523 { 03524 if (!strcasecmp(lang, "en") ) { /* English syntax */ 03525 return(ast_say_datetime_en(chan, t, ints, lang)); 03526 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 03527 return(ast_say_datetime_nl(chan, t, ints, lang)); 03528 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 03529 return(ast_say_datetime_pt(chan, t, ints, lang)); 03530 } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ 03531 return(ast_say_datetime_tw(chan, t, ints, lang)); 03532 } 03533 03534 /* Default to English */ 03535 return(ast_say_datetime_en(chan, t, ints, lang)); 03536 } 03537 03538 /* English syntax */ 03539 int ast_say_datetime_en(struct ast_channel *chan, time_t t, char *ints, char *lang) 03540 { 03541 struct tm tm; 03542 char fn[256]; 03543 int res = 0; 03544 int hour, pm=0; 03545 localtime_r(&t,&tm); 03546 if (!res) { 03547 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03548 res = ast_streamfile(chan, fn, lang); 03549 if (!res) 03550 res = ast_waitstream(chan, ints); 03551 } 03552 if (!res) { 03553 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03554 res = ast_streamfile(chan, fn, lang); 03555 if (!res) 03556 res = ast_waitstream(chan, ints); 03557 } 03558 if (!res) 03559 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03560 03561 hour = tm.tm_hour; 03562 if (!hour) 03563 hour = 12; 03564 else if (hour == 12) 03565 pm = 1; 03566 else if (hour > 12) { 03567 hour -= 12; 03568 pm = 1; 03569 } 03570 if (!res) 03571 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03572 03573 if (tm.tm_min > 9) { 03574 if (!res) 03575 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03576 } else if (tm.tm_min) { 03577 if (!res) 03578 res = ast_streamfile(chan, "digits/oh", lang); 03579 if (!res) 03580 res = ast_waitstream(chan, ints); 03581 if (!res) 03582 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03583 } else { 03584 if (!res) 03585 res = ast_streamfile(chan, "digits/oclock", lang); 03586 if (!res) 03587 res = ast_waitstream(chan, ints); 03588 } 03589 if (pm) { 03590 if (!res) 03591 res = ast_streamfile(chan, "digits/p-m", lang); 03592 } else { 03593 if (!res) 03594 res = ast_streamfile(chan, "digits/a-m", lang); 03595 } 03596 if (!res) 03597 res = ast_waitstream(chan, ints); 03598 if (!res) 03599 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 03600 return res; 03601 } 03602 03603 /* Dutch syntax */ 03604 int ast_say_datetime_nl(struct ast_channel *chan, time_t t, char *ints, char *lang) 03605 { 03606 struct tm tm; 03607 int res = 0; 03608 localtime_r(&t,&tm); 03609 res = ast_say_date(chan, t, ints, lang); 03610 if (!res) { 03611 res = ast_streamfile(chan, "digits/nl-om", lang); 03612 if (!res) 03613 res = ast_waitstream(chan, ints); 03614 } 03615 if (!res) 03616 ast_say_time(chan, t, ints, lang); 03617 return res; 03618 } 03619 03620 /* Portuguese syntax */ 03621 int ast_say_datetime_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) 03622 { 03623 struct tm tm; 03624 char fn[256]; 03625 int res = 0; 03626 int hour, pm=0; 03627 localtime_r(&t,&tm); 03628 if (!res) { 03629 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03630 res = ast_streamfile(chan, fn, lang); 03631 if (!res) 03632 res = ast_waitstream(chan, ints); 03633 } 03634 if (!res) { 03635 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03636 res = ast_streamfile(chan, fn, lang); 03637 if (!res) 03638 res = ast_waitstream(chan, ints); 03639 } 03640 if (!res) 03641 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03642 03643 hour = tm.tm_hour; 03644 if (!hour) 03645 hour = 12; 03646 else if (hour == 12) 03647 pm = 1; 03648 else if (hour > 12) { 03649 hour -= 12; 03650 pm = 1; 03651 } 03652 if (!res) 03653 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03654 03655 if (tm.tm_min > 9) { 03656 if (!res) 03657 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03658 } else if (tm.tm_min) { 03659 if (!res) 03660 res = ast_streamfile(chan, "digits/oh", lang); 03661 if (!res) 03662 res = ast_waitstream(chan, ints); 03663 if (!res) 03664 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03665 } else { 03666 if (!res) 03667 res = ast_streamfile(chan, "digits/oclock", lang); 03668 if (!res) 03669 res = ast_waitstream(chan, ints); 03670 } 03671 if (pm) { 03672 if (!res) 03673 res = ast_streamfile(chan, "digits/p-m", lang); 03674 } else { 03675 if (!res) 03676 res = ast_streamfile(chan, "digits/a-m", lang); 03677 } 03678 if (!res) 03679 res = ast_waitstream(chan, ints); 03680 if (!res) 03681 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 03682 return res; 03683 } 03684 03685 /* Taiwanese syntax */ 03686 int ast_say_datetime_tw(struct ast_channel *chan, time_t t, char *ints, char *lang) 03687 { 03688 struct tm tm; 03689 char fn[256]; 03690 int res = 0; 03691 int hour, pm=0; 03692 localtime_r(&t,&tm); 03693 if (!res) 03694 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 03695 if (!res) { 03696 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03697 res = ast_streamfile(chan, fn, lang); 03698 if (!res) 03699 res = ast_waitstream(chan, ints); 03700 } 03701 if (!res) 03702 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03703 if (!res) { 03704 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03705 res = ast_streamfile(chan, fn, lang); 03706 if (!res) 03707 res = ast_waitstream(chan, ints); 03708 } 03709 03710 hour = tm.tm_hour; 03711 if (!hour) 03712 hour = 12; 03713 else if (hour == 12) 03714 pm = 1; 03715 else if (hour > 12) { 03716 hour -= 12; 03717 pm = 1; 03718 } 03719 if (pm) { 03720 if (!res) 03721 res = ast_streamfile(chan, "digits/p-m", lang); 03722 } else { 03723 if (!res) 03724 res = ast_streamfile(chan, "digits/a-m", lang); 03725 } 03726 if (!res) 03727 res = ast_waitstream(chan, ints); 03728 if (!res) 03729 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03730 if (!res) 03731 res = ast_streamfile(chan, "digits/oclock", lang); 03732 if (!res) 03733 res = ast_waitstream(chan, ints); 03734 if (!res) 03735 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03736 if (!res) 03737 res = ast_streamfile(chan, "digits/minute", lang); 03738 if (!res) 03739 res = ast_waitstream(chan, ints); 03740 return res; 03741 } 03742 03743 03744 int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, char *lang) 03745 { 03746 if (!strcasecmp(lang, "en") ) { /* English syntax */ 03747 return(ast_say_datetime_from_now_en(chan, t, ints, lang)); 03748 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 03749 return(ast_say_datetime_from_now_pt(chan, t, ints, lang)); 03750 } 03751 03752 /* Default to English */ 03753 return(ast_say_datetime_from_now_en(chan, t, ints, lang)); 03754 } 03755 03756 /* English syntax */ 03757 int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, char *ints, char *lang) 03758 { 03759 int res=0; 03760 time_t nowt; 03761 int daydiff; 03762 struct tm tm; 03763 struct tm now; 03764 char fn[256]; 03765 03766 time(&nowt); 03767 03768 localtime_r(&t,&tm); 03769 localtime_r(&nowt,&now); 03770 daydiff = now.tm_yday - tm.tm_yday; 03771 if ((daydiff < 0) || (daydiff > 6)) { 03772 /* Day of month and month */ 03773 if (!res) { 03774 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03775 res = ast_streamfile(chan, fn, lang); 03776 if (!res) 03777 res = ast_waitstream(chan, ints); 03778 } 03779 if (!res) 03780 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03781 03782 } else if (daydiff) { 03783 /* Just what day of the week */ 03784 if (!res) { 03785 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03786 res = ast_streamfile(chan, fn, lang); 03787 if (!res) 03788 res = ast_waitstream(chan, ints); 03789 } 03790 } /* Otherwise, it was today */ 03791 if (!res) 03792 res = ast_say_time(chan, t, ints, lang); 03793 return res; 03794 } 03795 03796 /* Portuguese syntax */ 03797 int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) 03798 { 03799 int res=0; 03800 time_t nowt; 03801 int daydiff; 03802 struct tm tm; 03803 struct tm now; 03804 char fn[256]; 03805 03806 time(&nowt); 03807 03808 localtime_r(&t,&tm); 03809 localtime_r(&nowt,&now); 03810 daydiff = now.tm_yday - tm.tm_yday; 03811 if ((daydiff < 0) || (daydiff > 6)) { 03812 /* Day of month and month */ 03813 if (!res) 03814 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03815 if (!res) 03816 res = wait_file(chan, ints, "digits/pt-de", lang); 03817 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03818 if (!res) 03819 res = wait_file(chan, ints, fn, lang); 03820 03821 } else if (daydiff) { 03822 /* Just what day of the week */ 03823 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03824 if (!res) 03825 res = wait_file(chan, ints, fn, lang); 03826 } /* Otherwise, it was today */ 03827 snprintf(fn, sizeof(fn), "digits/pt-ah"); 03828 if (!res) 03829 res = wait_file(chan, ints, fn, lang); 03830 if (tm.tm_hour != 1) 03831 if (!res) 03832 res = wait_file(chan, ints, "digits/pt-sss", lang); 03833 if (!res) 03834 res = ast_say_time(chan, t, ints, lang); 03835 return res; 03836 }

Generated on Fri Sep 24 21:03:48 2004 for Asterisk by doxygen 1.3.8