CLeanup PBX patch and add localtime stuff for saytime (bug #168)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1506 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer 2003-09-13 20:51:48 +00:00
parent c511b967ed
commit 56f915e783
12 changed files with 2246 additions and 342 deletions

View File

@ -153,12 +153,7 @@ _all: all
all: depend asterisk subdirs
editline/config.h:
@if [ -d editline ]; then \
cd editline && unset CFLAGS LIBS && ./configure ; \
else \
echo "You need to do a cvs update -d not just cvs update"; \
exit 1; \
fi
cd editline && unset CFLAGS LIBS && ./configure ; \
editline/libedit.a: editline/config.h
$(MAKE) -C editline libedit.a
@ -199,8 +194,16 @@ build.h:
./make_build_h
endif
asterisk: editline/libedit.a db1-ast/libdb1.a $(OBJS)
$(CC) $(DEBUG) -o asterisk -rdynamic $(OBJS) $(LIBS) $(LIBEDIT) db1-ast/libdb1.a
stdtime/localtime.o:
@if [ -d stdtime ]; then \
$(MAKE) -C stdtime; \
else \
echo "You need to do a cvs update -d not just cvs update"; \
exit 1; \
fi
asterisk: editline/libedit.a db1-ast/libdb1.a stdtime/localtime.o $(OBJS)
$(CC) $(DEBUG) -o asterisk -rdynamic $(OBJS) $(LIBS) $(LIBEDIT) db1-ast/libdb1.a stdtime/localtime.o
subdirs:
for x in $(SUBDIRS); do $(MAKE) -C $$x || exit 1 ; done
@ -212,6 +215,7 @@ clean:
rm -f ast_expr.c
@if [ -e editline/Makefile ]; then $(MAKE) -C editline clean ; fi
$(MAKE) -C db1-ast clean
$(MAKE) -C stdtime clean
datafiles: all
mkdir -p $(ASTVARLIBDIR)/sounds/digits

View File

@ -106,26 +106,26 @@ static char *synopsis_vm =
"Leave a voicemail message";
static char *descrip_vm =
" VoiceMail([s|u|b]extension[@context]): Leaves voicemail for a given extension (must\n"
"be configured in voicemail.conf). If the extension is preceeded by an 's'"
"then instructions for leaving the message will be skipped. If the extension\n"
"is preceeded by 'u' then the \"unavailable\" message will be played (that is, \n"
"/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists. If the extension\n"
"is preceeded by a 'b' then the the busy message will be played (that is,\n"
"busy instead of unavail). \n"
"Returns -1 on error or mailbox not found, or if the user hangs up. \n"
"Otherwise, it returns 0. \n";
" VoiceMail([s|u|b]extension[@context]): Leaves voicemail for a given\n"
"extension (must be configured in voicemail.conf). If the extension is\n"
"preceded by an 's' then instructions for leaving the message will be\n"
"skipped. If the extension is preceeded by 'u' then the \"unavailable\"\n"
"message will be played (/var/lib/asterisk/sounds/vm/<exten>/unavail) if it\n"
"exists. If the extension is preceeded by a 'b' then the the busy message\n"
"will be played (that is, busy instead of unavail).\n"
"Returns -1 on error or mailbox not found, or if the user hangs up.\n"
"Otherwise, it returns 0.\n";
static char *synopsis_vmain =
"Enter voicemail system";
static char *descrip_vmain =
" VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system for the checking of\n"
"voicemail. The mailbox can be passed as the option, which will stop the\n"
"voicemail system from prompting the user for the mailbox. If the mailbox\n"
"is preceded by 's' then the password check will be skipped. If a context is\n"
"specified, logins are considered in that context only. Returns -1 if\n"
"the user hangs up or 0 otherwise.\n";
" VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system\n"
"for the checking of voicemail. The mailbox can be passed as the option,\n"
"which will stop the voicemail system from prompting the user for the mailbox.\n"
"If the mailbox is preceded by 's' then the password check will be skipped. If\n"
"a context is specified, logins are considered in that context only.\n"
"Returns -1 if the user hangs up or 0 otherwise.\n";
/* Leave a message */
static char *app = "VoiceMail2";
@ -1897,298 +1897,13 @@ static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
return res;
}
static int play_datetime_format(struct ast_channel *chan, time_t time, struct vm_state *vms, struct vm_zone *zone)
{
int d = 0, offset = 0, sndoffset = 0;
char sndfile[256], nextmsg[256];
struct tm tm;
char *tzenv, current_tz[256] = "", *qmark;
tzenv = getenv("TZ");
if (tzenv != NULL)
strncpy(current_tz, tzenv, sizeof(current_tz) - 1);
if (zone->timezone && strcmp(current_tz,zone->timezone)) {
setenv("TZ", zone->timezone, 1);
tzset();
localtime_r(&time, &tm);
if (tzenv != NULL)
setenv("TZ", current_tz, 1);
else
unsetenv("TZ");
} else {
/* No need to change the timezone */
localtime_r(&time, &tm);
}
/* Check for a subexpression */
if ((qmark = index(zone->msg_format, '?'))) {
/* TODO Allow subexpressions - we probably need to implement a parser here. */
}
for (offset=0 ; zone->msg_format[offset] != '\0' ; offset++) {
ast_log(LOG_NOTICE, "Parsing %c in %s\n", zone->msg_format[offset], zone->msg_format);
switch (zone->msg_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 ; zone->msg_format[++offset] != '\'' ; sndoffset++)
sndfile[sndoffset] = zone->msg_format[offset];
sndfile[sndoffset] = '\0';
snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile);
d = wait_file(chan,vms,nextmsg);
break;
case '$':
/* Ooooh, variables and/or expressions */
{
struct vm_zone z;
memcpy(&z,zone,sizeof(struct vm_zone));
pbx_substitute_variables_helper(chan, zone->msg_format + offset, z.msg_format, sizeof(z.msg_format));
d = play_datetime_format(chan, time, vms, &z);
/* Subtract one, so that when the for loop increments, we point at the nil */
offset = strlen(zone->msg_format) - 1;
}
break;
case 'A':
case 'a':
/* Sunday - Saturday */
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "day-%d", tm.tm_wday);
d = wait_file(chan,vms,nextmsg);
break;
case 'B':
case 'b':
case 'h':
/* January - December */
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "mon-%d", tm.tm_mon);
d = wait_file(chan,vms,nextmsg);
break;
case 'd':
case 'e':
/* First - Thirtyfirst */
if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) {
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "h-%d", tm.tm_mday);
d = wait_file(chan,vms,nextmsg);
} else if (tm.tm_mday == 31) {
/* "Thirty" and "first" */
d = wait_file(chan,vms,DIGITS_DIR "30");
if (!d) {
d = wait_file(chan,vms,DIGITS_DIR "h-1");
}
} else {
/* Between 21 and 29 - two sounds */
d = wait_file(chan,vms,DIGITS_DIR "20");
if (!d) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "h-%d", tm.tm_mday - 20);
d = wait_file(chan,vms,nextmsg);
}
}
break;
case 'Y':
/* Year */
if (tm.tm_year > 99) {
d = wait_file(chan,vms,DIGITS_DIR "2");
if (!d) {
d = wait_file(chan,vms,DIGITS_DIR "thousand");
}
if (tm.tm_year > 100) {
if (!d) {
/* This works until the end of 2020 */
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_year - 100);
d = wait_file(chan,vms,nextmsg);
}
}
} 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 {
d = wait_file(chan,vms,DIGITS_DIR "19");
if (!d) {
if (tm.tm_year < 20) {
/* 1901 - 1920 */
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_year);
d = wait_file(chan,vms,nextmsg);
} else {
/* 1921 - 1999 */
int ten, one;
ten = tm.tm_year / 10;
one = tm.tm_year % 10;
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", ten * 10);
d = wait_file(chan,vms,nextmsg);
if (!d) {
if (one != 0) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", one);
d = wait_file(chan,vms,nextmsg);
}
}
}
}
}
}
break;
case 'I':
case 'l':
/* 12-Hour */
if (tm.tm_hour == 0)
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "12");
else if (tm.tm_hour > 12)
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_hour - 12);
else
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_hour);
d = wait_file(chan,vms,nextmsg);
break;
case 'H':
case 'k':
/* 24-Hour */
if (zone->msg_format[offset] == 'H') {
/* e.g. oh-eight */
if (tm.tm_hour < 10) {
d = wait_file(chan,vms,DIGITS_DIR "oh");
}
} else {
/* e.g. eight */
if (tm.tm_hour == 0) {
d = wait_file(chan,vms,DIGITS_DIR "oh");
}
}
if (!d) {
if (tm.tm_hour != 0) {
snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/digits/%d", tm.tm_hour);
d = wait_file(chan,vms,nextmsg);
}
}
break;
case 'M':
/* Minute */
if (tm.tm_min == 0) {
d = wait_file(chan,vms,DIGITS_DIR "oclock");
} else if (tm.tm_min < 10) {
d = wait_file(chan,vms,DIGITS_DIR "oh");
if (!d) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_min);
d = wait_file(chan,vms,nextmsg);
}
} else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_min);
d = wait_file(chan,vms,nextmsg);
} else {
int ten, one;
ten = (tm.tm_min / 10) * 10;
one = (tm.tm_min % 10);
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", ten);
d = wait_file(chan,vms,nextmsg);
if (!d) {
/* Fifty, not fifty-zero */
if (one != 0) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", one);
d = wait_file(chan,vms,nextmsg);
}
}
}
break;
case 'P':
case 'p':
/* AM/PM */
if ((tm.tm_hour == 0) || (tm.tm_hour > 11))
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "p-m");
else
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "a-m");
d = wait_file(chan,vms,nextmsg);
break;
case 'Q':
/* Shorthand for "Today", "Yesterday", or ABdY */
{
struct timeval now;
struct tm tmnow;
time_t beg_today, tnow;
gettimeofday(&now,NULL);
tnow = now.tv_sec;
localtime_r(&tnow,&tmnow);
tmnow.tm_hour = 0;
tmnow.tm_min = 0;
tmnow.tm_sec = 0;
beg_today = mktime(&tmnow);
if (beg_today < time) {
/* Today */
d = wait_file(chan,vms,DIGITS_DIR "today");
} else if (beg_today - 86400 < time) {
/* Yesterday */
d = wait_file(chan,vms,DIGITS_DIR "yesterday");
} else {
struct vm_zone z;
memcpy(&z, zone, sizeof(struct vm_zone));
strcpy(z.msg_format, "ABdY");
d = play_datetime_format(chan, time, vms, &z);
}
}
break;
case 'q':
/* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
{
struct timeval now;
struct tm tmnow;
time_t beg_today, tnow;
gettimeofday(&now,NULL);
tnow = now.tv_sec;
localtime_r(&tnow,&tmnow);
tmnow.tm_hour = 0;
tmnow.tm_min = 0;
tmnow.tm_sec = 0;
beg_today = mktime(&tmnow);
if (beg_today < time) {
/* Today */
} else if (beg_today - 86400 < time) {
/* Yesterday */
d = wait_file(chan,vms,DIGITS_DIR "yesterday");
} else if (beg_today - 86400 * 6 < time) {
/* Within the last week */
struct vm_zone z;
memcpy(&z, zone, sizeof(struct vm_zone));
strcpy(z.msg_format, "A");
d = play_datetime_format(chan, time, vms, &z);
} else {
struct vm_zone z;
memcpy(&z, zone, sizeof(struct vm_zone));
strcpy(z.msg_format, "ABdY");
d = play_datetime_format(chan, time, vms, &z);
}
}
break;
case 'R':
{
struct vm_zone z;
memcpy(&z, zone, sizeof(struct vm_zone));
strcpy(z.msg_format, "HM");
d = play_datetime_format(chan, time, vms, &z);
}
break;
case ' ':
case ' ':
/* Just ignore spaces and tabs */
break;
default:
/* Unknown character */
ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c\n", zone->msg_format, zone->msg_format[offset]);
}
/* Jump out on DTMF */
if (d) {
break;
}
}
return d;
}
static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
{
int res = 0;
char filename[256], *origtime, temp[256];
char filename[256], *origtime;
struct vm_zone *the_zone = NULL;
struct ast_config *msg_cfg;
time_t t, tnow;
struct timeval tv_now;
struct tm time_now, time_then;
time_t t;
long tin;
make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
@ -2229,6 +1944,8 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v
strncpy(the_zone->msg_format, "'vm-received' q 'digits/at' IMp", sizeof(the_zone->msg_format) - 1);
}
/* No internal variable parsing for now, so we'll comment it out for the time being */
#if 0
/* Set the DIFF_* variables */
localtime_r(&t, &time_now);
gettimeofday(&tv_now,NULL);
@ -2243,9 +1960,11 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v
pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
/* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */
res = play_datetime_format(chan, t, vms, the_zone);
#endif
res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
#if 0
pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
#endif
return res;
}

