Skip to content
Snippets Groups Projects
say.c 187 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			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;
    }
    
    
    /* French syntax 
    oclock = heure
    */
    int ast_say_date_with_format_fr(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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    				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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    				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;
    
    Mark Spencer's avatar
    Mark Spencer committed
    					snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday);
    
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else {
    
    					res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
    
    					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) {
    							res = ast_say_number(chan, tm.tm_year - 100, 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. */
    					} else {
    
    						res = wait_file(chan,ints, "digits/thousand",lang);
    
    							wait_file(chan,ints, "digits/9",lang);
    							wait_file(chan,ints, "digits/hundred",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);
    
    				if (!res)
    					res = wait_file(chan,ints, "digits/oclock",lang);
    
    				res = ast_say_number(chan, tm.tm_hour, ints, lang, (char * ) NULL);
    
    					if (format[offset] == 'H') {
    						res = wait_file(chan,ints, "digits/oclock",lang);
    
    				if (!res)
    					res = wait_file(chan,ints, "digits/oclock",lang);
    
    				if (tm.tm_min == 0) {
    					break;
    				}
    				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 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 */
    
    					/* 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 = tt - (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);
    
    				/* 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 */
    
    					/* 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 = tt - (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 = ast_say_number(chan, tm.tm_hour, ints, lang, (char * ) NULL);
    				if (!res) {
    					res = wait_file(chan,ints, "digits/second",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;
    }
    
    
    int ast_say_date_with_format_it(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] = '\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':
    				/* First - Twelfth */
    				snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mon +1);
    				res = wait_file(chan,ints,nextmsg,lang);
    				break;
    
    				/* First day of the month is spelled as ordinal */
    				if (tm.tm_mday == 1) {
    					snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday);
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else {
    					if (!res) {
    						res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
    					}
    				}
    
    				if (tm.tm_year > 99) {
    					res = wait_file(chan,ints, "digits/ore-2000",lang);
    					if (tm.tm_year > 100) {
    						if (!res) {
    						/* This works until the end of 2021 */
    						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/ore-1900",lang);
    						if ((!res) && (tm.tm_year != 0)) {
    							if (tm.tm_year <= 21) {
    								/* 1910 - 1921 */
    								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
    								res = wait_file(chan,ints,nextmsg,lang);
    							} else {
    								/* 1922 - 1999, but sounds badly in 1928, 1931, 1938, etc... */
    								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 (tm.tm_hour == 0) {
    					res = wait_file(chan,ints, "digits/ore-mezzanotte",lang);
    				} else if (tm.tm_hour == 1) {
    					res = wait_file(chan,ints, "digits/ore-una",lang);
    				} else {
    					res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL);
    				}
    
    				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 */
    
    					gettimeofday(&now,NULL);
    					tt = now.tv_sec;
    					ast_localtime(&tt,&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 = tt - (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, "AdB", timezone);
    
    					}
    				}
    				break;
    			case 'q':
    				/* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
    				{
    					struct timeval now;
    					struct tm tmnow;
    
    					gettimeofday(&now,NULL);
    
    					/* 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 = tt - (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, "AdB", timezone);
    
    				res = ast_say_date_with_format(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 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);
    						}
    					}
    				}
    
    			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;
    }
    
    /* Dutch syntax */
    
    int ast_say_date_with_format_nl(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':
    				/* 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, NULL);
    				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 */
    				res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL);
    				if (!res) {
    					res = wait_file(chan,ints, "digits/nl-uur",lang);
    				}
    				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 > 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 */
    
    					/* 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 = tt - (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, "ABdY", timezone);
    					}
    				}
    				break;
    			case 'q':
    				/* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
    				{
    					struct timeval now;
    					struct tm tmnow;
    
    					/* 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 = tt - (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, "ABdY", timezone);
    					}
    				}
    				break;
    			case 'R':
    				res = ast_say_date_with_format(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 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;
    }
    
    /* Portuguese syntax */
    
    int ast_say_date_with_format_pt(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);
    
    				if (tm.tm_hour == 0) {
    					if (format[offset] == 'I')
    						res = wait_file(chan, ints, "digits/pt-ah", lang);
    					if (!res)
    						res = wait_file(chan, ints, "digits/pt-meianoite", lang);
    				}
    				else if (tm.tm_hour == 12) {
    					if (format[offset] == 'I')
    						res = wait_file(chan, ints, "digits/pt-ao", lang);
    					if (!res)
    						res = wait_file(chan, ints, "digits/pt-meiodia", lang);
    				}
    				else {
    					if (format[offset] == 'I') {
    						res = wait_file(chan, ints, "digits/pt-ah", lang);
    						if ((tm.tm_hour % 12) != 1)
    							if (!res)
    								res = wait_file(chan, ints, "digits/pt-sss", lang);
    					}
    					if (!res)
    						res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f");
    				}
    
    				res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL);
    
    				if (!res) {
    					if (tm.tm_hour != 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    						int remainder = tm.tm_hour;
    						if (tm.tm_hour > 20) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    							res = wait_file(chan,ints, "digits/20",lang);
    
    Mark Spencer's avatar
    Mark Spencer committed
    							remainder -= 20;
    						}
    						if (!res) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
    
    Mark Spencer's avatar
    Mark Spencer committed
    							res = wait_file(chan,ints,nextmsg,lang);
    						}
    
    					}
    				}
    				break;
    			case 'M':
    				/* Minute */
    				if (tm.tm_min == 0) {
    
    					res = wait_file(chan, ints, "digits/pt-hora", lang);
    					if (tm.tm_hour != 1)
    						if (!res)
    							res = wait_file(chan, ints, "digits/pt-sss", lang);			} else {
    					res = wait_file(chan,ints,"digits/pt-e",lang);
    					if (!res)
    						res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);	
    
    				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 */
    
    					/* 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 = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    
    					if (beg_today < time) {
    						/* Today */
    
    Mark Spencer's avatar
    Mark Spencer committed
    						res = wait_file(chan,ints, "digits/today",lang);
    
    					} else if (beg_today - 86400 < time) {
    						/* Yesterday */
    
    Mark Spencer's avatar
    Mark Spencer committed
    						res = wait_file(chan,ints, "digits/yesterday",lang);
    
    						res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-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 */
    
    					/* 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 = tt - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
    
    					if (beg_today < time) {
    						/* Today */
    					} else if ((beg_today - 86400) < time) {
    						/* Yesterday */
    
    Mark Spencer's avatar
    Mark Spencer committed
    						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, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone);
    
    				res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/pt-e' M", timezone);
    
    			case 'S':
    				/* Seconds */
    				if (tm.tm_sec == 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
    
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else if (tm.tm_sec < 10) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    					res = wait_file(chan,ints, "digits/oh",lang);
    
    					if (!res) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    						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)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    					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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
    
    					res = wait_file(chan,ints,nextmsg,lang);
    					if (!res) {
    						/* Fifty, not fifty-zero */
    						if (one != 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    							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;
    }
    
    
    /* Taiwanese / Chinese syntax */
    
    int ast_say_date_with_format_tw(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':
    				/* 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 */
    				if (!(tm.tm_mday % 10) || (tm.tm_mday < 10)) {
    					snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday);
    					res = wait_file(chan,ints,nextmsg,lang);
    				} else {
    					snprintf(nextmsg,sizeof(nextmsg), "digits/h-%dh", tm.tm_mday - (tm.tm_mday % 10));
    					res = wait_file(chan,ints,nextmsg,lang);
    					if(!res) {
    						snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday % 10);
    						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) {
    							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (tm.tm_year - 100) / 10);
    							res = wait_file(chan,ints,nextmsg,lang);
    							if (!res) {
    								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", (tm.tm_year - 100) % 10);
    								res = wait_file(chan,ints,nextmsg,lang);
    							}
    						}
    					}
    					if (!res) {
    						res = wait_file(chan,ints, "digits/year",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/1",lang);
    						if (!res) {
    							res = wait_file(chan,ints, "digits/9",lang);
    						}
    						if (!res) {
    							if (tm.tm_year <= 9) {
    								/* 1901 - 1909 */
    								res = wait_file(chan,ints, "digits/0",lang);
    								if (!res) {
    									snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
    									res = wait_file(chan,ints,nextmsg,lang);
    								}
    							} else {
    								/* 1910 - 1999 */
    								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year / 10);
    								res = wait_file(chan,ints,nextmsg,lang);
    								if (!res) {
    									snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year % 10);
    									res = wait_file(chan,ints,nextmsg,lang);
    								}
    							}
    						}
    					}