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

Generated on Tue Aug 17 16:13:54 2004 for Asterisk by doxygen 1.3.8