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 snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile); 01840 res = wait_file(chan,ints,nextmsg,lang); 01841 break; 01842 case 'A': 01843 case 'a': 01844 /* Sunday - Saturday */ 01845 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 01846 res = wait_file(chan,ints,nextmsg,lang); 01847 break; 01848 case 'B': 01849 case 'b': 01850 case 'h': 01851 /* January - December */ 01852 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 01853 res = wait_file(chan,ints,nextmsg,lang); 01854 break; 01855 case 'd': 01856 case 'e': 01857 /* First - Thirtyfirst */ 01858 if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) { 01859 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 01860 res = wait_file(chan,ints,nextmsg,lang); 01861 } else if (tm.tm_mday == 31) { 01862 /* "Thirty" and "first" */ 01863 res = wait_file(chan,ints, "digits/30",lang); 01864 if (!res) { 01865 res = wait_file(chan,ints, "digits/h-1",lang); 01866 } 01867 } else { 01868 /* Between 21 and 29 - two sounds */ 01869 res = wait_file(chan,ints, "digits/20",lang); 01870 if (!res) { 01871 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20); 01872 res = wait_file(chan,ints,nextmsg,lang); 01873 } 01874 } 01875 break; 01876 case 'Y': 01877 /* Year */ 01878 if (tm.tm_year > 99) { 01879 res = wait_file(chan,ints, "digits/2",lang); 01880 if (!res) { 01881 res = wait_file(chan,ints, "digits/thousand",lang); 01882 } 01883 if (tm.tm_year > 100) { 01884 if (!res) { 01885 /* This works until the end of 2020 */ 01886 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); 01887 res = wait_file(chan,ints,nextmsg,lang); 01888 } 01889 } 01890 } else { 01891 if (tm.tm_year < 1) { 01892 /* I'm not going to handle 1900 and prior */ 01893 /* We'll just be silent on the year, instead of bombing out. */ 01894 } else { 01895 res = wait_file(chan,ints, "digits/19",lang); 01896 if (!res) { 01897 if (tm.tm_year <= 9) { 01898 /* 1901 - 1909 */ 01899 res = wait_file(chan,ints, "digits/oh",lang); 01900 if (!res) { 01901 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 01902 res = wait_file(chan,ints,nextmsg,lang); 01903 } 01904 } else if (tm.tm_year <= 20) { 01905 /* 1910 - 1920 */ 01906 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 01907 res = wait_file(chan,ints,nextmsg,lang); 01908 } else { 01909 /* 1921 - 1999 */ 01910 int ten, one; 01911 ten = tm.tm_year / 10; 01912 one = tm.tm_year % 10; 01913 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); 01914 res = wait_file(chan,ints,nextmsg,lang); 01915 if (!res) { 01916 if (one != 0) { 01917 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 01918 res = wait_file(chan,ints,nextmsg,lang); 01919 } 01920 } 01921 } 01922 } 01923 } 01924 } 01925 break; 01926 case 'I': 01927 case 'l': 01928 /* 12-Hour */ 01929 if (tm.tm_hour == 0) 01930 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 01931 else if (tm.tm_hour > 12) 01932 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 01933 else 01934 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 01935 res = wait_file(chan,ints,nextmsg,lang); 01936 break; 01937 case 'H': 01938 case 'k': 01939 /* 24-Hour */ 01940 if (format[offset] == 'H') { 01941 /* e.g. oh-eight */ 01942 if (tm.tm_hour < 10) { 01943 res = wait_file(chan,ints, "digits/oh",lang); 01944 } 01945 } else { 01946 /* e.g. eight */ 01947 if (tm.tm_hour == 0) { 01948 res = wait_file(chan,ints, "digits/oh",lang); 01949 } 01950 } 01951 if (!res) { 01952 if (tm.tm_hour != 0) { 01953 int remainder = tm.tm_hour; 01954 if (tm.tm_hour > 20) { 01955 res = wait_file(chan,ints, "digits/20",lang); 01956 remainder -= 20; 01957 } 01958 if (!res) { 01959 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 01960 res = wait_file(chan,ints,nextmsg,lang); 01961 } 01962 } 01963 } 01964 break; 01965 case 'M': 01966 /* Minute */ 01967 if (tm.tm_min == 0) { 01968 res = wait_file(chan,ints, "digits/oclock",lang); 01969 } else if (tm.tm_min < 10) { 01970 res = wait_file(chan,ints, "digits/oh",lang); 01971 if (!res) { 01972 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 01973 res = wait_file(chan,ints,nextmsg,lang); 01974 } 01975 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) { 01976 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 01977 res = wait_file(chan,ints,nextmsg,lang); 01978 } else { 01979 int ten, one; 01980 ten = (tm.tm_min / 10) * 10; 01981 one = (tm.tm_min % 10); 01982 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 01983 res = wait_file(chan,ints,nextmsg,lang); 01984 if (!res) { 01985 /* Fifty, not fifty-zero */ 01986 if (one != 0) { 01987 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 01988 res = wait_file(chan,ints,nextmsg,lang); 01989 } 01990 } 01991 } 01992 break; 01993 case 'P': 01994 case 'p': 01995 /* AM/PM */ 01996 if (tm.tm_hour > 11) 01997 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 01998 else 01999 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 02000 res = wait_file(chan,ints,nextmsg,lang); 02001 break; 02002 case 'Q': 02003 /* Shorthand for "Today", "Yesterday", or ABdY */ 02004 { 02005 struct timeval now; 02006 struct tm tmnow; 02007 time_t beg_today; 02008 02009 gettimeofday(&now,NULL); 02010 ast_localtime(&now.tv_sec,&tmnow,timezone); 02011 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02012 /* In any case, it saves not having to do ast_mktime() */ 02013 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02014 if (beg_today < time) { 02015 /* Today */ 02016 res = wait_file(chan,ints, "digits/today",lang); 02017 } else if (beg_today - 86400 < time) { 02018 /* Yesterday */ 02019 res = wait_file(chan,ints, "digits/yesterday",lang); 02020 } else { 02021 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02022 } 02023 } 02024 break; 02025 case 'q': 02026 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02027 { 02028 struct timeval now; 02029 struct tm tmnow; 02030 time_t beg_today; 02031 02032 gettimeofday(&now,NULL); 02033 ast_localtime(&now.tv_sec,&tmnow,timezone); 02034 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02035 /* In any case, it saves not having to do ast_mktime() */ 02036 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02037 if (beg_today < time) { 02038 /* Today */ 02039 } else if ((beg_today - 86400) < time) { 02040 /* Yesterday */ 02041 res = wait_file(chan,ints, "digits/yesterday",lang); 02042 } else if (beg_today - 86400 * 6 < time) { 02043 /* Within the last week */ 02044 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02045 } else { 02046 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02047 } 02048 } 02049 break; 02050 case 'R': 02051 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); 02052 break; 02053 case 'S': 02054 /* Seconds */ 02055 if (tm.tm_sec == 0) { 02056 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02057 res = wait_file(chan,ints,nextmsg,lang); 02058 } else if (tm.tm_sec < 10) { 02059 res = wait_file(chan,ints, "digits/oh",lang); 02060 if (!res) { 02061 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02062 res = wait_file(chan,ints,nextmsg,lang); 02063 } 02064 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02065 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02066 res = wait_file(chan,ints,nextmsg,lang); 02067 } else { 02068 int ten, one; 02069 ten = (tm.tm_sec / 10) * 10; 02070 one = (tm.tm_sec % 10); 02071 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02072 res = wait_file(chan,ints,nextmsg,lang); 02073 if (!res) { 02074 /* Fifty, not fifty-zero */ 02075 if (one != 0) { 02076 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02077 res = wait_file(chan,ints,nextmsg,lang); 02078 } 02079 } 02080 } 02081 break; 02082 case 'T': 02083 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02084 break; 02085 case ' ': 02086 case ' ': 02087 /* Just ignore spaces and tabs */ 02088 break; 02089 default: 02090 /* Unknown character */ 02091 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02092 } 02093 /* Jump out on DTMF */ 02094 if (res) { 02095 break; 02096 } 02097 } 02098 return res; 02099 } 02100 02101 /* German syntax */ 02102 /* NB This currently is a 100% clone of the English syntax, just getting ready to make changes... */ 02103 int ast_say_date_with_format_de(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02104 { 02105 struct tm tm; 02106 int res=0, offset, sndoffset; 02107 char sndfile[256], nextmsg[256]; 02108 02109 ast_localtime(&time,&tm,timezone); 02110 02111 for (offset=0 ; format[offset] != '\0' ; offset++) { 02112 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02113 switch (format[offset]) { 02114 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02115 case '\'': 02116 /* Literal name of a sound file */ 02117 sndoffset=0; 02118 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02119 sndfile[sndoffset] = format[offset]; 02120 sndfile[sndoffset] = '\0'; 02121 snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile); 02122 res = wait_file(chan,ints,nextmsg,lang); 02123 break; 02124 case 'A': 02125 case 'a': 02126 /* Sunday - Saturday */ 02127 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 02128 res = wait_file(chan,ints,nextmsg,lang); 02129 break; 02130 case 'B': 02131 case 'b': 02132 case 'h': 02133 /* January - December */ 02134 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 02135 res = wait_file(chan,ints,nextmsg,lang); 02136 break; 02137 case 'd': 02138 case 'e': 02139 /* First - Thirtyfirst */ 02140 if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) { 02141 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 02142 res = wait_file(chan,ints,nextmsg,lang); 02143 } else if (tm.tm_mday == 31) { 02144 /* "Thirty" and "first" */ 02145 res = wait_file(chan,ints, "digits/30",lang); 02146 if (!res) { 02147 res = wait_file(chan,ints, "digits/h-1",lang); 02148 } 02149 } else { 02150 /* Between 21 and 29 - two sounds */ 02151 res = wait_file(chan,ints, "digits/20",lang); 02152 if (!res) { 02153 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20); 02154 res = wait_file(chan,ints,nextmsg,lang); 02155 } 02156 } 02157 break; 02158 case 'Y': 02159 /* Year */ 02160 if (tm.tm_year > 99) { 02161 res = wait_file(chan,ints, "digits/2",lang); 02162 if (!res) { 02163 res = wait_file(chan,ints, "digits/thousand",lang); 02164 } 02165 if (tm.tm_year > 100) { 02166 if (!res) { 02167 /* This works until the end of 2020 */ 02168 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); 02169 res = wait_file(chan,ints,nextmsg,lang); 02170 } 02171 } 02172 } else { 02173 if (tm.tm_year < 1) { 02174 /* I'm not going to handle 1900 and prior */ 02175 /* We'll just be silent on the year, instead of bombing out. */ 02176 } else { 02177 res = wait_file(chan,ints, "digits/19",lang); 02178 if (!res) { 02179 if (tm.tm_year <= 9) { 02180 /* 1901 - 1909 */ 02181 res = wait_file(chan,ints, "digits/oh",lang); 02182 if (!res) { 02183 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02184 res = wait_file(chan,ints,nextmsg,lang); 02185 } 02186 } else if (tm.tm_year <= 20) { 02187 /* 1910 - 1920 */ 02188 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02189 res = wait_file(chan,ints,nextmsg,lang); 02190 } else { 02191 /* 1921 - 1999 */ 02192 int ten, one; 02193 ten = tm.tm_year / 10; 02194 one = tm.tm_year % 10; 02195 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); 02196 res = wait_file(chan,ints,nextmsg,lang); 02197 if (!res) { 02198 if (one != 0) { 02199 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02200 res = wait_file(chan,ints,nextmsg,lang); 02201 } 02202 } 02203 } 02204 } 02205 } 02206 } 02207 break; 02208 case 'I': 02209 case 'l': 02210 /* 12-Hour */ 02211 if (tm.tm_hour == 0) 02212 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 02213 else if (tm.tm_hour > 12) 02214 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 02215 else 02216 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 02217 res = wait_file(chan,ints,nextmsg,lang); 02218 break; 02219 case 'H': 02220 case 'k': 02221 /* 24-Hour */ 02222 if (format[offset] == 'H') { 02223 /* e.g. oh-eight */ 02224 if (tm.tm_hour < 10) { 02225 res = wait_file(chan,ints, "digits/oh",lang); 02226 } 02227 } else { 02228 /* e.g. eight */ 02229 if (tm.tm_hour == 0) { 02230 res = wait_file(chan,ints, "digits/oh",lang); 02231 } 02232 } 02233 if (!res) { 02234 if (tm.tm_hour != 0) { 02235 int remainder = tm.tm_hour; 02236 if (tm.tm_hour > 20) { 02237 res = wait_file(chan,ints, "digits/20",lang); 02238 remainder -= 20; 02239 } 02240 if (!res) { 02241 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 02242 res = wait_file(chan,ints,nextmsg,lang); 02243 } 02244 } 02245 } 02246 break; 02247 case 'M': 02248 /* Minute */ 02249 if (tm.tm_min == 0) { 02250 res = wait_file(chan,ints, "digits/oclock",lang); 02251 } else if (tm.tm_min < 10) { 02252 res = wait_file(chan,ints, "digits/oh",lang); 02253 if (!res) { 02254 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 02255 res = wait_file(chan,ints,nextmsg,lang); 02256 } 02257 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) { 02258 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 02259 res = wait_file(chan,ints,nextmsg,lang); 02260 } else { 02261 int ten, one; 02262 ten = (tm.tm_min / 10) * 10; 02263 one = (tm.tm_min % 10); 02264 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02265 res = wait_file(chan,ints,nextmsg,lang); 02266 if (!res) { 02267 /* Fifty, not fifty-zero */ 02268 if (one != 0) { 02269 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02270 res = wait_file(chan,ints,nextmsg,lang); 02271 } 02272 } 02273 } 02274 break; 02275 case 'P': 02276 case 'p': 02277 /* AM/PM */ 02278 if (tm.tm_hour > 11) 02279 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 02280 else 02281 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 02282 res = wait_file(chan,ints,nextmsg,lang); 02283 break; 02284 case 'Q': 02285 /* Shorthand for "Today", "Yesterday", or ABdY */ 02286 { 02287 struct timeval now; 02288 struct tm tmnow; 02289 time_t beg_today; 02290 02291 gettimeofday(&now,NULL); 02292 ast_localtime(&now.tv_sec,&tmnow,timezone); 02293 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02294 /* In any case, it saves not having to do ast_mktime() */ 02295 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02296 if (beg_today < time) { 02297 /* Today */ 02298 res = wait_file(chan,ints, "digits/today",lang); 02299 } else if (beg_today - 86400 < time) { 02300 /* Yesterday */ 02301 res = wait_file(chan,ints, "digits/yesterday",lang); 02302 } else { 02303 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02304 } 02305 } 02306 break; 02307 case 'q': 02308 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02309 { 02310 struct timeval now; 02311 struct tm tmnow; 02312 time_t beg_today; 02313 02314 gettimeofday(&now,NULL); 02315 ast_localtime(&now.tv_sec,&tmnow,timezone); 02316 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02317 /* In any case, it saves not having to do ast_mktime() */ 02318 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02319 if (beg_today < time) { 02320 /* Today */ 02321 } else if ((beg_today - 86400) < time) { 02322 /* Yesterday */ 02323 res = wait_file(chan,ints, "digits/yesterday",lang); 02324 } else if (beg_today - 86400 * 6 < time) { 02325 /* Within the last week */ 02326 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02327 } else { 02328 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02329 } 02330 } 02331 break; 02332 case 'R': 02333 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); 02334 break; 02335 case 'S': 02336 /* Seconds */ 02337 if (tm.tm_sec == 0) { 02338 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02339 res = wait_file(chan,ints,nextmsg,lang); 02340 } else if (tm.tm_sec < 10) { 02341 res = wait_file(chan,ints, "digits/oh",lang); 02342 if (!res) { 02343 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02344 res = wait_file(chan,ints,nextmsg,lang); 02345 } 02346 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02347 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02348 res = wait_file(chan,ints,nextmsg,lang); 02349 } else { 02350 int ten, one; 02351 ten = (tm.tm_sec / 10) * 10; 02352 one = (tm.tm_sec % 10); 02353 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02354 res = wait_file(chan,ints,nextmsg,lang); 02355 if (!res) { 02356 /* Fifty, not fifty-zero */ 02357 if (one != 0) { 02358 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02359 res = wait_file(chan,ints,nextmsg,lang); 02360 } 02361 } 02362 } 02363 break; 02364 case 'T': 02365 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02366 break; 02367 case ' ': 02368 case ' ': 02369 /* Just ignore spaces and tabs */ 02370 break; 02371 default: 02372 /* Unknown character */ 02373 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02374 } 02375 /* Jump out on DTMF */ 02376 if (res) { 02377 break; 02378 } 02379 } 02380 return res; 02381 } 02382 02383 /* Spanish syntax */ 02384 int ast_say_date_with_format_es(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02385 { 02386 struct tm tm; 02387 int res=0, offset, sndoffset; 02388 char sndfile[256], nextmsg[256]; 02389 02390 ast_localtime(&time,&tm,timezone); 02391 02392 for (offset=0 ; format[offset] != '\0' ; offset++) { 02393 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02394 switch (format[offset]) { 02395 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02396 case '\'': 02397 /* Literal name of a sound file */ 02398 sndoffset=0; 02399 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02400 sndfile[sndoffset] = format[offset]; 02401 sndfile[sndoffset] = '\0'; 02402 snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile); 02403 res = wait_file(chan,ints,nextmsg,lang); 02404 break; 02405 case 'A': 02406 case 'a': 02407 /* Sunday - Saturday */ 02408 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 02409 res = wait_file(chan,ints,nextmsg,lang); 02410 break; 02411 case 'B': 02412 case 'b': 02413 case 'h': 02414 /* January - December */ 02415 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 02416 res = wait_file(chan,ints,nextmsg,lang); 02417 break; 02418 case 'd': 02419 case 'e': 02420 /* First - Thirtyfirst */ 02421 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 02422 break; 02423 case 'Y': 02424 /* Year */ 02425 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 02426 break; 02427 case 'I': 02428 case 'l': 02429 /* 12-Hour */ 02430 if (tm.tm_hour == 0) 02431 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 02432 else if (tm.tm_hour > 12) 02433 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 02434 else 02435 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 02436 res = wait_file(chan,ints,nextmsg,lang); 02437 break; 02438 case 'H': 02439 case 'k': 02440 /* 24-Hour */ 02441 res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL); 02442 if (!res) { 02443 if (tm.tm_hour != 0) { 02444 int remainder = tm.tm_hour; 02445 if (tm.tm_hour > 20) { 02446 res = wait_file(chan,ints, "digits/20",lang); 02447 remainder -= 20; 02448 } 02449 if (!res) { 02450 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 02451 res = wait_file(chan,ints,nextmsg,lang); 02452 } 02453 } 02454 } 02455 break; 02456 case 'M': 02457 /* Minute */ 02458 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 02459 break; 02460 case 'P': 02461 case 'p': 02462 /* AM/PM */ 02463 if (tm.tm_hour > 12) 02464 res = wait_file(chan, ints, "digits/p-m", lang); 02465 else if (tm.tm_hour && tm.tm_hour < 12) 02466 res = wait_file(chan, ints, "digits/a-m", lang); 02467 break; 02468 case 'Q': 02469 /* Shorthand for "Today", "Yesterday", or ABdY */ 02470 { 02471 struct timeval now; 02472 struct tm tmnow; 02473 time_t beg_today; 02474 02475 gettimeofday(&now,NULL); 02476 ast_localtime(&now.tv_sec,&tmnow,timezone); 02477 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02478 /* In any case, it saves not having to do ast_mktime() */ 02479 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02480 if (beg_today < time) { 02481 /* Today */ 02482 res = wait_file(chan,ints, "digits/today",lang); 02483 } else if (beg_today - 86400 < time) { 02484 /* Yesterday */ 02485 res = wait_file(chan,ints, "digits/yesterday",lang); 02486 } else { 02487 res = ast_say_date_with_format(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone); 02488 } 02489 } 02490 break; 02491 case 'q': 02492 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02493 { 02494 struct timeval now; 02495 struct tm tmnow; 02496 time_t beg_today; 02497 02498 gettimeofday(&now,NULL); 02499 ast_localtime(&now.tv_sec,&tmnow,timezone); 02500 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02501 /* In any case, it saves not having to do ast_mktime() */ 02502 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02503 if (beg_today < time) { 02504 /* Today */ 02505 res = wait_file(chan,ints, "digits/today",lang); 02506 } else if ((beg_today - 86400) < time) { 02507 /* Yesterday */ 02508 res = wait_file(chan,ints, "digits/yesterday",lang); 02509 } else if (beg_today - 86400 * 6 < time) { 02510 /* Within the last week */ 02511 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02512 } else { 02513 res = ast_say_date_with_format(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone); 02514 } 02515 } 02516 break; 02517 case 'R': 02518 res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/y' M", timezone); 02519 break; 02520 case 'S': 02521 /* Seconds */ 02522 if (tm.tm_sec == 0) { 02523 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02524 res = wait_file(chan,ints,nextmsg,lang); 02525 } else if (tm.tm_sec < 10) { 02526 res = wait_file(chan,ints, "digits/oh",lang); 02527 if (!res) { 02528 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02529 res = wait_file(chan,ints,nextmsg,lang); 02530 } 02531 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02532 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02533 res = wait_file(chan,ints,nextmsg,lang); 02534 } else { 02535 int ten, one; 02536 ten = (tm.tm_sec / 10) * 10; 02537 one = (tm.tm_sec % 10); 02538 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02539 res = wait_file(chan,ints,nextmsg,lang); 02540 if (!res) { 02541 /* Fifty, not fifty-zero */ 02542 if (one != 0) { 02543 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02544 res = wait_file(chan,ints,nextmsg,lang); 02545 } 02546 } 02547 } 02548 break; 02549 case 'T': 02550 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02551 break; 02552 case ' ': 02553 case ' ': 02554 /* Just ignore spaces and tabs */ 02555 break; 02556 default: 02557 /* Unknown character */ 02558 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02559 } 02560 /* Jump out on DTMF */ 02561 if (res) { 02562 break; 02563 } 02564 } 02565 return res; 02566 } 02567 02568 /* Dutch syntax */ 02569 int ast_say_date_with_format_nl(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02570 { 02571 struct tm tm; 02572 int res=0, offset, sndoffset; 02573 char sndfile[256], nextmsg[256]; 02574 02575 ast_localtime(&time,&tm,timezone); 02576 02577 for (offset=0 ; format[offset] != '\0' ; offset++) { 02578 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02579 switch (format[offset]) { 02580 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02581 case '\'': 02582 /* Literal name of a sound file */ 02583 sndoffset=0; 02584 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02585 sndfile[sndoffset] = format[offset]; 02586 sndfile[sndoffset] = '\0'; 02587 snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile); 02588 res = wait_file(chan,ints,nextmsg,lang); 02589 break; 02590 case 'A': 02591 case 'a': 02592 /* Sunday - Saturday */ 02593 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 02594 res = wait_file(chan,ints,nextmsg,lang); 02595 break; 02596 case 'B': 02597 case 'b': 02598 case 'h': 02599 /* January - December */ 02600 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 02601 res = wait_file(chan,ints,nextmsg,lang); 02602 break; 02603 case 'd': 02604 case 'e': 02605 /* First - Thirtyfirst */ 02606 res = ast_say_number(chan, tm.tm_mday, ints, lang, NULL); 02607 break; 02608 case 'Y': 02609 /* Year */ 02610 if (tm.tm_year > 99) { 02611 res = wait_file(chan,ints, "digits/2",lang); 02612 if (!res) { 02613 res = wait_file(chan,ints, "digits/thousand",lang); 02614 } 02615 if (tm.tm_year > 100) { 02616 if (!res) { 02617 /* This works until the end of 2020 */ 02618 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100); 02619 res = wait_file(chan,ints,nextmsg,lang); 02620 } 02621 } 02622 } else { 02623 if (tm.tm_year < 1) { 02624 /* I'm not going to handle 1900 and prior */ 02625 /* We'll just be silent on the year, instead of bombing out. */ 02626 } else { 02627 res = wait_file(chan,ints, "digits/19",lang); 02628 if (!res) { 02629 if (tm.tm_year <= 9) { 02630 /* 1901 - 1909 */ 02631 res = wait_file(chan,ints, "digits/oh",lang); 02632 if (!res) { 02633 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02634 res = wait_file(chan,ints,nextmsg,lang); 02635 } 02636 } else if (tm.tm_year <= 20) { 02637 /* 1910 - 1920 */ 02638 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 02639 res = wait_file(chan,ints,nextmsg,lang); 02640 } else { 02641 /* 1921 - 1999 */ 02642 int ten, one; 02643 ten = tm.tm_year / 10; 02644 one = tm.tm_year % 10; 02645 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10); 02646 res = wait_file(chan,ints,nextmsg,lang); 02647 if (!res) { 02648 if (one != 0) { 02649 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02650 res = wait_file(chan,ints,nextmsg,lang); 02651 } 02652 } 02653 } 02654 } 02655 } 02656 } 02657 break; 02658 case 'I': 02659 case 'l': 02660 /* 12-Hour */ 02661 if (tm.tm_hour == 0) 02662 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 02663 else if (tm.tm_hour > 12) 02664 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 02665 else 02666 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 02667 res = wait_file(chan,ints,nextmsg,lang); 02668 break; 02669 case 'H': 02670 case 'k': 02671 /* 24-Hour */ 02672 res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL); 02673 if (!res) { 02674 res = wait_file(chan,ints, "digits/nl-uur",lang); 02675 } 02676 break; 02677 case 'M': 02678 /* Minute */ 02679 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 02680 break; 02681 case 'P': 02682 case 'p': 02683 /* AM/PM */ 02684 if (tm.tm_hour > 11) 02685 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 02686 else 02687 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 02688 res = wait_file(chan,ints,nextmsg,lang); 02689 break; 02690 case 'Q': 02691 /* Shorthand for "Today", "Yesterday", or ABdY */ 02692 { 02693 struct timeval now; 02694 struct tm tmnow; 02695 time_t beg_today; 02696 02697 gettimeofday(&now,NULL); 02698 ast_localtime(&now.tv_sec,&tmnow,timezone); 02699 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02700 /* In any case, it saves not having to do ast_mktime() */ 02701 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02702 if (beg_today < time) { 02703 /* Today */ 02704 res = wait_file(chan,ints, "digits/today",lang); 02705 } else if (beg_today - 86400 < time) { 02706 /* Yesterday */ 02707 res = wait_file(chan,ints, "digits/yesterday",lang); 02708 } else { 02709 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02710 } 02711 } 02712 break; 02713 case 'q': 02714 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02715 { 02716 struct timeval now; 02717 struct tm tmnow; 02718 time_t beg_today; 02719 02720 gettimeofday(&now,NULL); 02721 ast_localtime(&now.tv_sec,&tmnow,timezone); 02722 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02723 /* In any case, it saves not having to do ast_mktime() */ 02724 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02725 if (beg_today < time) { 02726 /* Today */ 02727 } else if ((beg_today - 86400) < time) { 02728 /* Yesterday */ 02729 res = wait_file(chan,ints, "digits/yesterday",lang); 02730 } else if (beg_today - 86400 * 6 < time) { 02731 /* Within the last week */ 02732 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02733 } else { 02734 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone); 02735 } 02736 } 02737 break; 02738 case 'R': 02739 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); 02740 break; 02741 case 'S': 02742 /* Seconds */ 02743 if (tm.tm_sec == 0) { 02744 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02745 res = wait_file(chan,ints,nextmsg,lang); 02746 } else if (tm.tm_sec < 10) { 02747 res = wait_file(chan,ints, "digits/oh",lang); 02748 if (!res) { 02749 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02750 res = wait_file(chan,ints,nextmsg,lang); 02751 } 02752 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02753 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02754 res = wait_file(chan,ints,nextmsg,lang); 02755 } else { 02756 int ten, one; 02757 ten = (tm.tm_sec / 10) * 10; 02758 one = (tm.tm_sec % 10); 02759 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02760 res = wait_file(chan,ints,nextmsg,lang); 02761 if (!res) { 02762 /* Fifty, not fifty-zero */ 02763 if (one != 0) { 02764 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02765 res = wait_file(chan,ints,nextmsg,lang); 02766 } 02767 } 02768 } 02769 break; 02770 case 'T': 02771 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02772 break; 02773 case ' ': 02774 case ' ': 02775 /* Just ignore spaces and tabs */ 02776 break; 02777 default: 02778 /* Unknown character */ 02779 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02780 } 02781 /* Jump out on DTMF */ 02782 if (res) { 02783 break; 02784 } 02785 } 02786 return res; 02787 } 02788 02789 /* Portuguese syntax */ 02790 int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02791 { 02792 struct tm tm; 02793 int res=0, offset, sndoffset; 02794 char sndfile[256], nextmsg[256]; 02795 02796 ast_localtime(&time,&tm,timezone); 02797 02798 for (offset=0 ; format[offset] != '\0' ; offset++) { 02799 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 02800 switch (format[offset]) { 02801 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 02802 case '\'': 02803 /* Literal name of a sound file */ 02804 sndoffset=0; 02805 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 02806 sndfile[sndoffset] = format[offset]; 02807 sndfile[sndoffset] = '\0'; 02808 snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile); 02809 res = wait_file(chan,ints,nextmsg,lang); 02810 break; 02811 case 'A': 02812 case 'a': 02813 /* Sunday - Saturday */ 02814 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 02815 res = wait_file(chan,ints,nextmsg,lang); 02816 break; 02817 case 'B': 02818 case 'b': 02819 case 'h': 02820 /* January - December */ 02821 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 02822 res = wait_file(chan,ints,nextmsg,lang); 02823 break; 02824 case 'd': 02825 case 'e': 02826 /* First - Thirtyfirst */ 02827 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 02828 break; 02829 case 'Y': 02830 /* Year */ 02831 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 02832 break; 02833 case 'I': 02834 case 'l': 02835 /* 12-Hour */ 02836 if (tm.tm_hour == 0) { 02837 if (format[offset] == 'I') 02838 res = wait_file(chan, ints, "digits/pt-ah", lang); 02839 if (!res) 02840 res = wait_file(chan, ints, "digits/pt-meianoite", lang); 02841 } 02842 else if (tm.tm_hour == 12) { 02843 if (format[offset] == 'I') 02844 res = wait_file(chan, ints, "digits/pt-ao", lang); 02845 if (!res) 02846 res = wait_file(chan, ints, "digits/pt-meiodia", lang); 02847 } 02848 else { 02849 if (format[offset] == 'I') { 02850 res = wait_file(chan, ints, "digits/pt-ah", lang); 02851 if ((tm.tm_hour % 12) != 1) 02852 if (!res) 02853 res = wait_file(chan, ints, "digits/pt-sss", lang); 02854 } 02855 if (!res) 02856 res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f"); 02857 } 02858 break; 02859 case 'H': 02860 case 'k': 02861 /* 24-Hour */ 02862 res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL); 02863 if (!res) { 02864 if (tm.tm_hour != 0) { 02865 int remainder = tm.tm_hour; 02866 if (tm.tm_hour > 20) { 02867 res = wait_file(chan,ints, "digits/20",lang); 02868 remainder -= 20; 02869 } 02870 if (!res) { 02871 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder); 02872 res = wait_file(chan,ints,nextmsg,lang); 02873 } 02874 } 02875 } 02876 break; 02877 case 'M': 02878 /* Minute */ 02879 if (tm.tm_min == 0) { 02880 res = wait_file(chan, ints, "digits/pt-hora", lang); 02881 if (tm.tm_hour != 1) 02882 if (!res) 02883 res = wait_file(chan, ints, "digits/pt-sss", lang); } else { 02884 res = wait_file(chan,ints,"digits/pt-e",lang); 02885 if (!res) 02886 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 02887 } 02888 break; 02889 case 'P': 02890 case 'p': 02891 /* AM/PM */ 02892 if (tm.tm_hour > 12) 02893 res = wait_file(chan, ints, "digits/p-m", lang); 02894 else if (tm.tm_hour && tm.tm_hour < 12) 02895 res = wait_file(chan, ints, "digits/a-m", lang); 02896 break; 02897 case 'Q': 02898 /* Shorthand for "Today", "Yesterday", or ABdY */ 02899 { 02900 struct timeval now; 02901 struct tm tmnow; 02902 time_t beg_today; 02903 02904 gettimeofday(&now,NULL); 02905 ast_localtime(&now.tv_sec,&tmnow,timezone); 02906 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02907 /* In any case, it saves not having to do ast_mktime() */ 02908 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02909 if (beg_today < time) { 02910 /* Today */ 02911 res = wait_file(chan,ints, "digits/today",lang); 02912 } else if (beg_today - 86400 < time) { 02913 /* Yesterday */ 02914 res = wait_file(chan,ints, "digits/yesterday",lang); 02915 } else { 02916 res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone); 02917 } 02918 } 02919 break; 02920 case 'q': 02921 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 02922 { 02923 struct timeval now; 02924 struct tm tmnow; 02925 time_t beg_today; 02926 02927 gettimeofday(&now,NULL); 02928 ast_localtime(&now.tv_sec,&tmnow,timezone); 02929 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 02930 /* In any case, it saves not having to do ast_mktime() */ 02931 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 02932 if (beg_today < time) { 02933 /* Today */ 02934 } else if ((beg_today - 86400) < time) { 02935 /* Yesterday */ 02936 res = wait_file(chan,ints, "digits/yesterday",lang); 02937 } else if (beg_today - 86400 * 6 < time) { 02938 /* Within the last week */ 02939 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 02940 } else { 02941 res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone); 02942 } 02943 } 02944 break; 02945 case 'R': 02946 res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/pt-e' M", timezone); 02947 break; 02948 case 'S': 02949 /* Seconds */ 02950 if (tm.tm_sec == 0) { 02951 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02952 res = wait_file(chan,ints,nextmsg,lang); 02953 } else if (tm.tm_sec < 10) { 02954 res = wait_file(chan,ints, "digits/oh",lang); 02955 if (!res) { 02956 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02957 res = wait_file(chan,ints,nextmsg,lang); 02958 } 02959 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) { 02960 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 02961 res = wait_file(chan,ints,nextmsg,lang); 02962 } else { 02963 int ten, one; 02964 ten = (tm.tm_sec / 10) * 10; 02965 one = (tm.tm_sec % 10); 02966 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten); 02967 res = wait_file(chan,ints,nextmsg,lang); 02968 if (!res) { 02969 /* Fifty, not fifty-zero */ 02970 if (one != 0) { 02971 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one); 02972 res = wait_file(chan,ints,nextmsg,lang); 02973 } 02974 } 02975 } 02976 break; 02977 case 'T': 02978 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 02979 break; 02980 case ' ': 02981 case ' ': 02982 /* Just ignore spaces and tabs */ 02983 break; 02984 default: 02985 /* Unknown character */ 02986 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 02987 } 02988 /* Jump out on DTMF */ 02989 if (res) { 02990 break; 02991 } 02992 } 02993 return res; 02994 } 02995 02996 /* Taiwanese syntax */ 02997 int ast_say_date_with_format_tw(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone) 02998 { 02999 struct tm tm; 03000 int res=0, offset, sndoffset; 03001 char sndfile[256], nextmsg[256]; 03002 03003 ast_localtime(&time,&tm,timezone); 03004 03005 for (offset=0 ; format[offset] != '\0' ; offset++) { 03006 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format); 03007 switch (format[offset]) { 03008 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */ 03009 case '\'': 03010 /* Literal name of a sound file */ 03011 sndoffset=0; 03012 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++) 03013 sndfile[sndoffset] = format[offset]; 03014 sndfile[sndoffset] = '\0'; 03015 snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile); 03016 res = wait_file(chan,ints,nextmsg,lang); 03017 break; 03018 case 'A': 03019 case 'a': 03020 /* Sunday - Saturday */ 03021 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday); 03022 res = wait_file(chan,ints,nextmsg,lang); 03023 break; 03024 case 'B': 03025 case 'b': 03026 case 'h': 03027 /* January - December */ 03028 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon); 03029 res = wait_file(chan,ints,nextmsg,lang); 03030 break; 03031 case 'd': 03032 case 'e': 03033 /* First - Thirtyfirst */ 03034 if (!(tm.tm_mday % 10) || (tm.tm_mday < 10)) { 03035 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday); 03036 res = wait_file(chan,ints,nextmsg,lang); 03037 } else { 03038 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%dh", tm.tm_mday - (tm.tm_mday % 10)); 03039 res = wait_file(chan,ints,nextmsg,lang); 03040 if(!res) { 03041 snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday % 10); 03042 res = wait_file(chan,ints,nextmsg,lang); 03043 } 03044 } 03045 break; 03046 case 'Y': 03047 /* Year */ 03048 if (tm.tm_year > 99) { 03049 res = wait_file(chan,ints, "digits/2",lang); 03050 if (!res) { 03051 res = wait_file(chan,ints, "digits/thousand",lang); 03052 } 03053 if (tm.tm_year > 100) { 03054 if (!res) { 03055 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (tm.tm_year - 100) / 10); 03056 res = wait_file(chan,ints,nextmsg,lang); 03057 if (!res) { 03058 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (tm.tm_year - 100) % 10); 03059 res = wait_file(chan,ints,nextmsg,lang); 03060 } 03061 } 03062 } 03063 if (!res) { 03064 res = wait_file(chan,ints, "digits/year",lang); 03065 } 03066 } else { 03067 if (tm.tm_year < 1) { 03068 /* I'm not going to handle 1900 and prior */ 03069 /* We'll just be silent on the year, instead of bombing out. */ 03070 } else { 03071 res = wait_file(chan,ints, "digits/1",lang); 03072 if (!res) { 03073 res = wait_file(chan,ints, "digits/9",lang); 03074 } 03075 if (!res) { 03076 if (tm.tm_year <= 9) { 03077 /* 1901 - 1909 */ 03078 res = wait_file(chan,ints, "digits/0",lang); 03079 if (!res) { 03080 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year); 03081 res = wait_file(chan,ints,nextmsg,lang); 03082 } 03083 } else { 03084 /* 1910 - 1999 */ 03085 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year / 10); 03086 res = wait_file(chan,ints,nextmsg,lang); 03087 if (!res) { 03088 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year % 10); 03089 res = wait_file(chan,ints,nextmsg,lang); 03090 } 03091 } 03092 } 03093 } 03094 if (!res) { 03095 res = wait_file(chan,ints, "digits/year",lang); 03096 } 03097 } 03098 break; 03099 case 'I': 03100 case 'l': 03101 /* 12-Hour */ 03102 if (tm.tm_hour == 0) 03103 snprintf(nextmsg,sizeof(nextmsg), "digits/12"); 03104 else if (tm.tm_hour > 12) 03105 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12); 03106 else 03107 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 03108 res = wait_file(chan,ints,nextmsg,lang); 03109 if (!res) { 03110 res = wait_file(chan,ints, "digits/oclock",lang); 03111 } 03112 break; 03113 case 'H': 03114 case 'k': 03115 /* 24-Hour */ 03116 if (!(tm.tm_hour % 10) || tm.tm_hour < 10) { 03117 if (tm.tm_hour < 10) { 03118 res = wait_file(chan, ints, "digits/0", lang); 03119 } 03120 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour); 03121 res = wait_file(chan,ints,nextmsg,lang); 03122 } else { 03123 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - (tm.tm_hour % 10)); 03124 res = wait_file(chan,ints,nextmsg,lang); 03125 if (!res) { 03126 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour % 10); 03127 res = wait_file(chan,ints,nextmsg,lang); 03128 } 03129 } 03130 if (!res) { 03131 res = wait_file(chan,ints, "digits/oclock",lang); 03132 } 03133 break; 03134 case 'M': 03135 /* Minute */ 03136 if (!(tm.tm_min % 10) || tm.tm_min < 10) { 03137 if (tm.tm_min < 10) { 03138 res = wait_file(chan, ints, "digits/0", lang); 03139 } 03140 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min); 03141 res = wait_file(chan,ints,nextmsg,lang); 03142 } else { 03143 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min - (tm.tm_min % 10)); 03144 res = wait_file(chan,ints,nextmsg,lang); 03145 if (!res) { 03146 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min % 10); 03147 res = wait_file(chan,ints,nextmsg,lang); 03148 } 03149 } 03150 if (!res) { 03151 res = wait_file(chan,ints, "digits/minute",lang); 03152 } 03153 break; 03154 case 'P': 03155 case 'p': 03156 /* AM/PM */ 03157 if (tm.tm_hour > 11) 03158 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m"); 03159 else 03160 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m"); 03161 res = wait_file(chan,ints,nextmsg,lang); 03162 break; 03163 case 'Q': 03164 /* Shorthand for "Today", "Yesterday", or ABdY */ 03165 { 03166 struct timeval now; 03167 struct tm tmnow; 03168 time_t beg_today; 03169 03170 gettimeofday(&now,NULL); 03171 ast_localtime(&now.tv_sec,&tmnow,timezone); 03172 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03173 /* In any case, it saves not having to do ast_mktime() */ 03174 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03175 if (beg_today < time) { 03176 /* Today */ 03177 res = wait_file(chan,ints, "digits/today",lang); 03178 } else if (beg_today - 86400 < time) { 03179 /* Yesterday */ 03180 res = wait_file(chan,ints, "digits/yesterday",lang); 03181 } else { 03182 res = ast_say_date_with_format(chan, time, ints, lang, "YBdA", timezone); 03183 } 03184 } 03185 break; 03186 case 'q': 03187 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ 03188 { 03189 struct timeval now; 03190 struct tm tmnow; 03191 time_t beg_today; 03192 03193 gettimeofday(&now,NULL); 03194 ast_localtime(&now.tv_sec,&tmnow,timezone); 03195 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */ 03196 /* In any case, it saves not having to do ast_mktime() */ 03197 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec); 03198 if (beg_today < time) { 03199 /* Today */ 03200 } else if ((beg_today - 86400) < time) { 03201 /* Yesterday */ 03202 res = wait_file(chan,ints, "digits/yesterday",lang); 03203 } else if (beg_today - 86400 * 6 < time) { 03204 /* Within the last week */ 03205 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone); 03206 } else { 03207 res = ast_say_date_with_format(chan, time, ints, lang, "YBdA", timezone); 03208 } 03209 } 03210 break; 03211 case 'R': 03212 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone); 03213 break; 03214 case 'S': 03215 /* Seconds */ 03216 if (!(tm.tm_sec % 10) || tm.tm_sec < 10) { 03217 if (tm.tm_sec < 10) { 03218 res = wait_file(chan, ints, "digits/0", lang); 03219 } 03220 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec); 03221 res = wait_file(chan,ints,nextmsg,lang); 03222 } else { 03223 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec - (tm.tm_sec % 10)); 03224 res = wait_file(chan,ints,nextmsg,lang); 03225 if (!res) { 03226 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec % 10); 03227 res = wait_file(chan,ints,nextmsg,lang); 03228 } 03229 } 03230 if (!res) { 03231 res = wait_file(chan,ints, "digits/second",lang); 03232 } 03233 break; 03234 case 'T': 03235 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone); 03236 break; 03237 case ' ': 03238 case ' ': 03239 /* Just ignore spaces and tabs */ 03240 break; 03241 default: 03242 /* Unknown character */ 03243 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset); 03244 } 03245 /* Jump out on DTMF */ 03246 if (res) { 03247 break; 03248 } 03249 } 03250 return res; 03251 } 03252 03253 03254 int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang) 03255 { 03256 if (!strcasecmp(lang, "en") ) { /* English syntax */ 03257 return(ast_say_time_en(chan, t, ints, lang)); 03258 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 03259 return(ast_say_time_nl(chan, t, ints, lang)); 03260 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 03261 return(ast_say_time_pt(chan, t, ints, lang)); 03262 } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ 03263 return(ast_say_time_tw(chan, t, ints, lang)); 03264 } 03265 03266 /* Default to English */ 03267 return(ast_say_time_en(chan, t, ints, lang)); 03268 } 03269 03270 /* English syntax */ 03271 int ast_say_time_en(struct ast_channel *chan, time_t t, char *ints, char *lang) 03272 { 03273 struct tm tm; 03274 int res = 0; 03275 int hour, pm=0; 03276 localtime_r(&t,&tm); 03277 hour = tm.tm_hour; 03278 if (!hour) 03279 hour = 12; 03280 else if (hour == 12) 03281 pm = 1; 03282 else if (hour > 12) { 03283 hour -= 12; 03284 pm = 1; 03285 } 03286 if (!res) 03287 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03288 03289 if (tm.tm_min > 9) { 03290 if (!res) 03291 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03292 } else if (tm.tm_min) { 03293 if (!res) 03294 res = ast_streamfile(chan, "digits/oh", lang); 03295 if (!res) 03296 res = ast_waitstream(chan, ints); 03297 if (!res) 03298 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03299 } else { 03300 if (!res) 03301 res = ast_streamfile(chan, "digits/oclock", lang); 03302 if (!res) 03303 res = ast_waitstream(chan, ints); 03304 } 03305 if (pm) { 03306 if (!res) 03307 res = ast_streamfile(chan, "digits/p-m", lang); 03308 } else { 03309 if (!res) 03310 res = ast_streamfile(chan, "digits/a-m", lang); 03311 } 03312 if (!res) 03313 res = ast_waitstream(chan, ints); 03314 return res; 03315 } 03316 03317 /* Dutch syntax */ 03318 int ast_say_time_nl(struct ast_channel *chan, time_t t, char *ints, char *lang) 03319 { 03320 struct tm tm; 03321 int res = 0; 03322 int hour; 03323 localtime_r(&t,&tm); 03324 hour = tm.tm_hour; 03325 if (!res) 03326 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03327 03328 if (!res) 03329 res = ast_streamfile(chan, "digits/nl-uur", lang); 03330 if (!res) 03331 res = ast_waitstream(chan, ints); 03332 if (!res) 03333 if (tm.tm_min > 0) 03334 res = ast_say_number(chan, tm.tm_min, ints, lang, NULL); 03335 return res; 03336 } 03337 03338 /* Portuguese syntax */ 03339 int ast_say_time_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) 03340 { 03341 struct tm tm; 03342 int res = 0; 03343 int hour; 03344 localtime_r(&t,&tm); 03345 hour = tm.tm_hour; 03346 if (!res) 03347 res = ast_say_number(chan, hour, ints, lang, "f"); 03348 if (tm.tm_min) { 03349 if (!res) 03350 res = wait_file(chan, ints, "digits/pt-e", lang); 03351 if (!res) 03352 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03353 } else { 03354 if (!res) 03355 res = wait_file(chan, ints, "digits/pt-hora", lang); 03356 if (tm.tm_hour != 1) 03357 if (!res) 03358 res = wait_file(chan, ints, "digits/pt-sss", lang); 03359 } 03360 if (!res) 03361 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03362 return res; 03363 } 03364 03365 /* Taiwanese syntax */ 03366 int ast_say_time_tw(struct ast_channel *chan, time_t t, char *ints, char *lang) 03367 { 03368 struct tm tm; 03369 int res = 0; 03370 int hour, pm=0; 03371 localtime_r(&t,&tm); 03372 hour = tm.tm_hour; 03373 if (!hour) 03374 hour = 12; 03375 else if (hour == 12) 03376 pm = 1; 03377 else if (hour > 12) { 03378 hour -= 12; 03379 pm = 1; 03380 } 03381 if (pm) { 03382 if (!res) 03383 res = ast_streamfile(chan, "digits/p-m", lang); 03384 } else { 03385 if (!res) 03386 res = ast_streamfile(chan, "digits/a-m", lang); 03387 } 03388 if (!res) 03389 res = ast_waitstream(chan, ints); 03390 if (!res) 03391 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03392 if (!res) 03393 res = ast_streamfile(chan, "digits/oclock", lang); 03394 if (!res) 03395 res = ast_waitstream(chan, ints); 03396 if (!res) 03397 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03398 if (!res) 03399 res = ast_streamfile(chan, "digits/minute", lang); 03400 if (!res) 03401 res = ast_waitstream(chan, ints); 03402 return res; 03403 } 03404 03405 03406 int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang) 03407 { 03408 if (!strcasecmp(lang, "en") ) { /* English syntax */ 03409 return(ast_say_datetime_en(chan, t, ints, lang)); 03410 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */ 03411 return(ast_say_datetime_nl(chan, t, ints, lang)); 03412 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 03413 return(ast_say_datetime_pt(chan, t, ints, lang)); 03414 } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */ 03415 return(ast_say_datetime_tw(chan, t, ints, lang)); 03416 } 03417 03418 /* Default to English */ 03419 return(ast_say_datetime_en(chan, t, ints, lang)); 03420 } 03421 03422 /* English syntax */ 03423 int ast_say_datetime_en(struct ast_channel *chan, time_t t, char *ints, char *lang) 03424 { 03425 struct tm tm; 03426 char fn[256]; 03427 int res = 0; 03428 int hour, pm=0; 03429 localtime_r(&t,&tm); 03430 if (!res) { 03431 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03432 res = ast_streamfile(chan, fn, lang); 03433 if (!res) 03434 res = ast_waitstream(chan, ints); 03435 } 03436 if (!res) { 03437 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03438 res = ast_streamfile(chan, fn, lang); 03439 if (!res) 03440 res = ast_waitstream(chan, ints); 03441 } 03442 if (!res) 03443 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03444 03445 hour = tm.tm_hour; 03446 if (!hour) 03447 hour = 12; 03448 else if (hour == 12) 03449 pm = 1; 03450 else if (hour > 12) { 03451 hour -= 12; 03452 pm = 1; 03453 } 03454 if (!res) 03455 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03456 03457 if (tm.tm_min > 9) { 03458 if (!res) 03459 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03460 } else if (tm.tm_min) { 03461 if (!res) 03462 res = ast_streamfile(chan, "digits/oh", lang); 03463 if (!res) 03464 res = ast_waitstream(chan, ints); 03465 if (!res) 03466 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03467 } else { 03468 if (!res) 03469 res = ast_streamfile(chan, "digits/oclock", lang); 03470 if (!res) 03471 res = ast_waitstream(chan, ints); 03472 } 03473 if (pm) { 03474 if (!res) 03475 res = ast_streamfile(chan, "digits/p-m", lang); 03476 } else { 03477 if (!res) 03478 res = ast_streamfile(chan, "digits/a-m", lang); 03479 } 03480 if (!res) 03481 res = ast_waitstream(chan, ints); 03482 if (!res) 03483 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 03484 return res; 03485 } 03486 03487 /* Dutch syntax */ 03488 int ast_say_datetime_nl(struct ast_channel *chan, time_t t, char *ints, char *lang) 03489 { 03490 struct tm tm; 03491 int res = 0; 03492 localtime_r(&t,&tm); 03493 res = ast_say_date(chan, t, ints, lang); 03494 if (!res) { 03495 res = ast_streamfile(chan, "digits/nl-om", lang); 03496 if (!res) 03497 res = ast_waitstream(chan, ints); 03498 } 03499 if (!res) 03500 ast_say_time(chan, t, ints, lang); 03501 return res; 03502 } 03503 03504 /* Portuguese syntax */ 03505 int ast_say_datetime_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) 03506 { 03507 struct tm tm; 03508 char fn[256]; 03509 int res = 0; 03510 int hour, pm=0; 03511 localtime_r(&t,&tm); 03512 if (!res) { 03513 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03514 res = ast_streamfile(chan, fn, lang); 03515 if (!res) 03516 res = ast_waitstream(chan, ints); 03517 } 03518 if (!res) { 03519 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03520 res = ast_streamfile(chan, fn, lang); 03521 if (!res) 03522 res = ast_waitstream(chan, ints); 03523 } 03524 if (!res) 03525 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03526 03527 hour = tm.tm_hour; 03528 if (!hour) 03529 hour = 12; 03530 else if (hour == 12) 03531 pm = 1; 03532 else if (hour > 12) { 03533 hour -= 12; 03534 pm = 1; 03535 } 03536 if (!res) 03537 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03538 03539 if (tm.tm_min > 9) { 03540 if (!res) 03541 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03542 } else if (tm.tm_min) { 03543 if (!res) 03544 res = ast_streamfile(chan, "digits/oh", lang); 03545 if (!res) 03546 res = ast_waitstream(chan, ints); 03547 if (!res) 03548 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03549 } else { 03550 if (!res) 03551 res = ast_streamfile(chan, "digits/oclock", lang); 03552 if (!res) 03553 res = ast_waitstream(chan, ints); 03554 } 03555 if (pm) { 03556 if (!res) 03557 res = ast_streamfile(chan, "digits/p-m", lang); 03558 } else { 03559 if (!res) 03560 res = ast_streamfile(chan, "digits/a-m", lang); 03561 } 03562 if (!res) 03563 res = ast_waitstream(chan, ints); 03564 if (!res) 03565 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 03566 return res; 03567 } 03568 03569 /* Taiwanese syntax */ 03570 int ast_say_datetime_tw(struct ast_channel *chan, time_t t, char *ints, char *lang) 03571 { 03572 struct tm tm; 03573 char fn[256]; 03574 int res = 0; 03575 int hour, pm=0; 03576 localtime_r(&t,&tm); 03577 if (!res) 03578 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); 03579 if (!res) { 03580 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03581 res = ast_streamfile(chan, fn, lang); 03582 if (!res) 03583 res = ast_waitstream(chan, ints); 03584 } 03585 if (!res) 03586 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03587 if (!res) { 03588 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03589 res = ast_streamfile(chan, fn, lang); 03590 if (!res) 03591 res = ast_waitstream(chan, ints); 03592 } 03593 03594 hour = tm.tm_hour; 03595 if (!hour) 03596 hour = 12; 03597 else if (hour == 12) 03598 pm = 1; 03599 else if (hour > 12) { 03600 hour -= 12; 03601 pm = 1; 03602 } 03603 if (pm) { 03604 if (!res) 03605 res = ast_streamfile(chan, "digits/p-m", lang); 03606 } else { 03607 if (!res) 03608 res = ast_streamfile(chan, "digits/a-m", lang); 03609 } 03610 if (!res) 03611 res = ast_waitstream(chan, ints); 03612 if (!res) 03613 res = ast_say_number(chan, hour, ints, lang, (char *) NULL); 03614 if (!res) 03615 res = ast_streamfile(chan, "digits/oclock", lang); 03616 if (!res) 03617 res = ast_waitstream(chan, ints); 03618 if (!res) 03619 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); 03620 if (!res) 03621 res = ast_streamfile(chan, "digits/minute", lang); 03622 if (!res) 03623 res = ast_waitstream(chan, ints); 03624 return res; 03625 } 03626 03627 03628 int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, char *lang) 03629 { 03630 if (!strcasecmp(lang, "en") ) { /* English syntax */ 03631 return(ast_say_datetime_from_now_en(chan, t, ints, lang)); 03632 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */ 03633 return(ast_say_datetime_from_now_pt(chan, t, ints, lang)); 03634 } 03635 03636 /* Default to English */ 03637 return(ast_say_datetime_from_now_en(chan, t, ints, lang)); 03638 } 03639 03640 /* English syntax */ 03641 int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, char *ints, char *lang) 03642 { 03643 int res=0; 03644 time_t nowt; 03645 int daydiff; 03646 struct tm tm; 03647 struct tm now; 03648 char fn[256]; 03649 03650 time(&nowt); 03651 03652 localtime_r(&t,&tm); 03653 localtime_r(&nowt,&now); 03654 daydiff = now.tm_yday - tm.tm_yday; 03655 if ((daydiff < 0) || (daydiff > 6)) { 03656 /* Day of month and month */ 03657 if (!res) { 03658 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03659 res = ast_streamfile(chan, fn, lang); 03660 if (!res) 03661 res = ast_waitstream(chan, ints); 03662 } 03663 if (!res) 03664 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03665 03666 } else if (daydiff) { 03667 /* Just what day of the week */ 03668 if (!res) { 03669 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03670 res = ast_streamfile(chan, fn, lang); 03671 if (!res) 03672 res = ast_waitstream(chan, ints); 03673 } 03674 } /* Otherwise, it was today */ 03675 if (!res) 03676 res = ast_say_time(chan, t, ints, lang); 03677 return res; 03678 } 03679 03680 /* Portuguese syntax */ 03681 int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, char *ints, char *lang) 03682 { 03683 int res=0; 03684 time_t nowt; 03685 int daydiff; 03686 struct tm tm; 03687 struct tm now; 03688 char fn[256]; 03689 03690 time(&nowt); 03691 03692 localtime_r(&t,&tm); 03693 localtime_r(&nowt,&now); 03694 daydiff = now.tm_yday - tm.tm_yday; 03695 if ((daydiff < 0) || (daydiff > 6)) { 03696 /* Day of month and month */ 03697 if (!res) 03698 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); 03699 if (!res) 03700 res = wait_file(chan, ints, "digits/pt-de", lang); 03701 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon); 03702 if (!res) 03703 res = wait_file(chan, ints, fn, lang); 03704 03705 } else if (daydiff) { 03706 /* Just what day of the week */ 03707 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday); 03708 if (!res) 03709 res = wait_file(chan, ints, fn, lang); 03710 } /* Otherwise, it was today */ 03711 snprintf(fn, sizeof(fn), "digits/pt-ah"); 03712 if (!res) 03713 res = wait_file(chan, ints, fn, lang); 03714 if (tm.tm_hour != 1) 03715 if (!res) 03716 res = wait_file(chan, ints, "digits/pt-sss", lang); 03717 if (!res) 03718 res = ast_say_time(chan, t, ints, lang); 03719 return res; 03720 }

Generated on Sat Jun 12 16:40:59 2004 for Asterisk by doxygen 1.3.7