isdn4k-utils/isdnlog/isdnrep/opt_time.c

485 lines
13 KiB
C

/* $Id: opt_time.c,v 1.2 2005/01/22 18:47:16 tobiasb Exp $
*
* ISDN accounting for isdn4linux. (Report-module)
* Time options parsing. (Seperated from isdnrep.c 1.96)
*
* Copyright 1995 .. 2000 by Andreas Kool (akool@isdn4linux.de)
* and Stefan Luethje (luethje@sl-gw.lake.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Copyright 1994, Steven Grimm <koreth@hyperion.com>.
*
*
* $Log: opt_time.c,v $
* Revision 1.2 2005/01/22 18:47:16 tobiasb
* New: "isdnrep -t y" for calls of yesterday.
* Added some more verifications in the processing of isdnrep's -t option.
*
* Revision 1.1 2003/10/29 17:41:35 tobiasb
* isdnlog-4.67:
* - Enhancements for isdnrep:
* - New option -r for recomputing the connection fees with the rates
* from the current (and for a different or the cheapest provider).
* - Revised output format of summaries at end of report.
* - New format parameters %j, %v, and %V.
* - 2 new input formats for -t option.
* - Fix for dualmode workaround 0x100 to ensure that incoming calls
* will not become outgoing calls if a CALL_PROCEEDING message with
* an B channel confirmation is sent by a terminal prior to CONNECT.
* - Fixed and enhanced t: Tag handling in pp_rate.
* - Fixed typo in interface description of tools/rate.c
* - Fixed typo in tools/isdnrate.man, found by Paul Slootman.
* - Minor update to sample isdn.conf files:
* - Default isdnrep format shows numbers with 16 chars (+ & 15 digits).
* - New isdnrep format (-FNIO) without display of transfered bytes.
* - EUR as currency in Austria, may clash with outdated rate-at.dat.
* The number left of the currency symbol is nowadays insignificant.
* - Changes checked in earlier but after step to isdnlog-4.66:
* - New option for isdnrate: `-rvNN' requires a vbn starting with NN.
* - Do not compute the zone with empty strings (areacodes) as input.
* - New ratefile tags r: und t: which need an enhanced pp_rate.
* For a tag description see rate-files(5).
* - Some new and a few updated international cellphone destinations.
*
* NOTE: If there any questions, problems, or problems regarding isdnlog,
* feel free to join the isdn4linux mailinglist, see
* https://www.isdn4linux.de/mailman/listinfo/isdn4linux for details,
* or send a mail in English or German to <tobiasb@isdn4linux.de>.
*
*/
#define _OPT_TIME_C_
/* allow standalone binary for testing */
/* build with
gcc -g -DTEST_OPT_TIME -o opt_time opt_time.c
*/
#ifdef TEST_OPT_TIME
#include <stdio.h>
#include <string.h>
#include <time.h>
#define UNKNOWN (-1)
#define min(x,y) ((x) < (y) ? (x) : (y))
char *Strncpy(char *dest, const char *src, int len);
#else
#include "isdnrep.h"
#endif
#define END_TIME 1
#define S_YESTERDAY "y" /* character(s) for the yesterday time specification */
/*****************************************************************************/
static time_t get_month(char *String, int TimeStatus);
static time_t get_time(char *String, int TimeStatus);
static time_t get_gertime(char *s, int TimeStatus);
static time_t get_ytime(time_t *base, int back, int TimeStatus);
static time_t get_itime(char *s, int TimeStatus);
/*****************************************************************************/
/* parse time option, a return value of 0 means failure. */
int get_term (char *String, time_t *Begin, time_t *End,int delentries)
{
time_t now;
time_t Date[2];
int Cnt;
char DateStr[2][256] = {"",""};
int idate = 0;
char sep[3] = { '-', 0, 0 };
int sep_l = 1;
char *p;
time(&now);
if (tolower(String[0])=='i' || strstr(String,"--")) {
String += tolower(String[0])=='i';
sep[1] = sep[0];
sep_l++;
idate++;
}
if ( (p=strstr(String, sep)) )
{
if (String != p) /* ...<sep> */
Strncpy(DateStr[0], String, min(p-String+1,256));
if (*(p+sep_l)) /* <sep>... */
Strncpy(DateStr[1], p+sep_l, 256);
}
else
{
Strncpy(DateStr[0], String, 256);
Strncpy(DateStr[1], String, 256);
}
for (Cnt = 0; Cnt < 2; Cnt++)
{
int DateLen = strlen(DateStr[Cnt]);
if (strspn(DateStr[Cnt], S_YESTERDAY) == DateLen)
Date[Cnt] = get_ytime(&now, DateLen, delentries?0:Cnt);
else if ( strspn(DateStr[Cnt], idate ? "01234567890T:-" : "01234567890/.")
!= DateLen )
return 0;
else if (idate)
Date[Cnt] = get_itime(DateStr[Cnt],delentries?0:Cnt);
else if ( (p=strchr(DateStr[Cnt],'.')) && strchr(p+1,'.') )
Date[Cnt] = get_gertime(DateStr[Cnt],delentries?0:Cnt);
else if (strchr(DateStr[Cnt],'/'))
Date[Cnt] = get_month(DateStr[Cnt],delentries?0:Cnt);
else
Date[Cnt] = get_time(DateStr[Cnt],delentries?0:Cnt);
}
*Begin = DateStr[0][0] == '\0' ? 0 : Date[0];
*End = DateStr[1][0] == '\0' || !Date[1] ? now : Date[1];
if (*Begin > *End)
return 0;
return 1;
}
/*****************************************************************************/
/* parse a date like [DD/][M]M/[[YY]YY] */
static time_t get_month(char *String, int TimeStatus)
{
time_t now;
int Cnt = 0;
struct tm *TimeStruct;
int Args[3];
int ArgCnt;
time(&now);
if ( !(TimeStruct = localtime(&now)) )
return 0;
TimeStruct->tm_sec = 0;
TimeStruct->tm_min = 0;
TimeStruct->tm_hour= 0;
TimeStruct->tm_mday= 1;
TimeStruct->tm_isdst= UNKNOWN;
ArgCnt = sscanf(String,"%d/%d/%d",&(Args[0]),&(Args[1]),&(Args[2]));
switch (ArgCnt)
{
case 3:
TimeStruct->tm_mday = Args[0];
Cnt++;
case 2:
/* if (Args[Cnt+1] > 99) */
if (Args[Cnt+1] >= 1900)
TimeStruct->tm_year = ((Args[Cnt+1] / 100) - 19) * 100 + (Args[Cnt+1]%100);
else
if (Args[Cnt+1] < 70)
TimeStruct->tm_year = Args[Cnt+1] + 100;
else
TimeStruct->tm_year = Args[Cnt+1];
case 1:
TimeStruct->tm_mon = Args[Cnt];
break;
default:
return 0;
}
if (TimeStatus == END_TIME)
{
if (ArgCnt == 3) /* Wenn Tag angegeben ist */
{
TimeStruct->tm_mday++;
TimeStruct->tm_mon--;
}
}
else
TimeStruct->tm_mon--;
return mktime(TimeStruct);
}
/*****************************************************************************/
/* parse a date like [MM]DD[hhmm[[CC]YY][.ss]] */
static time_t get_time(char *String, int TimeStatus)
{
time_t now;
int Len = 0;
int Year;
char *Ptr;
struct tm *TimeStruct;
time(&now);
if ( !(TimeStruct = localtime(&now)) )
return 0;
TimeStruct->tm_sec = 0;
TimeStruct->tm_min = 0;
TimeStruct->tm_hour= 0;
TimeStruct->tm_isdst= UNKNOWN;
switch (strlen(String))
{
case 0:
return 0;
case 1:
case 2:
TimeStruct->tm_mday = atoi(String);
break;
default:
Len = strlen(String);
if ((Ptr = strchr(String,'.')) != NULL)
{
TimeStruct->tm_sec = atoi(Ptr+1);
Len -= strlen(Ptr);
}
if (Len % 2)
return 0;
if (sscanf(String,"%2d%2d%2d%2d%d",
&(TimeStruct->tm_mon),
&(TimeStruct->tm_mday),
&(TimeStruct->tm_hour),
&(TimeStruct->tm_min),
&Year ) > 4) {
/* if (Year > 99) */
if (Year >= 1900)
TimeStruct->tm_year = ((Year / 100) - 19) * 100 + (Year%100);
else {
if (Year < 70)
TimeStruct->tm_year = Year + 100;
else
TimeStruct->tm_year = Year;
}
}
TimeStruct->tm_mon--;
break;
}
if (TimeStatus == END_TIME) {
if (TimeStruct->tm_sec == 0 &&
TimeStruct->tm_min == 0 &&
TimeStruct->tm_hour== 0 )
TimeStruct->tm_mday++;
else {
if (TimeStruct->tm_sec == 0 &&
TimeStruct->tm_min == 0 )
TimeStruct->tm_hour++;
else {
if (TimeStruct->tm_sec == 0 )
TimeStruct->tm_min++;
else
TimeStruct->tm_sec++;
}
}
}
return mktime(TimeStruct);
}
/*****************************************************************************/
/* parse a date like [D]D.[M]M.[[CC][Y]Y] */
static time_t get_gertime(char *s, int TimeStatus)
{
/* convert to CCYY-MM-DD and give it to get_itime */
char t[10+1], *sm, *sy;
int day, month, year;
if (strlen(s)>10 || strlen(s)<4)
return 0;
sm = strchr(s,'.') + 1;
sy = strchr(sm,'.') + 1;
if ( *sy )
year = atoi(sy); /* (century and) year from input */
else { /* get current year */
time_t now;
struct tm *tm;
time(&now);
if ( !(tm = localtime(&now)) )
return 0;
year = tm->tm_year+1900;
}
month = atoi(sm);
day = atoi(s);
if (year>9999 || month>12 || day>31)
return 0;
/* expansion of two digit year value takes place in get_itime */
sprintf(t, "%02d-%02d-%02d", year, month, day);
return get_itime(t, TimeStatus);
}
/*****************************************************************************/
/* parse a date like y[y[y...]] where each y(esterday) goes back one day. */
static time_t get_ytime(time_t *base, int back, int TimeStatus) {
struct tm *tm;
time_t yesterday = *base - 24*60*60 * back;
char t[10+1];
tm = localtime(&yesterday);
if (tm == NULL || tm->tm_year > 9999 - 1900 || tm->tm_mon > 12 - 1
|| tm->tm_mday > 31)
return 0;
sprintf(t, "%04d-%02d-%02d", 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday);
return get_itime(t, TimeStatus);
}
/*****************************************************************************/
/* parse a date like CCYY[-]MM[-]DD["T"]hh[:]mm[:]ss */
static time_t get_itime(char *s, int TimeStatus)
{
time_t now, offset=0;
struct tm *t;
char *p;
char a[5];
int i[6];
int n;
time(&now);
if ( !(t = localtime(&now)) )
return 0;
t->tm_isdst = UNKNOWN;
p = s;
if (strlen(s)<4) /* at least CCYY or YY-MM */
return 0;
p = s;
if ( !( isdigit(p[0]) && isdigit(p[1]) ) )
return 0;
if (p[2] == '-') { /* YY- */
Strncpy(a, p, 2+1);
i[0] = atoi(a);
i[0] += ((t->tm_year+1900)/100)*100; /* add current century */
p += 2;
}
else { /* CCYY */
if ( !( isdigit(p[2]) && isdigit(p[3]) ) )
return 0;
Strncpy(a, p, 4+1);
i[0] = atoi(a);
p += 4;
}
for (n=1; n<6; n++) /* MM DD hh mm ss */
{ /* 1 2 3 4 5 */
if (*p == ( n<3 ? '-' : (n<4 ? 'T' : ':') ) )
p++;
if (! *p)
break;
if ( !( isdigit(p[0]) && isdigit(p[1]) ) )
return 0;
Strncpy(a, p, 2+1);
i[n] = atoi(a);
p += 2;
}
t->tm_year = i[0] - 1900;
if (n==2 && TimeStatus==END_TIME && i[1] == 12)
n = 1; /* --2003-12 => --2003 */
if (n==1 && TimeStatus==END_TIME) /* --2003 => --2003-12-31T23:59:59 */
{
TimeStatus = 0; /* 1) => --2003-01-01T00:00:00 */
t->tm_year++; /* 2) => --2004-01-01T00:00:00 */
offset = -1; /* 3) => --2003-12-31T23:59:59 */
}
t->tm_mon = (n>1) ? i[1]-1 : 0;
if (n==2 && TimeStatus==END_TIME) /* --2000-02 => --2000-02-29T23:59:59 */
{
TimeStatus = 0; /* 1) => --2000-02-01T00:00:00 */
t->tm_mon++; /* 2) => --2000-03-01T00:00:00 */
offset = -1; /* 3) => --2000-02-29T23:59:59 */
}
t->tm_mday = (n>2) ? i[2] : 1;
t->tm_hour = (n>3) ? i[3] : ( (TimeStatus==END_TIME) ? 23 : 0);
t->tm_min = (n>4) ? i[4] : ( (TimeStatus==END_TIME) ? 59 : 0);
t->tm_sec = (n>5) ? i[5] : ( (TimeStatus==END_TIME) ? 59 : 0);
return mktime(t)+offset;
}
/*****************************************************************************/
#ifdef TEST_OPT_TIME
/* taken from ../../lib/libtools.c */
char *Strncpy(char *dest, const char *src, int len)
{
int l = strlen(src);
if (l > len - 1)
l = len - 1;
strncpy(dest,src,l);
dest[l] = '\0';
return dest;
}
#define STIME(z) a=localtime(&z); strftime(s, BUFSIZ, "%Y-%m-%d %H:%M:%S", a);
int main(int argc, char *argv[], char *envp[])
{
int delentries = 0, res;
time_t begintime, endtime, now;
struct tm *a;
char s[BUFSIZ];
time(&now);
STIME(now)
printf("Testing get_term (parses isdnrep's -t option)\n"
"Enter . to quit, d to switch delentries.\n"
"Any other input will be parsed as option value\n"
"Current time: %s\n", s);
while(1)
{
fgets(s, BUFSIZ, stdin);
s[strlen(s)-1]=0;
if (s[0] == '.' && s[1] == 0)
break;
else if (s[0] == 'd' && s[1] == 0) {
delentries = !delentries;
continue;
}
res = get_term (s, &begintime, &endtime, delentries);
if (res) {
STIME(begintime)
printf("OK: %s -- ", s);
STIME(endtime)
printf("%s (delentries=%d)\n", s, delentries);
}
else
printf("ERR\n");
}
return 0;
}
#undef STIME
#endif
/*****************************************************************************/
/* vim:set ts=2: */
/*****************************************************************************/