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

say.c

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

Generated on Thu Nov 29 22:50:24 2007 for Asterisk by  doxygen 1.4.2