Skip to content
Snippets Groups Projects
say.c 109 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		1000 is one thousand in en, 2000 is two thousand.
    		In it we have 1000 = mille , 2000 = 2 mila 
    
    		For million(s) we use the plural, if more than one
    		Also, one million is abbreviated in it, like on-million,
    		or 'un milione', not 'uno milione'.
    		So the right file is provided.
    		*/
    
    
    		while(!res && (num || playh)) {
    			if (playh) {
    				snprintf(fn, sizeof(fn), "digits/hundred");
    				playh = 0;
    			} else if (num < 20) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 21) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 28) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 31) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 38) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 41) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 48) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 51) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 58) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 61) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 68) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 71) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 78) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 81) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 88) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 91) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num == 98) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else if (num < 100) {
    				snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
    				num -= ((num / 10) * 10);
    			} else {
    				if (num < 1000) {
    					if ((num / 100) > 1) {
    						snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    						playh++;
    					} else {
    						snprintf(fn, sizeof(fn), "digits/hundred");
    					}
    					num -= ((num / 100) * 100);
    				} else {
    					if (num < 1000000) { /* 1,000,000 */
    						if ((num/1000) > 1)
    
    							res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
    
    						if (res)
    							return res;
    						tempnum = num;
    						num = num % 1000;
    						if ((tempnum / 1000) < 2)
    							snprintf(fn, sizeof(fn), "digits/thousand");
    						else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
    							snprintf(fn, sizeof(fn), "digits/thousands");
    					} else {
    						if (num < 1000000000) { /* 1,000,000,000 */
    							if ((num / 1000000) > 1)
    
    								res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
    
    							if (res)
    								return res;
    							tempnum = num;
    							num = num % 1000000;
    							if ((tempnum / 1000000) < 2)
    								snprintf(fn, sizeof(fn), "digits/million");
    							else
    								snprintf(fn, sizeof(fn), "digits/millions");
    						} else {
    							ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    							res = -1;
    						}
    					}
    				}
    			}
    			if (!res) {
    				if(!ast_streamfile(chan, fn, language)) {
    					if (audiofd && ctrlfd)
    						res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    					else
    						res = ast_waitstream(chan, ints);
    				}
    				ast_stopstream(chan);
    			}
    		}
    	return res;
    
    /*--- ast_say_number_full_nl: dutch syntax */
    /* New files: digits/nl-en
    
    static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
    
    	char fn[256] = "";
    	if (!num) 
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    
    	while (!res && (num || playh )) {
    		if (playh) {
    			snprintf(fn, sizeof(fn), "digits/hundred");
    			playh = 0;
    		} else if (num < 20) {
    			snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    		} else if (num < 100) {
    			units = num % 10;
    			if (units > 0) {
    				res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
    				if (res)
    					return res;
    				num = num - units;
    				snprintf(fn, sizeof(fn), "digits/nl-en");
    			} else {
    				snprintf(fn, sizeof(fn), "digits/%d", num - units);
    				num = 0;
    			}
    		} else {
    			if (num < 1000) {
    				snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    				playh++;
    				num -= ((num / 100) * 100);
    			} else {
    				if (num < 1000000) { /* 1,000,000 */
    					res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
    					if (res)
    						return res;
    					num = num % 1000;
    					snprintf(fn, sizeof(fn), "digits/thousand");
    				} else {
    					if (num < 1000000000) { /* 1,000,000,000 */
    						res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
    						if (res)
    							return res;
    						num = num % 1000000;
    						snprintf(fn, sizeof(fn), "digits/million");
    					} else {
    						ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    						res = -1;
    					}
    				}
    			}
    		}
    
    		if (!res) {
    			if(!ast_streamfile(chan, fn, language)) {
    				if (audiofd && ctrlfd)
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    				else
    					res = ast_waitstream(chan, ints);
    			}
    			ast_stopstream(chan);
    		}
    
    /* ast_say_number_full_pl: Polish syntax */
    static int ast_say_number_full_pl(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
    /*
    Sounds needed:
    0		zero
    1		jeden
    10		dziesiec
    100		sto
    1000		tysiac
    1000000		milion
    1000000000	miliard
    1000000000.2	miliardy
    1000000000.5	miliardow
    1000000.2	miliony
    1000000.5	milionow
    1000.2		tysiace
    1000.5		tysiecy
    100m		stu
    10m		dziesieciu
    11		jedenascie
    11m		jedenastu
    12		dwanascie
    12m		dwunastu
    13		trzynascie
    13m		trzynastu
    14		czternascie
    14m		czternastu
    15		pietnascie
    15m		pietnastu
    16		szesnascie
    16m		szesnastu
    17		siedemnascie
    17m		siedemnastu
    18		osiemnascie
    18m		osiemnastu
    19		dziewietnascie
    19m		dziewietnastu
    1z		jedna
    2		dwie
    20		dwadziescia
    200		dwiescie
    200m		dwustu
    20m		dwudziestu
    2-1m		dwaj
    2-2m		dwoch
    2z		dwie
    3		trzy
    30		trzydziesci
    300		trzysta
    300m		trzystu
    30m		trzydziestu
    3-1m		trzej
    3-2m		trzech
    4		cztery
    40		czterdziesci
    400		czterysta
    400m		czterystu
    40m		czterdziestu
    4-1m		czterej
    4-2m		czterech
    5		piec
    50		piecdziesiat
    500		piecset
    500m		pieciuset
    50m		piedziesieciu
    5m		pieciu
    6		szesc
    60		szescdziesiat
    600		szescset
    600m		szesciuset
    60m		szescdziesieciu
    6m		szesciu
    7		siedem
    70		siedemdziesiat
    700		siedemset
    700m		siedmiuset
    70m		siedemdziesieciu
    7m		siedmiu
    8		osiem
    80		osiemdziesiat
    800		osiemset
    800m		osmiuset
    80m		osiemdziesieciu
    8m		osmiu
    9		dziewiec
    90		dziewiecdziesiat
    900		dziewiecset
    900m		dziewieciuset
    90m		dziewiedziesieciu
    9m		dziewieciu
    and combinations of eg.: 20_1, 30m_3m, etc...
    
    */
    {
    	typedef struct {  
    	char *separator_dziesiatek;
    	char *cyfry[10];
    	char *cyfry2[10];
    	char *setki[10];
    	char *dziesiatki[10];
    	char *nastki[10];  
    	char *rzedy[3][3];
    	} odmiana;
    
    	char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
    
    	char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
    
    	char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m",  /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
    
    	char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
    
    	char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
    
    	char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
    
    	char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
    
    	char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
    
    	char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
    
    	char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
    
    	char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
    
    	char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
    
    	char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}}; 
    
    	/* Initialise variables to allow compilation on Debian-stable, etc */
    	odmiana *o;
    
    	static char* rzad_na_tekst(odmiana *odm, int i, int rzad)
    	{
    		if (rzad==0)
    			return "";
      
    		if (i==1)
    			return odm->rzedy[rzad - 1][0];
    
    		if ((i > 21 || i < 11) &&  i%10 > 1 && i%10 < 5)
    			return odm->rzedy[rzad - 1][1];
    		else
    			return odm->rzedy[rzad - 1][2];
    	}
    
    	static char* append(char* buffer, char* str)
    	{
    		strcpy(buffer, str);
    		buffer += strlen(str); 
    		return buffer;
    	}
    
    	static void odtworz_plik(char *fn)
    	{    
    		char file_name[255] = "digits/";
    		strcat(file_name, fn);
    		ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
    		if (!ast_streamfile(chan, file_name, language)) {
    			if (audiofd && ctrlfd)
    				ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    			else
    				ast_waitstream(chan, ints);
    		}
    		ast_stopstream(chan);
    	}
    
    	static void powiedz(odmiana *odm, int rzad, int i)
    	{
    		/* Initialise variables to allow compilation on Debian-stable, etc */
    		int m1000E6 = 0;
    		int i1000E6 = 0;
    		int m1000E3 = 0;
    		int i1000E3 = 0;
    		int m1000 = 0;
    		int i1000 = 0;
    		int m100 = 0;
    		int i100 = 0;
    		
    		if (i == 0 && rzad > 0) { 
    			return;
    		}
    		if (i == 0) {
    			odtworz_plik(odm->cyfry[0]);
    		}
    
    		m1000E6 = i % 1000000000;
    		i1000E6 = i / 1000000000;
    
    		powiedz(odm, rzad+3, i1000E6);
    
    		m1000E3 = m1000E6 % 1000000;
    		i1000E3 = m1000E6 / 1000000;
    
    		powiedz(odm, rzad+2, i1000E3);
    
    		m1000 = m1000E3 % 1000;
    		i1000 = m1000E3 / 1000;
    
    		powiedz(odm, rzad+1, i1000);
    
    		m100 = m1000 % 100;
    		i100 = m1000 / 100;
    
    		if (i100>0)
    			odtworz_plik(odm->setki[i100]);
    
    		if ( m100 > 0 && m100 <=9 ) {
    			if (m1000>0)
    				odtworz_plik(odm->cyfry2[m100]);
    			else
    				odtworz_plik(odm->cyfry[m100]);
    		} else if (m100 % 10 == 0) {
    			odtworz_plik(odm->dziesiatki[m100 / 10]);
    		} else if (m100 <= 19 ) {
    			odtworz_plik(odm->nastki[m100 % 10]);
    		} else if (m100 != 0) {
    			if (odm->separator_dziesiatek[0]==' ') {
    				odtworz_plik(odm->dziesiatki[m100 / 10]);
    				odtworz_plik(odm->cyfry2[m100 % 10]);
    			} else {
    				char buf[10];
    				char *b = buf;
    				b = append(b, odm->dziesiatki[m100 / 10]);  
    				b = append(b, odm->separator_dziesiatek);  
    				b = append(b, odm->cyfry2[m100 % 10]); 
    				odtworz_plik(buf);
    			}
    		} 
    
    		if (rzad > 0) {
    			odtworz_plik(rzad_na_tekst(odm, i, rzad));
    		}
    	}
    
    	static odmiana *odmiana_nieosobowa = NULL; 
    	static odmiana *odmiana_meska = NULL; 
    	static odmiana *odmiana_zenska = NULL; 
    
    	if (odmiana_nieosobowa == NULL) {
    		odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
    
    		odmiana_nieosobowa->separator_dziesiatek = "_";
    
    		memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
    		memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
    		memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
    		memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
    		memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
    		memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
    	}
    
    	if (odmiana_zenska == NULL) {
    		odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
    
    		odmiana_zenska->separator_dziesiatek = "_";
    
    		memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
    		memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
    		memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
    		memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
    		memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
    		memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
    	}
    
    	if (odmiana_meska == NULL) {
    		odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
    
    		odmiana_meska->separator_dziesiatek = "_";
    
    		memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
    		memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
    		memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
    		memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
    		memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
    		memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
    	}
    
    	if (options) {
    		if (strncasecmp(options, "f", 1) == 0)
    			o = odmiana_zenska;
    		else if (strncasecmp(options, "m", 1) == 0)
    			o = odmiana_meska;
    		else
    			o = odmiana_nieosobowa;
    	} else
    		o = odmiana_nieosobowa;
    
    	powiedz(o, 0, num);
    	return 0;
    }
    
    
    /* ast_say_number_full_pt: Portuguese syntax */
    /* 	Extra sounds needed: */
    /* 	For feminin all sound files end with F */
    /*	100E for 100+ something */
    /*	1000000S for plural */
    /*	pt-e for 'and' */
    static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
    
    	int mf = 1;                            /* +1 = Masculin; -1 = Feminin */
    
    	if (!num) 
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    
    
    	if (options && !strncasecmp(options, "f",1))
    		mf = -1;
    
    	while(!res && num ) {
    		if (num < 20) {
    			if ((num == 1 || num == 2) && (mf < 0))
    				snprintf(fn, sizeof(fn), "digits/%dF", num);
    			else
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    		} else if (num < 100) {
    			snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
    			if (num % 10)
    				playh = 1;
    			num = num % 10;
    		} else if (num < 1000) {
    			if (num == 100)
    				snprintf(fn, sizeof(fn), "digits/100");
    			else if (num < 200)
    				snprintf(fn, sizeof(fn), "digits/100E");
    			else {
    				if (mf < 0 && num > 199)
    					snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
    				else
    					snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
    				if (num % 100)
    					playh = 1;
    			}
    			num = num % 100;
    		} else if (num < 1000000) {
    			if (num > 1999) {
    				res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
    				if (res)
    					return res;
    			}
    			snprintf(fn, sizeof(fn), "digits/1000");
    			if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
    				playh = 1;
    			num = num % 1000;
    		} else if (num < 1000000000) {
    			res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
    			if (res)
    				return res;
    			if (num < 2000000)
    				snprintf(fn, sizeof(fn), "digits/1000000");
    			else
    				snprintf(fn, sizeof(fn), "digits/1000000S");
     
    			if ((num % 1000000) &&
    				// no thousands
    				((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
    				// no hundreds and below
    				(!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
    				playh = 1;
    			num = num % 1000000;
    		}
    		if (!res && playh) {
    			res = wait_file(chan, ints, "digits/pt-e", language);
    			ast_stopstream(chan);
    			playh = 0;
    		}
    		if (!res) {
    			if(!ast_streamfile(chan, fn, language)) {
    				if (audiofd && ctrlfd)
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);			else
    					res = ast_waitstream(chan, ints);
    			}
    			ast_stopstream(chan);
    		}
    	}
    	return res;
    }
    
    /*--- ast_say_number_full_se: Swedish/Norwegian syntax */
    static int ast_say_number_full_se(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
    {
    	int res = 0;
    	int playh = 0;
    	char fn[256] = "";
    	int cn = 1;		/* +1 = Commune; -1 = Neutrum */
    	if (!num) 
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    	if (options && !strncasecmp(options, "n",1)) cn = -1;
    
    	while(!res && (num || playh)) {
    			if (playh) {
    				snprintf(fn, sizeof(fn), "digits/hundred");
    				playh = 0;
    			} else
    			if (num < 20) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else
    			if (num < 100) {
    				snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
    				num -= ((num / 10) * 10);
    		        } else 
    			if (num == 1 && cn == -1) {	/* En eller ett? */
    			 	snprintf(fn, sizeof(fn), "digits/1N");
    				num = 0;
    			} else {
    				if (num < 1000){
    					snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    					playh++;
    					num -= ((num / 100) * 100);
    				} else {
    					if (num < 1000000) { /* 1,000,000 */
    						res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
    						if (res)
    							return res;
    						num = num % 1000;
    						snprintf(fn, sizeof(fn), "digits/thousand");
    					} else {
    						if (num < 1000000000) {	/* 1,000,000,000 */
    							res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
    							if (res)
    								return res;
    							num = num % 1000000;
    							snprintf(fn, sizeof(fn), "digits/million");
    						} else {
    							ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    							res = -1;
    						}
    					}
    				}
    			}
    			 if (!res) {
                                    if(!ast_streamfile(chan, fn, language)) {
                                        if (audiofd && ctrlfd)
                                            res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
                                        else
                                             res = ast_waitstream(chan, ints);
                                    }
                                    ast_stopstream(chan);
    
                            }
    			
    	}
    	return res;
    }
    
    
    
    /*--- ast_say_number_full_tw: Taiwanese syntax */
    static int ast_say_number_full_tw(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
    {
    	int res = 0;
    	int playh = 0;
    	char fn[256] = "";
    	if (!num)
    		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
    
    	while(!res && (num || playh)) {
    		if (playh) {
    				snprintf(fn, sizeof(fn), "digits/hundred");
    				playh = 0;
    			} else	if (num < 10) {
    				snprintf(fn, sizeof(fn), "digits/%d", num);
    				num = 0;
    			} else	if (num < 100) {
    				snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
    				num -= ((num / 10) * 10);
    			} else {
    				if (num < 1000){
    					snprintf(fn, sizeof(fn), "digits/%d", (num/100));
    					playh++;
    					num -= ((num / 100) * 100);
    				} else {
    					if (num < 1000000) { /* 1,000,000 */
    
    						res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
    
    						if (res)
    							return res;
    						num = num % 1000;
    						snprintf(fn, sizeof(fn), "digits/thousand");
    					} else {
    						if (num < 1000000000) {	/* 1,000,000,000 */
    
    							res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
    
    							if (res)
    								return res;
    							num = num % 1000000;
    							snprintf(fn, sizeof(fn), "digits/million");
    						} else {
    							ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
    							res = -1;
    						}
    					}
    				}
    			}
    			if (!res) {
    				if(!ast_streamfile(chan, fn, language)) {
    					if (audiofd && ctrlfd)
    						res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    					else
    						res = ast_waitstream(chan, ints);
    				}
    				ast_stopstream(chan);
    
    			}
    	}
    	return res;
    }
    
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
    
    {
    	if (!strcasecmp(lang,"en") ) {	/* English syntax */
    		return(ast_say_date_en(chan, t, ints, lang));
    	} else if (!strcasecmp(lang, "nl") ) {	/* Dutch syntax */
    		return(ast_say_date_nl(chan, t, ints, lang));
    	} else if (!strcasecmp(lang, "pt") ) {	/* Portuguese syntax */
    		return(ast_say_date_pt(chan, t, ints, lang));
    	}
    
    	/* Default to English */
    	return(ast_say_date_en(chan, t, ints, lang));
    }
    
    /* English syntax */
    int ast_say_date_en(struct ast_channel *chan, time_t t, char *ints, char *lang)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char fn[256];
    	int res = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!res) {
    
    		snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = ast_streamfile(chan, fn, lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    	}
    	if (!res) {
    
    		snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = ast_streamfile(chan, fn, lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    	}
    	if (!res)
    
    		res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!res)
    		res = ast_waitstream(chan, ints);
    	if (!res)
    
    		res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    /* Dutch syntax */
    int ast_say_date_nl(struct ast_channel *chan, time_t t, char *ints, char *lang)
    
    	struct tm tm;
    	char fn[256];
    	int res = 0;
    	ast_localtime(&t,&tm,NULL);
    	if (!res) {
    		snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
    		res = ast_streamfile(chan, fn, lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    	}
    	if (!res)
    		res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
    	if (!res) {
    		snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
    		res = ast_streamfile(chan, fn, lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    	}
    
    	if (!res)
    		res = ast_waitstream(chan, ints);
    
    	if (!res)
    		res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
    	return res;
    }
    
    /* Portuguese syntax */
    int ast_say_date_pt(struct ast_channel *chan, time_t t, char *ints, char *lang)
    {
    	struct tm tm;
    	char fn[256];
    	int res = 0;
    	ast_localtime(&t,&tm,NULL);
    	localtime_r(&t,&tm);
    	snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
    	if (!res)
    		res = wait_file(chan, ints, fn, lang);
    	if (!res)
    		res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
    	if (!res)
    		res = wait_file(chan, ints, "digits/pt-de", lang);
    	snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
    	if (!res)
    		res = wait_file(chan, ints, fn, lang);
    	if (!res)
    		res = wait_file(chan, ints, "digits/pt-de", lang);
    	if (!res)
    		res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
    
    
    	return res;
    }
    
    int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
    
    {
    	if (!strcasecmp(lang, "en") ) {	/* English syntax */
    		return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
    
    	} else if (!strcasecmp(lang, "de") ) {	/* German syntax */
    		return(ast_say_date_with_format_de(chan, time, ints, lang, format, timezone));
    
    	} else if (!strcasecmp(lang, "es") || !strcasecmp(lang, "mx")) {	/* Spanish syntax */
    		return(ast_say_date_with_format_es(chan, time, ints, lang, format, timezone));
    
    	} else if (!strcasecmp(lang, "nl") ) {	/* Dutch syntax */
    		return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone));
    	} else if (!strcasecmp(lang, "pt") ) {	/* Portuguese syntax */
    		return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone));
    
    	} else if (!strcasecmp(lang, "tw") ) {	/* Taiwanese syntax */
    		return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone));
    
    	}
    
    	/* Default to English */
    	return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
    }
    
    /* English syntax */
    int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
    
    {
    	struct tm tm;
    	int res=0, offset, sndoffset;
    	char sndfile[256], nextmsg[256];
    
    	ast_localtime(&time,&tm,timezone);
    
    
    	for (offset=0 ; format[offset] != '\0' ; offset++) {
    		ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
    		switch (format[offset]) {
    			/* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
    			case '\'':
    				/* Literal name of a sound file */
    				sndoffset=0;
    				for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
    					sndfile[sndoffset] = format[offset];
    				sndfile[sndoffset] = '\0';
    
    				res = wait_file(chan,ints,sndfile,lang);
    
    				break;
    			case 'A':
    			case 'a':
    				/* Sunday - Saturday */
    				snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
    				res = wait_file(chan,ints,nextmsg,lang);
    				break;
    			case 'B':
    			case 'b':
    			case 'h':
    				/* January - December */
    				snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
    				res = wait_file(chan,ints,nextmsg,lang);
    				break;
    			case 'd':
    			case 'e':
    				/* First - Thirtyfirst */
    				if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) {
    					snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday);
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else if (tm.tm_mday == 31) {
    					/* "Thirty" and "first" */
    					res = wait_file(chan,ints, "digits/30",lang);
    					if (!res) {
    						res = wait_file(chan,ints, "digits/h-1",lang);
    					}
    				} else {
    					/* Between 21 and 29 - two sounds */
    					res = wait_file(chan,ints, "digits/20",lang);
    					if (!res) {
    						snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20);
    						res = wait_file(chan,ints,nextmsg,lang);
    					}
    				}
    				break;
    			case 'Y':
    				/* Year */
    				if (tm.tm_year > 99) {
    					res = wait_file(chan,ints, "digits/2",lang);
    					if (!res) {
    						res = wait_file(chan,ints, "digits/thousand",lang);
    					}
    					if (tm.tm_year > 100) {
    						if (!res) {
    							/* This works until the end of 2020 */
    							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100);
    							res = wait_file(chan,ints,nextmsg,lang);
    						}
    					}
    				} else {
    					if (tm.tm_year < 1) {
    						/* I'm not going to handle 1900 and prior */
    						/* We'll just be silent on the year, instead of bombing out. */
    					} else {
    						res = wait_file(chan,ints, "digits/19",lang);
    						if (!res) {
    							if (tm.tm_year <= 9) {
    								/* 1901 - 1909 */
    								res = wait_file(chan,ints, "digits/oh",lang);
    								if (!res) {
    									snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
    									res = wait_file(chan,ints,nextmsg,lang);
    								}
    							} else if (tm.tm_year <= 20) {
    								/* 1910 - 1920 */
    								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
    								res = wait_file(chan,ints,nextmsg,lang);
    							} else {
    								/* 1921 - 1999 */
    								int ten, one;
    								ten = tm.tm_year / 10;
    								one = tm.tm_year % 10;
    								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
    								res = wait_file(chan,ints,nextmsg,lang);
    								if (!res) {
    									if (one != 0) {
    										snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
    										res = wait_file(chan,ints,nextmsg,lang);
    									}
    								}
    							}
    						}
    					}
    				}
    				break;
    			case 'I':
    			case 'l':
    				/* 12-Hour */
    				if (tm.tm_hour == 0)
    					snprintf(nextmsg,sizeof(nextmsg), "digits/12");
    				else if (tm.tm_hour > 12)
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
    				else
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
    				res = wait_file(chan,ints,nextmsg,lang);
    				break;
    			case 'H':
    			case 'k':
    				/* 24-Hour */
    				if (format[offset] == 'H') {
    					/* e.g. oh-eight */
    					if (tm.tm_hour < 10) {
    						res = wait_file(chan,ints, "digits/oh",lang);
    					}
    				} else {
    					/* e.g. eight */
    					if (tm.tm_hour == 0) {
    						res = wait_file(chan,ints, "digits/oh",lang);
    					}
    				}
    				if (!res) {
    					if (tm.tm_hour != 0) {
    						int remainder = tm.tm_hour;
    						if (tm.tm_hour > 20) {
    							res = wait_file(chan,ints, "digits/20",lang);
    							remainder -= 20;
    						}
    						if (!res) {
    							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
    							res = wait_file(chan,ints,nextmsg,lang);
    						}
    					}
    				}
    				break;
    			case 'M':
    				/* Minute */
    				if (tm.tm_min == 0) {
    					res = wait_file(chan,ints, "digits/oclock",lang);
    				} else if (tm.tm_min < 10) {
    					res = wait_file(chan,ints, "digits/oh",lang);
    					if (!res) {
    						snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
    						res = wait_file(chan,ints,nextmsg,lang);
    					}
    				} else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else {
    					int ten, one;
    					ten = (tm.tm_min / 10) * 10;
    					one = (tm.tm_min % 10);
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
    					res = wait_file(chan,ints,nextmsg,lang);
    					if (!res) {
    						/* Fifty, not fifty-zero */
    						if (one != 0) {
    							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
    							res = wait_file(chan,ints,nextmsg,lang);
    						}
    					}
    				}
    				break;
    			case 'P':
    			case 'p':
    				/* AM/PM */
    				if (tm.tm_hour > 11)
    					snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
    				else
    					snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
    				res = wait_file(chan,ints,nextmsg,lang);
    				break;