Skip to content
Snippets Groups Projects
say.c 168 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    	if (!res)
    
    		res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
    
    	hour = tm.tm_hour;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!hour)
    		hour = 12;
    	else if (hour == 12)
    		pm = 1;
    	else if (hour > 12) {
    		hour -= 12;
    		pm = 1;
    	}
    	if (!res)
    
    		res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
    
    	if (tm.tm_min > 9) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!res)
    
    			res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
    
    	} else if (tm.tm_min) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!res)
    			res = ast_streamfile(chan, "digits/oh", lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    		if (!res)
    
    			res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    		if (!res)
    			res = ast_streamfile(chan, "digits/oclock", lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    	}
    	if (pm) {
    		if (!res)
    			res = ast_streamfile(chan, "digits/p-m", lang);
    	} else {
    		if (!res)
    			res = ast_streamfile(chan, "digits/a-m", lang);
    	}
    	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;
    }
    
    
    int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
    
    {
    	struct tm tm;
    	char fn[256];
    	int res = 0;
    	int hour, pm=0;
    	localtime_r(&t,&tm);
    	if (!res)
    		res = ast_say_number(chan, tm.tm_year + 1900, 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_say_number(chan, tm.tm_mday, ints, lang, (char *) 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);
    	}
    
    	hour = tm.tm_hour;
    	if (!hour)
    		hour = 12;
    	else if (hour == 12)
    		pm = 1;
    	else if (hour > 12) {
    		hour -= 12;
    		pm = 1;
    	}
    	if (pm) {
    		if (!res)
    			res = ast_streamfile(chan, "digits/p-m", lang);
    	} else {
    		if (!res)
    			res = ast_streamfile(chan, "digits/a-m", lang);
    	}
    	if (!res)
    		res = ast_waitstream(chan, ints);
    	if (!res)
    		res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
    	if (!res)
    		res = ast_streamfile(chan, "digits/oclock", lang);
    	if (!res)
    		res = ast_waitstream(chan, ints);
    	if (!res)
    		res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
    	if (!res)
    		res = ast_streamfile(chan, "digits/minute", lang);
    	if (!res)
    		res = ast_waitstream(chan, ints);
    	return res;
    }
    
    
    int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
    
    {
    	if (!strcasecmp(lang, "en") ) {	/* English syntax */
    		return(ast_say_datetime_from_now_en(chan, t, ints, lang));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else if (!strcasecmp(lang, "fr") ) {	/* French syntax */
    		return(ast_say_datetime_from_now_fr(chan, t, ints, lang));
    
    	} else if (!strcasecmp(lang, "pt") ) {	/* Portuguese syntax */
    		return(ast_say_datetime_from_now_pt(chan, t, ints, lang));
    
    	}
    
    	/* Default to English */
    	return(ast_say_datetime_from_now_en(chan, t, ints, lang));
    }
    
    /* English syntax */
    
    int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res=0;
    	time_t nowt;
    	int daydiff;
    
    	struct tm tm;
    	struct tm now;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char fn[256];
    
    	time(&nowt);
    
    
    	localtime_r(&t,&tm);
    	localtime_r(&nowt,&now);
    	daydiff = now.tm_yday - tm.tm_yday;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if ((daydiff < 0) || (daydiff > 6)) {
    		/* Day of month and month */
    		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
    
    	} else if (daydiff) {
    		/* Just what day of the week */
    		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);
    		}
    	} /* Otherwise, it was today */
    	if (!res)
    		res = ast_say_time(chan, t, ints, lang);
    	return res;
    }
    
    
    /* French syntax */
    int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
    
    {
    	int res=0;
    	time_t nowt;
    	int daydiff;
    	struct tm tm;
    	struct tm now;
    	char fn[256];
    
    	time(&nowt);
    
    	localtime_r(&t,&tm);
    	localtime_r(&nowt,&now);
    	daydiff = now.tm_yday - tm.tm_yday;
    	if ((daydiff < 0) || (daydiff > 6)) {
    		/* Day of month and month */
    
    		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_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
    
    	} else if (daydiff) {
    		/* Just what day of the week */
    
    		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);
    		}
    	} /* Otherwise, it was today */
    
    	if (!res)
    		res = ast_say_time(chan, t, ints, lang);
    	return res;
    }
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    
    /* Portuguese syntax */
    int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res=0;
    	time_t nowt;
    	int daydiff;
    	struct tm tm;
    	struct tm now;
    	char fn[256];
    
    	time(&nowt);
    
    	localtime_r(&t,&tm);
    	localtime_r(&nowt,&now);
    	daydiff = now.tm_yday - tm.tm_yday;
    	if ((daydiff < 0) || (daydiff > 6)) {
    		/* Day of month and month */
    		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);
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else if (daydiff) {
    		/* Just what day of the week */
    
    		snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
    		if (!res)
    			res = wait_file(chan, ints, fn, lang);
    	}	/* Otherwise, it was today */
    	snprintf(fn, sizeof(fn), "digits/pt-ah");
    	if (!res)
    		res = wait_file(chan, ints, fn, lang);
    	if (tm.tm_hour != 1)
    	if (!res)
    		res = wait_file(chan, ints, "digits/pt-sss", lang);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!res)
    		res = ast_say_time(chan, t, ints, lang);
    	return res;
    }
    
    
    
    /*********************************** GREEK SUPPORT ***************************************/
    
    
    /*
     * digits/female-[1..4] : "Mia, dyo , treis, tessereis"
     */
    static int gr_say_number_female(int num, struct ast_channel *chan, const char *ints, const char *lang){
    	int tmp;
    	int left;
    	int res;
    	char fn[256] = "";
    
    
    	/* ast_log(LOG_DEBUG, "\n\n Saying number female %s %d \n\n",lang, num); */
    
    5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657
    	if (num < 5) {
    		snprintf(fn, sizeof(fn), "digits/female-%d", num);
    		res = wait_file(chan, ints, fn, lang);
    	} else if (num < 13) {
    		res = ast_say_number(chan, num, ints, lang, (char *) NULL);
    	} else if (num <100 ) { 
    		tmp = (num/10) * 10;
    		left = num - tmp;
    		snprintf(fn, sizeof(fn), "digits/%d", tmp);
    		res = ast_streamfile(chan, fn, lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    		if (left)
    			gr_say_number_female(left, chan, ints, lang);
    			
    	} else {
    		return -1;
    	}
    	return res;
    }
    
    
    
    /*
     *  	A list of the files that you need to create
     ->  	digits/xilia = "xilia"
     ->  	digits/myrio = "ekatomyrio"
     ->  	digits/thousands = "xiliades"
     ->  	digits/millions = "ektatomyria"
     ->  	digits/[1..12]   :: A pronunciation of th digits form 1 to 12 e.g. "tria"
     ->  	digits/[10..100]  :: A pronunciation of the tens from 10 to 90 
    															 e,g 80 = "ogdonta" 
    						 Here we must note that we use digits/tens/100 to utter "ekato"
    						 and digits/hundred-100 to utter "ekaton"
     ->  	digits/hundred-[100...1000] :: A pronunciation of  hundreds from 100 to 1000 e.g 400 = 
    																		 "terakosia". Here again we use hundreds/1000 for "xilia" 
    						 and digits/thousnds for "xiliades"
    */
    
    static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char *ints, const char *language,int audiofd, int ctrlfd)
    {
    	int res = 0;
    	char fn[256] = "";
    	int i=0;
    
     
    	if (!num) {
    		snprintf(fn, sizeof(fn), "digits/0");
    		res = ast_streamfile(chan, fn, chan->language);
    		if (!res)
    			return  ast_waitstream(chan, ints);
    	}
    
    	while(!res && num ) {
    		i++;
    		if (num < 13) {
    			snprintf(fn, sizeof(fn), "digits/%d", num);
    			num = 0;
    		} else if (num <= 100) {
    			/* 13 < num <= 100  */
    			snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
    			num -= ((num / 10) * 10); 
    		} else if (num < 200) {
    			/* 100 < num < 200 */
    			snprintf(fn, sizeof(fn), "digits/hundred-100");
    			num -= ((num / 100) * 100);
    		}else if (num < 1000) {
    			/* 200 < num < 1000 */
    			snprintf(fn, sizeof(fn), "digits/hundred-%d", (num/100)*100);
    			num -= ((num / 100) * 100);
    		}else if (num < 2000){
    			snprintf(fn, sizeof(fn), "digits/xilia");
    			num -= ((num / 1000) * 1000);
    		}
    		else {
    			/* num >  1000 */ 
    			if (num < 1000000) {
    				res = ast_say_number_full_gr(chan, (num / 1000), ints, chan->language, audiofd, ctrlfd);
    				if (res)
    					return res;
    				num = num % 1000;
    				snprintf(fn, sizeof(fn), "digits/thousands");
    			}  else {
    				if (num < 1000000000) { /* 1,000,000,000 */
    					res = ast_say_number_full_gr(chan, (num / 1000000), ints, chan->language ,audiofd, ctrlfd);
    					if (res)
    						return res;
    					num = num % 1000000;
    					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 > -1) && (ctrlfd > -1))
    					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
    				else
    					res = ast_waitstream(chan, ints);
    			}
    			ast_stopstream(chan);
    		}
    	}
    	return res;
    }
    
    
    /*
     * The format is  weekday - day - month -year
     * 
     * A list of the files that you need to create
     * digits/day-[1..7]  : "Deytera .. Paraskeyh"
     * digits/months/1..12 : "Ianouariou .. Dekembriou"  
    													Attention the months are in 
    				"gekinh klhsh"
     */
    
    
    static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
    {
    	struct tm tm;
    	
    	char fn[256];
    	int res = 0;
    	
    
    	ast_localtime(&t,&tm,NULL);
    	/* W E E K - D A Y */
    	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);
    	}
    	/* D A Y */
    	if (!res) {
    		gr_say_number_female(tm.tm_mday, chan, ints, lang);
    	}
    	/* M O N T H */
    	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);
    	}
    	/* Y E A R */
    	if (!res)
    		res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
    	return res; 
    }
    
    
     
    /* A list of the files that you need to create
     * digits/female/1..4 : "Mia, dyo , treis, tesseris "
     * digits/kai : "KAI"
     * didgits : "h wra"
     * digits/p-m : "meta meshmbrias" 
     * digits/a-m : "pro meshmbrias"
     */
    
    static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
    {
    
    	struct tm tm;
    	int res = 0;
    	int hour, pm=0;
    
    	localtime_r(&t,&tm);
    	hour = tm.tm_hour;
    
    	if (!hour)
    		hour = 12;
    	else if (hour == 12)
    		pm = 1;
    	else if (hour > 12) {
    		hour -= 12;
    		pm = 1;
    	}
     
    	res = gr_say_number_female(hour, chan, ints, lang);
    	if (tm.tm_min) {
    		if (!res)
    			res = ast_streamfile(chan, "digits/kai", lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    		if (!res)
    			res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
    	} else {
    		if (!res)
    			res = ast_streamfile(chan, "digits/hwra", lang);
    		if (!res)
    			res = ast_waitstream(chan, ints);
    	}
    	if (pm) {
    		if (!res)
    			res = ast_streamfile(chan, "digits/p-m", lang);
    	} else {
    		if (!res)
    			res = ast_streamfile(chan, "digits/a-m", lang);
    	}
    	if (!res)
    		res = ast_waitstream(chan, ints);
    	return res;
    }
    
    
    
    static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
    {
    	struct tm tm;
    	char fn[256];
    	int res = 0;
    	localtime_r(&t,&tm);
    
    	
    	/* W E E K - D A Y */
    	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);
    	}
    	/* D A Y */
    	if (!res) {
    		gr_say_number_female(tm.tm_mday, chan, ints, lang);
    	}
    	/* M O N T H */
    	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);
    	}
    
    	res = ast_say_time_gr(chan, t, ints, lang);
    	return res;
    }
    
    static int ast_say_date_with_format_gr(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 'd':
    		case 'e':
    			/* first - thirtyfirst */
    			gr_say_number_female(tm.tm_mday, chan, ints, lang);
    			break;
    		case 'Y':
    			/* Year */
    			
    			ast_say_number_full_gr(chan, 1900+tm.tm_year, ints, chan->language, -1, -1);
    			break;
    		case 'I':
    		case 'l':
    			/* 12-Hour */
    			if (tm.tm_hour == 0)
    				gr_say_number_female(12, chan, ints, lang);
    			else if (tm.tm_hour > 12)
    				gr_say_number_female(tm.tm_hour - 12, chan, ints, lang);
    			else
    				gr_say_number_female(tm.tm_hour, chan, ints, lang);
    			break;
    		case 'H':
    		case 'k':
    			/* 24-Hour */
    			gr_say_number_female(tm.tm_hour, chan, ints, lang);
    			break;
    		case 'M':
    			/* Minute */
    			if (tm.tm_min) {
    				if (!res)
    					res = ast_streamfile(chan, "digits/kai", lang);
    				if (!res)
    					res = ast_waitstream(chan, ints);
    				if (!res)
    					res = ast_say_number_full_gr(chan, tm.tm_min, ints, lang, -1, -1);
    			} else {
    				if (!res)
    					res = ast_streamfile(chan, "digits/oclock", lang);
    				if (!res)
    					res = ast_waitstream(chan, ints);
    			}
    			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 */
    			{
    				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 ABdY */
    			{
    				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 */
    			snprintf(nextmsg,sizeof(nextmsg), "digits/kai");
    			res = wait_file(chan,ints,nextmsg,lang);
    			if (!res)
    				res = ast_say_number_full_gr(chan, tm.tm_sec, ints, lang, -1, -1);
    			if (!res)
    				snprintf(nextmsg,sizeof(nextmsg), "digits/seconds");
    			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;
    }