22
include/asterisk/localtime.h Executable file
View File

@ -0,0 +1,22 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Custom localtime functions for multiple timezones
*
* Copyright (C) 2003, Mark Spencer
*
* Tilghman Lesher <tlesher@vcch.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#ifndef _ASTERISK_LOCALTIME_H
#define _ASTERISK_LOCALTIME_H
extern int ast_tzsetwall(void);
extern void ast_tzset(const char *name);
extern struct tm *ast_localtime(const time_t *timep, struct tm *p_tm, const char *zone);
extern time_t ast_mktime(struct tm * const tmp, const char *zone);
#endif

View File

@ -523,6 +523,8 @@ extern void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char
extern void pbx_builtin_clear_globals(void);
extern void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
int ast_extension_patmatch(const char *pattern, const char *data);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

View File

@ -69,6 +69,8 @@ int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang);
int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, char *lang);
int ast_say_date_with_format(struct ast_channel *chan, time_t t, char *ints, char *lang, char *format, char *timezone);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

18
pbx.c
View File

@ -144,8 +144,6 @@ struct ast_hint {
struct ast_hint *next;
};
int ast_extension_patmatch(const char *pattern, const char *data);
static int pbx_builtin_prefix(struct ast_channel *, void *);
static int pbx_builtin_suffix(struct ast_channel *, void *);
static int pbx_builtin_stripmsd(struct ast_channel *, void *);
@ -172,6 +170,7 @@ static int pbx_builtin_saynumber(struct ast_channel *, void *);
static int pbx_builtin_saydigits(struct ast_channel *, void *);
void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
static int ast_extension_patmatch_repeated(const char *pattern, const char *data, const int num);
static struct varshead globals = AST_LIST_HEAD_INITIALIZER(varshead);
@ -522,14 +521,13 @@ char patmatch_group[80] = "";
variables, starting with $1, $2 and so on.
* alternation as in (01|0|99) ("01 or 0 or 99")
*/
int ast_extension_patmatch(const char *pattern, char *data)
int ast_extension_patmatch(const char *pattern, const char *data)
{
int i,border=0;
char *where;
static char prev = '\0';
static char groupdata[80] = "";
static char *group = patmatch_group;
int groupcounter = patmatch_groupcounter;
if (option_debug)
ast_log(LOG_DEBUG, " >>> \"%s\" =~ /%s/\n", data, pattern);
@ -571,7 +569,7 @@ int ast_extension_patmatch(const char *pattern, char *data)
case '{': /* quantifier {n[,m]} */
{
char *comma;
char *comma=NULL;
int cpos;
where=strchr(pattern,'}');
if (where) {
@ -636,11 +634,10 @@ int ast_extension_patmatch(const char *pattern, char *data)
}
prev = *tmp;
if (i >= from || !from) { /* if found */
int l = strlen(groupdata) - strlen(data);
if (option_debug)
ast_log(LOG_DEBUG, " >>>> found '%s' in data '%s' after %d runs\n", group, data, i);
char name[16];
data = data + (i * (strlen(group)- 1)) - 1;
int l = strlen(groupdata) - strlen(data);
/* data = data-i+from-1; */ /* possible failure here! */
if (prev == ')') { /* grouping => capture */
*(group+strlen(group)-1) = '\0';
@ -708,7 +705,7 @@ int ast_extension_patmatch(const char *pattern, char *data)
s = scopy = (char *) malloc(strlen(pattern));
sepcopy = (char *) malloc(strlen(pattern));
strcpy(s,group);
while (sep = strsep(&s,"|")) {
while ((sep = strsep(&s,"|"))) {
strcpy(sepcopy,sep);
strcat(sepcopy,pattern+border+1);
if (option_debug)
@ -737,7 +734,6 @@ int ast_extension_patmatch(const char *pattern, char *data)
return 0;
} else {
if (pattern[1] != '{') { /* capture without quantifiers */
char name[16];
int l = strlen(groupdata) - strlen(data);
groupdata[l-1] = '\0';
*(group+strlen(group)-1) = '\0';
@ -810,7 +806,7 @@ int ast_extension_patmatch(const char *pattern, char *data)
}
/* try exactly num repetitions, from high to from */
int ast_extension_patmatch_repeated(const char *pattern, char *data, const int num)
static int ast_extension_patmatch_repeated(const char *pattern, const char *data, const int num)
{
int i;
ast_log(LOG_DEBUG, " >>> try %d repetitions of '%s' in data '%s'\n", num, pattern, data);
@ -848,7 +844,7 @@ int ast_extension_match(char *pattern, char *data)
static int extension_close(char *pattern, char *data, int needmore)
{
int match;
int match=1;
/* If "data" is longer, it can'be a subset of pattern unless
pattern is a pattern match */
if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))

286
say.c
View File

@ -12,12 +12,21 @@
*/
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <time.h>
#include <asterisk/file.h>
#include <asterisk/channel.h>
#include <asterisk/logger.h>
#include <asterisk/say.h>
#include <asterisk/lock.h>
#include <asterisk/localtime.h>
#include "asterisk.h"
#include <stdio.h>
#define DIGITS_DIR AST_SOUNDS "/digits/"
int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
{
/* XXX Merge with full version? XXX */
@ -105,14 +114,14 @@ int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *lan
playh++;
num -= ((num / 100) * 100);
} else {
if (num < 1000000) {
if (num < 1000000) { /* 1,000,000 */
res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd);
if (res)
return res;
num = num % 1000;
snprintf(fn, sizeof(fn), "digits/thousand");
} else {
if (num < 1000000000) {
if (num < 1000000000) { /* 1,000,000,000 */
res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd);
if (res)
return res;
@ -204,11 +213,7 @@ int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
struct tm tm;
char fn[256];
int res = 0;
localtime_r(&t,&tm);
if (!&tm) {
ast_log(LOG_WARNING, "Unable to derive local time\n");
return -1;
}
ast_localtime(&t,&tm,NULL);
if (!res) {
snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
res = ast_streamfile(chan, fn, lang);
@ -231,16 +236,267 @@ int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
return res;
}
static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang)
{
int res;
if ((res = ast_streamfile(chan, file, lang)))
ast_log(LOG_WARNING, "Unable to play message %s\n", file);
if (!res)
res = ast_waitstream(chan, ints);
return res;
}
int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
{
struct tm tm;
int res=0, offset, sndoffset;
char sndfile[256], nextmsg[256];
ast_log(LOG_DEBUG, "ast_say_date_with_format() called\n");
ast_localtime(&time,&tm,timezone);
ast_log(LOG_DEBUG, "ast_localtime() returned\n");
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), AST_SOUNDS "/%s", sndfile);
res = wait_file(chan,ints,nextmsg,lang);
break;
case 'A':
case 'a':
/* Sunday - Saturday */
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "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_DIR "mon-%d", tm.tm_mon);
res = wait_file(chan,ints,nextmsg,lang);
break;
case 'd':
case 'e':
/* First - Thirtyfirst */
if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) {
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "h-%d", tm.tm_mday);
res = wait_file(chan,ints,nextmsg,lang);
} else if (tm.tm_mday == 31) {
/* "Thirty" and "first" */
res = wait_file(chan,ints,DIGITS_DIR "30",lang);
if (!res) {
res = wait_file(chan,ints,DIGITS_DIR "h-1",lang);
}
} else {
/* Between 21 and 29 - two sounds */
res = wait_file(chan,ints,DIGITS_DIR "20",lang);
if (!res) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "h-%d", tm.tm_mday - 20);
res = wait_file(chan,ints,nextmsg,lang);
}
}
break;
case 'Y':
/* Year */
if (tm.tm_year > 99) {
res = wait_file(chan,ints,DIGITS_DIR "2",lang);
if (!res) {
res = wait_file(chan,ints,DIGITS_DIR "thousand",lang);
}
if (tm.tm_year > 100) {
if (!res) {
/* This works until the end of 2020 */
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%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_DIR "19",lang);
if (!res) {
if (tm.tm_year <= 9) {
/* 1901 - 1909 */
res = wait_file(chan,ints,DIGITS_DIR "oh",lang);
if (!res) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_year);
res = wait_file(chan,ints,nextmsg,lang);
}
} else if (tm.tm_year <= 20) {
/* 1910 - 1920 */
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%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_DIR "%d", ten * 10);
res = wait_file(chan,ints,nextmsg,lang);
if (!res) {
if (one != 0) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%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_DIR "12");
else if (tm.tm_hour > 12)
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_hour - 12);
else
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%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_DIR "oh",lang);
}
} else {
/* e.g. eight */
if (tm.tm_hour == 0) {
res = wait_file(chan,ints,DIGITS_DIR "oh",lang);
}
}
if (!res) {
if (tm.tm_hour != 0) {
snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/digits/%d", tm.tm_hour);
res = wait_file(chan,ints,nextmsg,lang);
}
}
break;
case 'M':
/* Minute */
if (tm.tm_min == 0) {
res = wait_file(chan,ints,DIGITS_DIR "oclock",lang);
} else if (tm.tm_min < 10) {
res = wait_file(chan,ints,DIGITS_DIR "oh",lang);
if (!res) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_min);
res = wait_file(chan,ints,nextmsg,lang);
}
} else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_min);
res = wait_file(chan,ints,nextmsg,lang);
} else {
int ten, one;
ten = (tm.tm_min / 10) * 10;
one = (tm.tm_min % 10);
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", ten);
res = wait_file(chan,ints,nextmsg,lang);
if (!res) {
/* Fifty, not fifty-zero */
if (one != 0) {
snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", one);
res = wait_file(chan,ints,nextmsg,lang);
}
}
}
break;
case 'P':
case 'p':
/* AM/PM */
if ((tm.tm_hour == 0) || (tm.tm_hour > 11))
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "p-m");
else
snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "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_DIR "today",lang);
} else if (beg_today - 86400 < time) {
/* Yesterday */
res = wait_file(chan,ints,DIGITS_DIR "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;
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_DIR "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 ' ':
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_time(struct ast_channel *chan, time_t t, char *ints, char *lang)
{
struct tm tm;
int res = 0;
int hour, pm=0;
localtime_r(&t,&tm);
if (!&tm) {
ast_log(LOG_WARNING, "Unable to derive local time\n");
return -1;
}
hour = tm.tm_hour;
if (!hour)
hour = 12;
@ -288,10 +544,6 @@ int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang)
int res = 0;
int hour, pm=0;
localtime_r(&t,&tm);
if (!&tm) {
ast_log(LOG_WARNING, "Unable to derive local time\n");
return -1;
}
if (!res) {
snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
res = ast_streamfile(chan, fn, lang);
@ -361,10 +613,6 @@ int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, ch
time(&nowt);
localtime_r(&t,&tm);
if (!&tm) {
ast_log(LOG_WARNING, "Unable to derive local time\n");
return -1;
}
localtime_r(&nowt,&now);
daydiff = now.tm_yday - tm.tm_yday;
if ((daydiff < 0) || (daydiff > 6)) {

19
stdtime/Makefile Executable file
View File

@ -0,0 +1,19 @@
CC=gcc
#CFLAGS=-Wall
INCLUDE=-I../include
all: localtime.o
clean::
rm -f localtime.o test
depend::
@echo "Nothing to do for depend"
test: test.c
${CC} ${CFLAGS} -o test test.c
localtime.o: localtime.c

1462
stdtime/localtime.c Executable file

File diff suppressed because it is too large Load Diff

220
stdtime/private.h Executable file
View File

@ -0,0 +1,220 @@
/* $FreeBSD: src/lib/libc/stdtime/private.h,v 1.6.8.1 2000/08/23 00:19:15 jhb Exp $ */
#ifndef PRIVATE_H
#define PRIVATE_H
/*
** This file is in the public domain, so clarified as of
** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
*/
/* Stuff moved from Makefile.inc to reduce clutter */
#ifndef TM_GMTOFF
#define TM_GMTOFF tm_gmtoff
#define TM_ZONE tm_zone
#define STD_INSPIRED 1
#define PCTS 1
#define HAVE_LONG_DOUBLE 1
#define HAVE_STRERROR 1
#define HAVE_UNISTD_H 1
#define LOCALE_HOME _PATH_LOCALE
#define TZDIR "/usr/share/zoneinfo"
#endif /* ndef TM_GMTOFF */
/*
** This header is for use ONLY with the time conversion code.
** There is no guarantee that it will remain unchanged,
** or that it will remain at all.
** Do NOT copy it to any system include directory.
** Thank you!
*/
/*
** ID
*/
#ifndef lint
#ifndef NOID
/*
static char privatehid[] = "@(#)private.h 7.43";
*/
#endif /* !defined NOID */
#endif /* !defined lint */
/*
** Defaults for preprocessor symbols.
** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
*/
#ifndef HAVE_ADJTIME
#define HAVE_ADJTIME 1
#endif /* !defined HAVE_ADJTIME */
#ifndef HAVE_GETTEXT
#define HAVE_GETTEXT 0
#endif /* !defined HAVE_GETTEXT */
#ifndef HAVE_SETTIMEOFDAY
#define HAVE_SETTIMEOFDAY 3
#endif /* !defined HAVE_SETTIMEOFDAY */
#ifndef HAVE_STRERROR
#define HAVE_STRERROR 0
#endif /* !defined HAVE_STRERROR */
#ifndef HAVE_UNISTD_H
#define HAVE_UNISTD_H 1
#endif /* !defined HAVE_UNISTD_H */
#ifndef HAVE_UTMPX_H
#define HAVE_UTMPX_H 0
#endif /* !defined HAVE_UTMPX_H */
#ifndef LOCALE_HOME
#define LOCALE_HOME "/usr/lib/locale"
#endif /* !defined LOCALE_HOME */
/*
** Nested includes
*/
#include "sys/types.h" /* for time_t */
#include "stdio.h"
#include "errno.h"
#include "string.h"
#include "limits.h" /* for CHAR_BIT */
#include "time.h"
#include "stdlib.h"
#if HAVE_GETTEXT - 0
#include "libintl.h"
#endif /* HAVE_GETTEXT - 0 */
#if HAVE_UNISTD_H - 0
#include "unistd.h" /* for F_OK and R_OK */
#endif /* HAVE_UNISTD_H - 0 */
#if !(HAVE_UNISTD_H - 0)
#ifndef F_OK
#define F_OK 0
#endif /* !defined F_OK */
#ifndef R_OK
#define R_OK 4
#endif /* !defined R_OK */
#endif /* !(HAVE_UNISTD_H - 0) */
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
/*
** Workarounds for compilers/systems.
*/
#ifndef P
#ifdef __STDC__
#define P(x) x
#endif /* defined __STDC__ */
#ifndef __STDC__
#define P(x) ()
#endif /* !defined __STDC__ */
#endif /* !defined P */
/*
** SunOS 4.1.1 headers lack FILENAME_MAX.
*/
#ifndef FILENAME_MAX
#ifndef MAXPATHLEN
#ifdef unix
#include "sys/param.h"
#endif /* defined unix */
#endif /* !defined MAXPATHLEN */
#ifdef MAXPATHLEN
#define FILENAME_MAX MAXPATHLEN
#endif /* defined MAXPATHLEN */
#ifndef MAXPATHLEN
#define FILENAME_MAX 1024 /* Pure guesswork */
#endif /* !defined MAXPATHLEN */
#endif /* !defined FILENAME_MAX */
/*
** Finally, some convenience items.
*/
#ifndef TRUE
#define TRUE 1
#endif /* !defined TRUE */
#ifndef FALSE
#define FALSE 0
#endif /* !defined FALSE */
#ifndef TYPE_BIT
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
#endif /* !defined TYPE_BIT */
#ifndef TYPE_SIGNED
#define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */
#ifndef INT_STRLEN_MAXIMUM
/*
** 302 / 1000 is log10(2.0) rounded up.
** Subtract one for the sign bit if the type is signed;
** add one for integer division truncation;
** add one more for a minus sign if the type is signed.
*/
#define INT_STRLEN_MAXIMUM(type) \
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
#endif /* !defined INT_STRLEN_MAXIMUM */
/*
** INITIALIZE(x)
*/
#ifndef GNUC_or_lint
#ifdef lint
#define GNUC_or_lint
#endif /* defined lint */
#ifndef lint
#ifdef __GNUC__
#define GNUC_or_lint
#endif /* defined __GNUC__ */
#endif /* !defined lint */
#endif /* !defined GNUC_or_lint */
#ifndef INITIALIZE
#ifdef GNUC_or_lint
#define INITIALIZE(x) ((x) = 0)
#endif /* defined GNUC_or_lint */
#ifndef GNUC_or_lint
#define INITIALIZE(x)
#endif /* !defined GNUC_or_lint */
#endif /* !defined INITIALIZE */
/*
** For the benefit of GNU folk...
** `_(MSGID)' uses the current locale's message library string for MSGID.
** The default is to use gettext if available, and use MSGID otherwise.
*/
#ifndef _
#if HAVE_GETTEXT - 0
#define _(msgid) gettext(msgid)
#else /* !(HAVE_GETTEXT - 0) */
#define _(msgid) msgid
#endif /* !(HAVE_GETTEXT - 0) */
#endif /* !defined _ */
#ifndef TZ_DOMAIN
#define TZ_DOMAIN "tz"
#endif /* !defined TZ_DOMAIN */
/*
** UNIX was a registered trademark of UNIX System Laboratories in 1993.
*/
#endif /* !defined PRIVATE_H */

20
stdtime/test.c Executable file
View File

@ -0,0 +1,20 @@
/* Testing localtime functionality */
#include "localtime.c"
#include <sys/time.h>
#include <stdio.h>
int main(int argc, char **argv) {
struct timeval tv;
struct tm tm;
char *zone[4] = { "America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles" };
int i;
gettimeofday(&tv,NULL);
for (i=0;i<4;i++) {
ast_localtime(&tv.tv_sec,&tm,zone[i]);
printf("Localtime at %s is %04d/%02d/%02d %02d:%02d:%02d\n",zone[i],tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
return 0;
}

190
stdtime/tzfile.h Executable file
View File

@ -0,0 +1,190 @@
#ifndef TZFILE_H
#define TZFILE_H
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
*/
/*
** This header is for use ONLY with the time conversion code.
** There is no guarantee that it will remain unchanged,
** or that it will remain at all.
** Do NOT copy it to any system include directory.
** Thank you!
*/
/*
** ID
*/
#ifndef lint
#ifndef NOID
/*
static char tzfilehid[] = "@(#)tzfile.h 7.14";
*/
#endif /* !defined NOID */
#endif /* !defined lint */
/*
** Information about time zone files.
*/
#ifndef TZDIR
#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
#endif /* !defined TZDIR */
#ifndef TZDEFAULT
#define TZDEFAULT "/etc/localtime"
#endif /* !defined TZDEFAULT */
#ifndef TZDEFRULES
#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
/*
** Each file begins with. . .
*/
#define TZ_MAGIC "TZif"
struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_reserved[16]; /* reserved for future use */
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */
char tzh_typecnt[4]; /* coded number of local time types */
char tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*
** . . .followed by. . .
**
** tzh_timecnt (char [4])s coded transition times a la time(2)
** tzh_timecnt (unsigned char)s types of local time starting at above
** tzh_typecnt repetitions of
** one (char [4]) coded UTC offset in seconds
** one (unsigned char) used to set tm_isdst
** one (unsigned char) that's an abbreviation list index
** tzh_charcnt (char)s '\0'-terminated zone abbreviations
** tzh_leapcnt repetitions of
** one (char [4]) coded leap second transition times
** one (char [4]) total correction after above
** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
** time is standard time, if FALSE,
** transition time is wall clock time
** if absent, transition times are
** assumed to be wall clock time
** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
** time is UTC, if FALSE,
** transition time is local time
** if absent, transition times are
** assumed to be local time
*/
/*
** In the current implementation, "tzset()" refuses to deal with files that
** exceed any of the limits below.
*/
#ifndef TZ_MAX_TIMES
/*
** The TZ_MAX_TIMES value below is enough to handle a bit more than a
** year's worth of solar time (corrected daily to the nearest second) or
** 138 years of Pacific Presidential Election time
** (where there are three time zone transitions every fourth year).
*/
#define TZ_MAX_TIMES 370
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
#ifndef NOSOLAR
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
#endif /* !defined NOSOLAR */
#ifdef NOSOLAR
/*
** Must be at least 14 for Europe/Riga as of Jan 12 1995,
** as noted by Earl Chew <earl@hpato.aus.hp.com>.
*/
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
#endif /* !defined NOSOLAR */
#endif /* !defined TZ_MAX_TYPES */
#ifndef TZ_MAX_CHARS
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
/* (limited by what unsigned chars can hold) */
#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
#endif /* !defined TZ_MAX_LEAPS */
#define SECSPERMIN 60
#define MINSPERHOUR 60
#define HOURSPERDAY 24
#define DAYSPERWEEK 7
#define DAYSPERNYEAR 365
#define DAYSPERLYEAR 366
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
#define MONSPERYEAR 12
#define TM_SUNDAY 0
#define TM_MONDAY 1
#define TM_TUESDAY 2
#define TM_WEDNESDAY 3
#define TM_THURSDAY 4
#define TM_FRIDAY 5
#define TM_SATURDAY 6
#define TM_JANUARY 0
#define TM_FEBRUARY 1
#define TM_MARCH 2
#define TM_APRIL 3
#define TM_MAY 4
#define TM_JUNE 5
#define TM_JULY 6
#define TM_AUGUST 7
#define TM_SEPTEMBER 8
#define TM_OCTOBER 9
#define TM_NOVEMBER 10
#define TM_DECEMBER 11
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
/*
** Accurate only for the past couple of centuries;
** that will probably do.
*/
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
#ifndef USG
/*
** Use of the underscored variants may cause problems if you move your code to
** certain System-V-based systems; for maximum portability, use the
** underscore-free variants. The underscored variants are provided for
** backward compatibility only; they may disappear from future versions of
** this file.
*/
#define SECS_PER_MIN SECSPERMIN
#define MINS_PER_HOUR MINSPERHOUR
#define HOURS_PER_DAY HOURSPERDAY
#define DAYS_PER_WEEK DAYSPERWEEK
#define DAYS_PER_NYEAR DAYSPERNYEAR
#define DAYS_PER_LYEAR DAYSPERLYEAR
#define SECS_PER_HOUR SECSPERHOUR
#define SECS_PER_DAY SECSPERDAY
#define MONS_PER_YEAR MONSPERYEAR
#endif /* !defined USG */
#endif /* !defined TZFILE_H */