Skip to content
Snippets Groups Projects
say.c 186 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			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 'm':
    				/* Month enumerated */
    				res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, (char *) NULL);	
    				break;
    
    			case 'd':
    			case 'e':
    				/* First - Thirtyfirst */
    
    				res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char *) NULL);	
    
    				break;
    			case 'Y':
    				/* Year */
    				if (tm.tm_year > 99) {
    
    				        res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
    
    				} 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. */
    
    					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);
    
    
    						res |= ast_say_number(chan, tm.tm_year, ints, lang, (char *) NULL);
    
    					}
    				}
    				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) {
    
    					if (format[offset] == 'M') {
    						res = wait_file(chan, ints, "digits/oclock", lang);
    					} else {
    						res = wait_file(chan, ints, "digits/hundred", 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 {
    
    					res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
    
    				}
    				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;
    			case 'Q':
    				/* Shorthand for "Today", "Yesterday", or ABdY */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    						res = wait_file(chan,ints, "digits/today",lang);
    					} else if (beg_today - 86400 < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    
    					} else if (beg_today - 86400 * 6 < time) {
    						/* Within the last week */
    						res = ast_say_date_with_format_en(chan, time, ints, lang, "A", timezone);
    					} else if (beg_today - 2628000 < time) {
    						/* Less than a month ago - "Sunday, October third" */
    						res = ast_say_date_with_format_en(chan, time, ints, lang, "ABd", timezone);
    					} else if (beg_today - 15768000 < time) {
    						/* Less than 6 months ago - "August seventh" */
    						res = ast_say_date_with_format_en(chan, time, ints, lang, "Bd", timezone);
    
    						/* More than 6 months ago - "April nineteenth two thousand three" */
    						res = ast_say_date_with_format_en(chan, time, ints, lang, "BdY", timezone);
    
    					}
    				}
    				break;
    			case 'q':
    				/* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    					} else if ((beg_today - 86400) < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    					} else if (beg_today - 86400 * 6 < time) {
    						/* Within the last week */
    
    						res = ast_say_date_with_format_en(chan, time, ints, lang, "A", timezone);
    					} else if (beg_today - 2628000 < time) {
    						/* Less than a month ago - "Sunday, October third" */
    						res = ast_say_date_with_format_en(chan, time, ints, lang, "ABd", timezone);
    					} else if (beg_today - 15768000 < time) {
    						/* Less than 6 months ago - "August seventh" */
    						res = ast_say_date_with_format_en(chan, time, ints, lang, "Bd", timezone);
    
    						/* More than 6 months ago - "April nineteenth two thousand three" */
    						res = ast_say_date_with_format_en(chan, time, ints, lang, "BdY", timezone);
    
    				res = ast_say_date_with_format_en(chan, time, ints, lang, "HM", timezone);
    
    				break;
    			case 'S':
    				/* Seconds */
    				if (tm.tm_sec == 0) {
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else if (tm.tm_sec < 10) {
    					res = wait_file(chan,ints, "digits/oh",lang);
    					if (!res) {
    						snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
    						res = wait_file(chan,ints,nextmsg,lang);
    					}
    				} else {
    
    					res = ast_say_number(chan, tm.tm_sec, ints, lang, (char *) NULL);
    
    				res = ast_say_date_with_format_en(chan, time, ints, lang, "HMS", timezone);
    
    				break;
    			case ' ':
    			case '	':
    				/* Just ignore spaces and tabs */
    				break;
    			default:
    				/* Unknown character */
    				ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
    		}
    		/* Jump out on DTMF */
    		if (res) {
    			break;
    		}
    	}
    	return res;
    }
    
    
    /* Danish syntax */
    int ast_say_date_with_format_da(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const 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 'm':
    				/* Month enumerated */
    				res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, "m");	
    				break;
    			case 'd':
    			case 'e':
    				/* First - Thirtyfirst */
    				res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, "m");	
    				break;
    			case 'Y':
    				/* Year */
    				{
    					int year = tm.tm_year + 1900;
    					if (year > 1999) {	/* year 2000 and later */
    						res = ast_say_number(chan, year, ints, lang, (char *) NULL);	
    					} else {
    						if (year < 1100) {
    							/* I'm not going to handle 1100 and prior */
    							/* We'll just be silent on the year, instead of bombing out. */
    						} else {
    						    /* year 1100 to 1999. will anybody need this?!? */
    						    /* say 1967 as 'nineteen hundred seven and sixty' */
    							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (year / 100) );
    							res = wait_file(chan,ints,nextmsg,lang);
    							if (!res) {
    								res = wait_file(chan,ints, "digits/hundred",lang);
    								if (!res && year % 100 != 0) {
    									res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);	
    								}
    							}
    						}
    					}
    				}
    				break;
    			case 'I':
    			case 'l':
    				/* 12-Hour */
    				res = wait_file(chan,ints,"digits/oclock",lang);
    				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);
    				if (!res) {
    					res = wait_file(chan,ints,nextmsg,lang);
    				}
    				break;
    			case 'H':
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    				/* 24-Hour, single digit hours preceeded by "oh" (0) */
    				if (tm.tm_hour < 10 && tm.tm_hour > 0) {
    					res = wait_file(chan,ints, "digits/0",lang);
    				}
    				/* FALLTRHU */
    
    			case 'k':
    				/* 24-Hour */
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    				res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL);	
    
    				break;
    			case 'M':
    				/* Minute */
    				if (tm.tm_min > 0 || format[offset+ 1 ] == 'S' ) { /* zero 'digits/0' only if seconds follow (kind of a hack) */
    					res = ast_say_number(chan, tm.tm_min, ints, lang, "f");	
    				}
    				if ( !res && format[offset + 1] == 'S' ) { /* minutes only if seconds follow (kind of a hack) */
    					if (tm.tm_min == 1) {
    						res = wait_file(chan,ints,"digits/minute",lang);
    					} else {
    						res = wait_file(chan,ints,"digits/minutes",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;
    			case 'Q':
    				/* Shorthand for "Today", "Yesterday", or AdBY */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    						res = wait_file(chan,ints, "digits/today",lang);
    					} else if (beg_today - 86400 < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    					} else {
    						res = ast_say_date_with_format(chan, time, ints, lang, "AdBY", timezone);
    					}
    				}
    				break;
    			case 'q':
    				/* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    					} else if ((beg_today - 86400) < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    					} else if (beg_today - 86400 * 6 < time) {
    						/* Within the last week */
    						res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
    					} else {
    						res = ast_say_date_with_format(chan, time, ints, lang, "AdBY", timezone);
    					}
    				}
    				break;
    			case 'R':
    				res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
    				break;
    			case 'S':
    				/* Seconds */
    				res = wait_file(chan,ints, "digits/and",lang);
    				if (!res) {
    					res = ast_say_number(chan, tm.tm_sec, ints, lang, "f");	
    					if (!res) {
    						res = wait_file(chan,ints, "digits/seconds",lang);
    					}
    				}
    				break;
    			case 'T':
    				res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
    				break;
    			case ' ':
    			case '	':
    				/* Just ignore spaces and tabs */
    				break;
    			default:
    				/* Unknown character */
    				ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
    		}
    		/* Jump out on DTMF */
    		if (res) {
    			break;
    		}
    	}
    	return res;
    }
    
    
    /* German syntax */
    int ast_say_date_with_format_de(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const 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 'm':
    				/* Month enumerated */
    				res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, "m");	
    				break;
    			case 'd':
    			case 'e':
    				/* First - Thirtyfirst */
    				res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, "m");	
    				break;
    			case 'Y':
    				/* Year */
    				{
    					int year = tm.tm_year + 1900;
    					if (year > 1999) {	/* year 2000 and later */
    						res = ast_say_number(chan, year, ints, lang, (char *) NULL);	
    					} else {
    						if (year < 1100) {
    							/* I'm not going to handle 1100 and prior */
    							/* We'll just be silent on the year, instead of bombing out. */
    						} else {
    						    /* year 1100 to 1999. will anybody need this?!? */
    
    						    /* say 1967 as 'neunzehn hundert sieben und sechzig' */
    
    							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (year / 100) );
    							res = wait_file(chan,ints,nextmsg,lang);
    							if (!res) {
    								res = wait_file(chan,ints, "digits/hundred",lang);
    								if (!res && year % 100 != 0) {
    									res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);	
    								}
    							}
    						}
    					}
    				}
    				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);
    				if (!res) {
    					res = wait_file(chan,ints,"digits/oclock",lang);
    				}
    				break;
    			case 'H':
    			case 'k':
    				/* 24-Hour */
    				res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL);	
    				if (!res) {
    					res = wait_file(chan,ints,"digits/oclock",lang);
    				}
    				break;
    			case 'M':
    				/* Minute */
    				if (tm.tm_min > 0 || format[offset+ 1 ] == 'S' ) { /* zero 'digits/0' only if seconds follow (kind of a hack) */
    					res = ast_say_number(chan, tm.tm_min, ints, lang, "f");	
    				}
    				if ( !res && format[offset + 1] == 'S' ) { /* minutes only if seconds follow (kind of a hack) */
    					if (tm.tm_min == 1) {
    						res = wait_file(chan,ints,"digits/minute",lang);
    					} else {
    						res = wait_file(chan,ints,"digits/minutes",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;
    			case 'Q':
    				/* Shorthand for "Today", "Yesterday", or AdBY */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    						res = wait_file(chan,ints, "digits/today",lang);
    					} else if (beg_today - 86400 < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    					} else {
    						res = ast_say_date_with_format(chan, time, ints, lang, "AdBY", timezone);
    					}
    				}
    				break;
    			case 'q':
    				/* Shorthand for "" (today), "Yesterday", A (weekday), or AdBY */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    					} else if ((beg_today - 86400) < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    					} else if (beg_today - 86400 * 6 < time) {
    						/* Within the last week */
    						res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
    					} else {
    						res = ast_say_date_with_format(chan, time, ints, lang, "AdBY", timezone);
    					}
    				}
    				break;
    			case 'R':
    				res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
    				break;
    			case 'S':
    				/* Seconds */
    				res = wait_file(chan,ints, "digits/and",lang);
    				if (!res) {
    					res = ast_say_number(chan, tm.tm_sec, ints, lang, "f");	
    					if (!res) {
    						res = wait_file(chan,ints, "digits/seconds",lang);
    					}
    				}
    				break;
    			case 'T':
    				res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
    				break;
    			case ' ':
    			case '	':
    				/* Just ignore spaces and tabs */
    				break;
    			default:
    				/* Unknown character */
    				ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
    		}
    		/* Jump out on DTMF */
    		if (res) {
    			break;
    		}
    	}
    	return res;
    }
    
    
    /* TODO: this probably is not the correct format for doxygen remarks */
    
    /** ast_say_date_with_format_he Say formmated date in Hebrew
     *
    
     * \ref ast_say_date_with_format_en for the details of the options 
    
     *
     * Changes from the English version: 
     *
     * * don't replicate in here the logic of ast_say_number_full_he
     *
     * * year is always 4-digit (because it's simpler)
     *
     * * added c, x, and X. Mainly for my tests
     *
     * * The standard "long" format used in Hebrew is AdBY, rather than ABdY
     *
     * TODO: 
     * * A "ha" is missing in the standard date format, before the 'd'.
     * * The numbers of 3000--19000 are not handled well
     **/
    #define IL_DATE_STR "AdBY"
    #define IL_TIME_STR "IMp"
    #define IL_DATE_STR_FULL IL_DATE_STR " 'digits/at' " IL_TIME_STR
    int ast_say_date_with_format_he(struct ast_channel *chan, time_t time, 
        const char *ints, const char *lang, const char *format, 
        const char *timezone)
    {
    	/* TODO: This whole function is cut&paste from 
    	 * ast_say_date_with_format_en . Is that considered acceptable?
    	 **/
    	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': /* Day of the month */
                                    /* I'm not sure exactly what the parameters 
                                     * audiofd and ctrlfd to 
                                     * ast_say_number_full_he mean, but it seems
                                     * safe to pass -1 there. 
                                     *
                                     * At least in one of the pathes :-( 
                                     */
    				res = ast_say_number_full_he(chan, tm.tm_mday,
    					ints, lang, "m", -1, -1
    				);
    				break;
    			case 'Y': /* Year */
    				res = ast_say_number_full_he(chan, tm.tm_year+1900,
    					ints, lang, "f", -1, -1
    				);
    				break;
    			case 'I':
    			case 'l': /* 12-Hour */
    				{
    					int hour = tm.tm_hour;
    					hour = hour%12;
    					if (hour == 0) hour=12;
    				
    					res = ast_say_number_full_he(chan, hour,
    						ints, lang, "f", -1, -1
    					);
    				}
    				break;
    			case 'H':
    			case 'k': /* 24-Hour */
    				/* With 'H' there is an 'oh' after a single-
    				 * digit hour */
    				if ((format[offset] == 'H') && 
    				    (tm.tm_hour <10)&&(tm.tm_hour>0)
    				) { /* e.g. oh-eight */
    					res = wait_file(chan,ints, "digits/oh",lang);
    				}
    				
    				res = ast_say_number_full_he(chan, tm.tm_hour,
    					ints, lang, "f", -1, -1
    				);
    				break;
    			case 'M': /* Minute */
    				res = ast_say_number_full_he(chan, tm.tm_min, 
    					ints, lang,"f", -1, -1
    				);
    				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;
    			case 'Q':
    				/* Shorthand for "Today", "Yesterday", or "date" */
    			case 'q':
    				/* Shorthand for "" (today), "Yesterday", A 
                                     * (weekday), or "date" */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					char todo = format[offset]; /* The letter to format*/
    
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    						if (todo == 'Q') {
    							res = wait_file(chan,
    
    						}
    					} else if (beg_today - 86400 < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    					} else if ((todo != 'Q') &&
    						(beg_today - 86400 * 6 < time))
    					{
    						/* Within the last week */
    
    						res = ast_say_date_with_format_he(chan,
    										  time, ints, lang, 
    										  "A", timezone);
    
    						res = ast_say_date_with_format_he(chan,
    										  time, ints, lang, 
    										  IL_DATE_STR, timezone);
    
    					}
    				}
    				break;
    			case 'R':
    				res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
    				break;
    			case 'S': /* Seconds */
    				res = ast_say_number_full_he(chan, tm.tm_sec,
    					ints, lang, "f", -1, -1
    				);
    				break;
    			case 'T':
    				res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
    				break;
    			/* c, x, and X seem useful for testing. Not sure
                             * if thiey're good for the general public */
                            case 'c':
    				res = ast_say_date_with_format_he(chan, time, 
                                        ints, lang, IL_DATE_STR_FULL, timezone);
    				break;
                            case 'x':
    				res = ast_say_date_with_format_he(chan, time, 
                                        ints, lang, IL_DATE_STR, timezone);
    				break;
                            case 'X': /* Currently not locale-dependent...*/
    				res = ast_say_date_with_format_he(chan, time, 
                                        ints, lang, IL_TIME_STR, timezone);
    				break;
    			case ' ':
    			case '	':
    				/* Just ignore spaces and tabs */
    				break;
    			default:
    				/* Unknown character */
    				ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
    		}
    		/* Jump out on DTMF */
    		if (res) {
    			break;
    		}
    	}
    	return res;
    }
    
    
    
    /* Spanish syntax */
    int ast_say_date_with_format_es(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const 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';
    				snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile);
    				res = wait_file(chan,ints,nextmsg,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 'm':
    				/* First - Twelfth */
    				snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1);
    				res = wait_file(chan,ints,nextmsg,lang);
    				break;
    			case 'd':
    			case 'e':
    				/* First - Thirtyfirst */
    				res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
    				break;
    			case 'Y':
    				/* Year */
    				res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
    				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 */
    
    				res = ast_say_number(chan, tm.tm_hour, ints, lang, NULL);
    
    				break;
    			case 'M':
    				/* Minute */
    				res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);	
    				break;
    			case 'P':
    			case 'p':
    				/* AM/PM */
    				if (tm.tm_hour > 12)
    					res = wait_file(chan, ints, "digits/p-m", lang);
    				else if (tm.tm_hour  && tm.tm_hour < 12)
    					res = wait_file(chan, ints, "digits/a-m", lang);
    
    				break;
    			case 'Q':
    				/* Shorthand for "Today", "Yesterday", or ABdY */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    						res = wait_file(chan,ints, "digits/today",lang);
    					} else if (beg_today - 86400 < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    					} else {
    
    						res = ast_say_date_with_format(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone);
    
    					}
    				}
    				break;
    			case 'q':
    				/* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
    
    				/* XXX As emphasized elsewhere, this should the native way in your
    				 * language to say the date, with changes in what you say, depending
    				 * upon how recent the date is. XXX */
    
    				{
    					struct timeval now;
    					struct tm tmnow;
    					time_t beg_today;
    
    					gettimeofday(&now,NULL);
    					ast_localtime(&now.tv_sec,&tmnow,timezone);
    					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
    					/* In any case, it saves not having to do ast_mktime() */
    					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    					if (beg_today < time) {
    						/* Today */
    
    						res = wait_file(chan,ints, "digits/today",lang);
    
    					} else if ((beg_today - 86400) < time) {
    						/* Yesterday */
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    					} else if (beg_today - 86400 * 6 < time) {
    						/* Within the last week */
    						res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
    					} else {
    
    						res = ast_say_date_with_format(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone);
    
    				res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/y' M", timezone);
    
    				break;
    			case 'S':
    				/* Seconds */
    				if (tm.tm_sec == 0) {
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else if (tm.tm_sec < 10) {
    					res = wait_file(chan,ints, "digits/oh",lang);
    					if (!res) {
    						snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
    						res = wait_file(chan,ints,nextmsg,lang);
    					}
    				} else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else {
    					int ten, one;
    					ten = (tm.tm_sec / 10) * 10;
    					one = (tm.tm_sec % 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 'T':
    				res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
    				break;
    			case ' ':
    			case '	':
    				/* Just ignore spaces and tabs */
    				break;
    			default:
    				/* Unknown character */
    				ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
    		}
    		/* Jump out on DTMF */
    		if (res) {
    			break;
    		}
    	}
    	return res;