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

Generated on Wed Aug 10 11:36:32 2005 for Asterisk by  doxygen 1.4.4