isdn4k-utils/isdnlog/isdnrep/isdnrep.c

4121 lines
110 KiB
C
Raw Permalink Blame History

/* $Id: isdnrep.c,v 1.104 2007/01/05 04:23:58 tobiasb Exp $
*
* ISDN accounting for isdn4linux. (Report-module)
*
* 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.
*
* functions htoi() and url_unescape():
* Copyright 1994, Steven Grimm <koreth@hyperion.com>.
*
*
* $Log: isdnrep.c,v $
* Revision 1.104 2007/01/05 04:23:58 tobiasb
* Made isdnrep and isdnrate buildable under cygwin. See ChangeLog for details.
*
* Revision 1.103 2006/07/03 15:51:27 keil
* - HZ is not used anymore, this value is defined as duration in
* 1/100 seconds independ from system HZ value
*
* Revision 1.102 2004/12/16 21:30:50 tobiasb
* New option -U: default source number for outgoing calls.
*
* Revision 1.101 2004/07/25 14:21:13 tobiasb
* New isdnrep option -m [*|/]number. It multiplies or divide the cost of
* each call by the given number. `-m/1.16' for example displays the costs
* without the German `Umsatzsteuer'.
*
* Revision 1.100 2004/07/24 17:58:06 tobiasb
* New isdnrep options: `-L:' controls the displayed call summaries in the
* report footer. `-x' displays only call selected or not deselected by
* hour or type of day -- may be useful in conjunction with `-r'.
*
* Activated new configuration file entry `REPOPTIONS' for isdnrep default
* options. This options can be disabled by `-c' on the command line.
*
* Revision 1.99 2004/02/25 12:09:08 paul
* There was no bounds checking on unknownzones, which is only useds
* if DEBUG is defined. This caused a SIGSEGV with many unknown numbers
* (which were all the same, BTW...) Now only do unknownzones if DEBUG
* is defined.
*
* Revision 1.98 2003/11/14 20:29:29 tobiasb
* Removed SIGSEGV in isdnrep that occurred while fetching zone names for outgoing calls
* from the current ratefile if the matching zone did not contain a name after the zone
* number. This error was introduced with isdnrep-4.65 or rev. 1.96 of isdnrep.c.
* Uwe Furchheim discovered the error and provided sufficient details on the mailinglist
* rates4linux-users, see http://sourceforge.net/mailarchive/forum.php?forum_id=4262
*
* Revision 1.97 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>.
*
* Revision 1.96 2003/07/25 22:18:03 tobiasb
* isdnlog-4.65:
* - New values for isdnlog option -2x / dual=x with enable certain
* workarounds for correct logging in dualmode in case of prior
* errors. See `man isdnlog' and isdnlog/processor.c for details.
* - New isdnlog option -U2 / ignoreCOLP=2 for displaying ignored
* COLP information.
* - Improved handling of incomplete D-channel frames.
* - Increased length of number aliases shown immediately by isdnlog.
* Now 127 instead of 32 chars are possible. (Patch by Jochen Erwied.)
* - The zone number for an outgoing call as defined in the rate-file
* is written to the logfile again and used by isdnrep
* - Improved zone summary of isdnrep. Now the real zone numbers as
* defined in the rate-file are shown. The zone number is taken
* from the logfile as mentioned before or computed from the current
* rate-file. Missmatches are indicated with the chars ~,+ and *,
* isdnrep -v ... explains the meanings.
* - Fixed provider summary of isdnrep. Calls should no longer be
* treated wrongly as done via the default (preselected) provider.
* - Fixed the -pmx command line option of isdnrep, where x is the xth
* defined [MSN].
* - `make install' restarts isdnlog after installing the data files.
* - A new version number generates new binaries.
* - `make clean' removes isdnlog/isdnlog/ilp.o when called with ILP=1.
*
* Revision 1.95 2001/03/21 10:24:01 paul
* Previous patch for correctly deleting entries messed up the printing
* of a specific date (or range), now hopefully fixed. Please test!
* Also replaced usage of tmpnam() with more secure mkstemp().
* Reindented some lines, tabstop of 2 is really strange.
*
* Revision 1.94 2001/02/08 14:04:53 paul
* Fix bug where deleting up to 31/12/99 caused ALL entries to be deleted;
* now the entries being deleted are output (as usual with isdnrep), and
* the rest are preserved in the log.
* Also cleaned up error messages to be a bit more consistent.
*
* Revision 1.93 2000/08/17 21:34:44 akool
* isdnlog-4.40
* - README: explain possibility to open the "outfile=" in Append-Mode with "+"
* - Fixed 2 typos in isdnlog/tools/zone/de - many thanks to
* Tobias Becker <tobias@talypso.de>
* - detect interface (via IIOCNETGPN) _before_ setting CHARGEINT/HUPTIMEOUT
* - isdnlog/isdnlog/processor.c ... fixed wrong init of IIOCNETGPNavailable
* - isdnlog/isdnrep/isdnrep.c ... new option -S summary
* - isdnlog/isdnrep/rep_main.c
* - isdnlog/isdnrep/isdnrep.1.in
* - isdnlog/tools/NEWS
* - isdnlog/tools/cdb/debian ... (NEW dir) copyright and such from orig
* - new "rate-de.dat" from sourceforge (hi and welcome: Who is "roro"?)
*
* Revision 1.92 2000/06/22 16:08:24 keil
* parameter in (...) are allways converted into int
* newer gcc give an error using char here
*
* Revision 1.91 2000/05/27 14:55:30 akool
* isdnlog-4.25
* - isdnlog/isdnrep/isdnrep.c ... bugfix for wrong providers and duration
* by Hans Klein on d.a.c.i
*
* - isdnlog/tools/rate-at.c ... 1046 Neu, 1002 ab 1.6., 1024
* - isdnlog/rate-at.dat ... 1046 Neu, 1002 ab 1.6., 1024
* - new rates 01078:3U and 01024:Super_24
*
* Revision 1.90 2000/03/06 07:03:20 akool
* isdnlog-4.15
* - isdnlog/tools/tools.h ... moved one_call, sum_calls to isdnrep.h
* ==> DO A 'make clean' PLEASE
* - isdnlog/tools/telnum.c ... fixed a small typo
* - isdnlog/isdnrep/rep_main.c ... incl. dest.h
* - isdnlog/isdnrep/isdnrep.c ... fixed %l, %L
* - isdnlog/isdnrep/isdnrep.h ... struct one_call, sum_calls are now here
*
* Support for Norway added. Many thanks to Tore Ferner <torfer@pvv.org>
* - isdnlog/rate-no.dat ... NEW
* - isdnlog/holiday-no.dat ... NEW
* - isdnlog/samples/isdn.conf.no ... NEW
* - isdnlog/samples/rate.conf.no ... NEW
*
* Revision 1.89 2000/02/28 19:53:55 akool
* isdnlog-4.14
* - Patch from Roland Rosenfeld <roland@spinnaker.de> fix for isdnrep
* - isdnlog/tools/rate.c ... epnum
* - isdnlog/tools/rate-at.c ... new rates
* - isdnlog/rate-at.dat
* - isdnlog/tools/rate-files.man ... %.3f
* - doc/Configure.help ... unknown cc
* - isdnlog/configure.in ... unknown cc
* - isdnlog/.Config.in ... unknown cc
* - isdnlog/Makefile.in ... unknown cc
* - isdnlog/tools/dest/Makefile.in ... LANG => DEST_LANG
* - isdnlog/samples/rate.conf.pl ... NEW
* - isdnlog/samples/isdn.conf.pl ... NEW
* - isdnlog/rate-pl.dat ... NEW
* - isdnlog/tools/isdnrate.c ... fixed -P pid_dir, restarts on HUP now
* - isdnlog/tools/isdnrate.man ... SIGHUP documented
*
* Revision 1.88 2000/02/07 20:32:41 akool
* isdnlog-4.09
* - NEW: 01078:3U and 010050:Drillisch foreign countries
* - isdnlog/isdnrep/isdnrep.c ... moved hist, provider ok again
* - isdnlog/isdnrep/CHANGES.isdnrep ... NEW (old changes)
* - isdnlog/isdnlog/isdnlog.8.in ... addded signals
* - isdnlog/README ... upd. core (SIGSEGV), files
*
* Revision 1.87 2000/01/16 12:36:58 akool
* isdnlog-4.03
* - Patch from Gerrit Pape <pape@innominate.de>
* fixes html-output if "-t" option of isdnrep is omitted
* - Patch from Roland Rosenfeld <roland@spinnaker.de>
* fixes "%p" in ILABEL and OLABEL
*
* Revision 1.86 1999/12/31 13:57:18 akool
* isdnlog-4.00 (Millenium-Edition)
* - Oracle support added by Jan Bolt (Jan.Bolt@t-online.de)
* - resolved *any* warnings against rate-de.dat
* - Many new rates
* - CREDITS file added
*
* for older changes please look at CHANGES
*/
#define _REP_FUNC_C_
#include <sys/param.h>
#include <dirent.h>
#include <search.h>
/* included by libisdn.h: #include <linux/limits.h> */
#include <string.h>
#include "dest.h"
#include "isdnrep.h"
#include "../../vbox/src/libvbox.h"
#include "libisdn.h"
#define SET_TIME 1
#define GET_TIME 2
#define GET_DATE 4
#define GET_DATE2 8
#define GET_YEAR 16
/*****************************************************************************/
#define GET_OUT 0
#define GET_IN 1
#define GET_BYTES 0
#define GET_BPS 2
/*****************************************************************************/
#define C_BEGIN_FMT '%'
#define FMT_FMT 1
#define FMT_STR 2
/*****************************************************************************/
#define C_VBOX 'v'
#define C_FAX 'f'
#define F_VBOX 1
#define F_FAX 2
/*****************************************************************************/
#define F_BEGIN 1
#define F_END 2
/*****************************************************************************/
#define DEF_FMT " %X %D %15.15H %T %-15.15F %7u %U %I %O"
#define WWW_FMT "%X %D %17.17H %T %-17.17F %-20.20l SI: %S %9u %U %I %O"
/*****************************************************************************/
#define STR_FAX "Fax: "
/*****************************************************************************/
#define H_ENV_VAR "QUERY_STRING"
/*****************************************************************************/
#define F_1ST_LINE 1
#define F_BODY_HEADER 2
#define F_BODY_HEADERL 4
#define F_BODY_LINE 8
#define F_BODY_BOTTOM1 16
#define F_BODY_BOTTOM2 32
#define F_COUNT_ONLY 64
#define F_TEXT_LINE 128
#define F_TABLE_LINE 256
/*****************************************************************************/
#define H_BG_COLOR "#FFFFFF"
#define H_TABLE_COLOR1 "#CCCCFF"
#define H_TABLE_COLOR2 "#FFCCCC"
#define H_TABLE_COLOR3 "#CCFFCC"
#define H_TABLE_COLOR4 "#FFFFCC"
#define H_TABLE_COLOR5 "#CCFFFF"
#define H_FORM_ON "<FORM METHOD=\"put\" ACTION=\"%s\">"
#define H_FORM_OFF "</FORM>"
#define H_1ST_LINE "<CENTER><FONT size=+1><B>%s</B></FONT><P>\n"
#define H_TEXT_LINE "<CENTER><B>%s</B><P>\n"
#define H_BODY_LINE "<TR>%s</TR>\n"
#define H_BODY_HEADER1 "<TABLE width=%g%% bgcolor=%s border=0 cellspacing=0 cellpadding=0>\n"
#define H_BODY_HEADER2 "<COL width=%d*>\n"
//#define H_BODY_HEADER2 "<COLGROUP span=1 width=%d*>\n"
#define H_BODY_HEADER3 "<TH colspan=%d>%s</TH>\n"
#define H_BODY_BOTTOM1 "<TD align=left colspan=%d>%s</TD>%s\n"
#define H_BODY_BOTTOM2 "</TABLE><P>\n"
#define H_TABLE_LINE "<TR><TD align=left colspan=%d><TT>%s</TT></TD></TR>\n"
#define H_LINE "<TR><TD colspan=%d><HR size=%d noshade width=100%%></TD></TR>\n"
#define H_LEFT "<TD align=left><TT>%s</TT></TD>"
#define H_CENTER "<TD align=center><TT>%s</TT></TD>"
#define H_RIGHT "<TD align=right><TT>%s</TT></TD>"
#define H_LINK "<A HREF=\"%s?-M+%c%d%s\">%s</A>"
#define H_LINK_DAY "<A HREF=\"%s?%s\">%s</A>&nbsp;"
#define H_FORM_DAY "%s<input name=\"%s\" maxlength=%d value=\"\" size=%d><INPUT TYPE=\"submit\" NAME=\"submit\" VALUE=\"go\">"
#define H_EMPTY "&nbsp;"
#define H_APP_ZYXEL2 "application/x-zyxel2"
#define H_APP_ZYXEL3 "application/x-zyxel3"
#define H_APP_ZYXEL4 "application/x-zyxel4"
#define H_APP_ULAW "application/x-ulaw"
#define H_APP_TEXT "text/plain"
#define H_APP_FAX3 "application/x-faxg3"
/*****************************************************************************/
#define UNKNOWNZONE MAXZONES
/*****************************************************************************/
/* flags for zones_src.flags (FZN = flag zone name) */
#define FZN_KNOWN 0x01 /* zone_names[i] is a valid zone name, not ?? */
#define FZN_UNSURE 0x02 /* zone_names[i] may be incorrect */
#define FZN_MPROV 0x04 /* zone i is used with more than one provider */
#define FZN_MNAME 0x08 /* found different names for zone i */
/*****************************************************************************/
/* bits in sel_sums[] for the footer summaries */
#define SUM_IN 0x01
#define SUM_OUT 0x02
#define SUM_INOUT 0x04
#define SUM_ZONE 0x08
#define SUM_PROV 0x10
#define SUM_MSN 0x20
#define SUM_ALL 0x3f
#define SUM__CHARS "ioczpm" /* corresponding chars for option value */
/*****************************************************************************/
/* indices for sel_sums, days, and hours option */
#define INCLUDE 0
#define EXCLUDE 1
#define RESULT 2
/*****************************************************************************/
typedef struct {
int type;
char *string;
char s_type;
char *range;
} prt_fmt;
typedef struct {
int version;
int compression;
int used;
time_t time;
char type;
char *name;
} file_list;
typedef struct {
int flags; /* see FZN_ constants */
int first_prov; /* for detection of FZN_MPROV */
} zones_src_t;
/*****************************************************************************/
static int show_msn(one_call *cur_call);
static int add_sum_calls(sum_calls *s1, sum_calls *s2);
static int print_sum_calls(sum_calls *s, int computed);
static int add_one_call(sum_calls *s1, one_call *s2, double units);
static int clear_sum(sum_calls *s1);
static char *print_currency(double money, int computed);
static void strich(int type);
static int n_match(char *Pattern, char* Number, char* version);
static int set_caller_infos(one_call *cur_call, char *string, time_t from);
static int set_alias(one_call *cur_call, int *nx, char *myname);
static int print_header(int lday);
static int print_entries(one_call *cur_call, double unit, int *nx, char *myname);
static int print_bottom(double unit, char *start, char *stop);
static char *get_time_value(time_t t, int *day, int flag);
static char **string_to_array(char *string);
static prt_fmt** get_format(const char *format);
static char *set_byte_string(int flag, double Bytes);
static int print_line(int status, one_call *cur_call, int computed, char *overlap);
static int print_line2(int status, const char *, ...);
static int print_line3(const char *fmt, ...);
static int append_string(char **string, prt_fmt *fmt_ptr, char* value);
static char *html_conv(char *string);
static int get_format_size(void);
static int set_col_size(void);
static char *overlap_string(char *s1, char *s2);
static char* fill_spaces(char *string);
static void free_format(prt_fmt** ptr);
static int html_bottom(char *progname, char *start, char *stop);
static int html_header(void);
static char *print_diff_date(char *start, char *stop);
static int get_file_list(void);
static int set_dir_entries(char *directory, int (*set_fct)(const char *, const char *));
static int set_vbox_entry(const char *path, const char *file);
static int set_mgetty_entry(const char *path, const char *file);
static int set_element_list(file_list* elem);
static int Compare_files(const void *e1, const void *e2);
static file_list *get_file_to_call(time_t filetime, char type);
static char *get_links(time_t filetime, char type);
static char *append_fax(char **string, char *file, char type, int version);
static int time_in_interval(time_t t1, time_t t2, char type);
static char *nam2html(char *file);
static char *get_a_day(time_t t, int d_diff, int m_diff, int flag);
static char *get_time_string(time_t begin, time_t end, int d_diff, int m_diff);
static char *get_default_html_params(void);
static char *create_vbox_file(char *file, int *compression);
static int htoi(char *s);
static char **get_http_args(char *str, int *index);
static char *url_unescape(char *str);
static int app_fmt_string(char *target, int targetlen, char *fmt, int condition, char *value);
static int find_format_length(char *string);
static int check_day_hour(bitfield *days, bitfield *hours, const time_t check);
/*****************************************************************************/
static int invertnumbers = 0;
static int unknowns = 0;
static UNKNOWNS unknown[MAXUNKNOWN];
static int zones[MAXZONES + 1];
static int zones_usage[MAXZONES + 1];
static char * zones_names[MAXZONES + 1];
static double zones_dm[MAXZONES + 1];
static double zones_dur[MAXZONES + 1];
static zones_src_t
zones_src[MAXZONES +1];
static char** ShowMSN = NULL;
static int* colsize = NULL;
static double h_percent = 100.0;
static char* h_table_color = H_TABLE_COLOR1;
static file_list **file_root = NULL;
static int file_root_size = 0;
static int file_root_member = 0;
static char *_myname;
static time_t _begintime;
static int read_path = 0;
/*****************************************************************************/
static char msg1[] = "isdnrep: can't open %s (%s)\n";
static char wrongdate2[] = "isdnrep: wrong date for delete: %s\n";
static char nomemory[] = "isdnrep: out of memory!\n";
static char htmlconv[][2][10] = {
{">", "&gt;"},
{"<", "&lt;"},
{" ", H_EMPTY},
{"" , ""},
};
/*****************************************************************************/
static int Tarif96 = 0;
static int Tarif962 = 0;
static sum_calls day_sum;
static sum_calls day_com_sum;
static sum_calls all_sum;
static sum_calls all_com_sum;
/*****************************************************************************/
static double *msn_sum;
static int *usage_sum;
static double *dur_sum;
static int usage_provider[MAXPROVIDER];
static int provider_failed[MAXPROVIDER];
static double duration_provider[MAXPROVIDER];
static double pay_provider[MAXPROVIDER];
#if DEBUG
#include <assert.h>
static char unknownzones[4096];
#endif
#undef MAXPROVIDER
#define MAXPROVIDER getNProvider()
/*****************************************************************************/
void info(int chan, int reason, int state, char *msg)
{
/* DUMMY - dont needed here! */
} /* info */
/*****************************************************************************/
int send_html_request(char *myname, char *option)
{
char file[PATH_MAX];
char commandline[PATH_MAX];
char *filetype = NULL;
char *command = NULL;
char *vboxfile = NULL;
int compression;
if (*option == C_VBOX)
{
sprintf(file,"%s%c%s",vboxpath,C_SLASH,option+2);
if (option[1] == '1')
{
if (vboxcommand1)
command = vboxcommand1;
else
filetype = H_APP_ZYXEL4;
}
else
if (option[1] == '2')
{
if (vboxcommand2)
command = vboxcommand2;
else
{
vboxfile = strcpy(file,create_vbox_file(file,&compression));
switch(compression)
{
case 2 : filetype = H_APP_ZYXEL2;
break;
case 3 : filetype = H_APP_ZYXEL3;
break;
case 4 : filetype = H_APP_ZYXEL4;
break;
case 6 : filetype = H_APP_ULAW;
break;
default: printf( "Content-Type: %s\n\n",H_APP_TEXT);
printf( "%s: unsupported compression type of vbox file :`%d'\n",myname,compression);
return(UNKNOWN);
break;
}
}
}
else
{
printf( "Content-Type: %s\n\n",H_APP_TEXT);
printf( "%s: unsupported version of vbox `%c'\n",myname,option[0]);
return(UNKNOWN);
}
}
else
if (*option == C_FAX)
{
sprintf(file,"%s%c%s",mgettypath,C_SLASH,option+2);
if (option[1] == '3')
{
if (mgettycommand)
command = mgettycommand;
else
filetype = H_APP_FAX3;
}
else
{
printf( "Content-Type: %s\n\n",H_APP_TEXT);
printf( "%s:unsupported version of fax `%c%c'\n",myname,option[0],option[1]);
return(UNKNOWN);
}
}
else
{
printf( "Content-Type: %s\n\n",H_APP_TEXT);
printf( "%s:invalid option string `%c%c'\n",myname,option[0],option[1]);
return(UNKNOWN);
}
if (command == NULL)
{
char precmd[SHORT_STRING_SIZE];
sprintf(precmd, "echo \"Content-Type: %s\"",filetype);
system(precmd);
sprintf(precmd, "echo");
system(precmd);
// printf( "Content-Type: %s\n\n",filetype);
}
sprintf(commandline,"%s %s",command?command:"cat",file);
system(commandline);
if (vboxfile)
{
if (unlink(vboxfile))
{
print_msg(PRT_ERR, "isdnrep: can't delete file `%s': %s!\n",file, strerror(errno));
return(UNKNOWN);
}
}
return 0;
}
/*****************************************************************************/
int read_logfile(char *myname)
{
auto double einheit = 0.23;
auto int nx[2];
auto time_t now, from = 0;
auto struct tm *tm;
auto int lday = UNKNOWN;
auto char start[20] = "", stop[20];
auto FILE *fi, *ftmp = NULL;
auto char string[BUFSIZ], s[BUFSIZ];
one_call cur_call;
initHoliday(holifile, NULL);
initDest(destfile, NULL);
initRate(rateconf, ratefile, zonefile, NULL);
interns0 = 3; /* Fixme: */
msn_sum = calloc(mymsns + 1, sizeof(double));
usage_sum = calloc(mymsns + 1, sizeof(int));
dur_sum = calloc(mymsns + 1, sizeof(double));
#if DEBUG
*unknownzones = 0;
#endif
_myname = myname;
_begintime = begintime;
if (html & H_PRINT_HEADER)
html_header();
if (lineformat == NULL)
{
if (html)
lineformat = WWW_FMT;
else
lineformat = DEF_FMT;
}
if (get_format(lineformat) == NULL)
return(UNKNOWN);
/* following two lines must be after get_format()! */
if (html)
get_file_list();
clear_sum(&day_sum);
clear_sum(&day_com_sum);
clear_sum(&all_sum);
clear_sum(&all_com_sum);
if (knowns == 0 || strcmp(known[knowns-1]->who,S_UNKNOWN))
{
if ((known = (KNOWN**) realloc(known, sizeof(KNOWN *) * (knowns+1))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
if ((known[knowns] = (KNOWN*) calloc(1,sizeof(KNOWN))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
known[knowns]->who = S_UNKNOWN;
known[knowns++]->num = "0000";
}
if (recalc.mode && !prep_recalc())
return UNKNOWN; /* error in -r Option, msg by prep_recalc to stdout */
if (delentries)
{
if(begintime)
{
print_msg(PRT_ERR, wrongdate2, timestring);
return(UNKNOWN);
}
else
{
if ((ftmp = tmpfile()) == NULL)
{
print_msg(PRT_ERR, msg1, "tmpfile", strerror(errno));
return(UNKNOWN);
}
}
}
if (!timearea) { /* from darf nicht gesetzt werden, wenn alle Telefonate angezeigt werden sollen */
/* get time of start of today (midnight) */
time(&now);
/* aktuelle Zeit wird gesetzt */
tm = localtime(&now);
/* Zeit von 1970 nach Struktur */
tm->tm_sec = tm->tm_min = tm->tm_hour = 0;
from = mktime(tm);
/* Struktur nach Zeit von 1970 */
/* from hat den aktuellen Tag 0.00 Uhr */
} /* if */
if ((fi = fopen(logfile, "r")) == (FILE *)NULL){
print_msg(PRT_ERR, msg1, logfile, strerror(errno));
return(UNKNOWN);
}
memset(zones_usage, 0, sizeof(zones_usage));
memset(zones_names, 0, sizeof(zones_names));
memset(zones_src, 0, sizeof(zones_src)); /* start with zone names unknown */
while (fgets(s, BUFSIZ, fi)) {
strcpy(string,s);
if (*s == '#')
continue;
/* set_caller_infos() returns UNKNOWN also if outside time range */
/* but if we are deleting, then the line must be copied to tempfile */
/* so no direct "continue;" in that case */
if (set_caller_infos(&cur_call,s,from) == UNKNOWN) {
if (!delentries)
continue;
if (cur_call.t >= endtime) {
/* past end: stop delete, start copying */
fputs(string,ftmp);
continue;
}
}
/* TODO (tobiasb|2004-02): right place for setting begintime?
either verify whether delentries is working or disable/remove it */
if (!print_failed && cur_call.duration == 0)
continue;
if (!begintime)
begintime = cur_call.t;
if (phonenumberonly)
if (!show_msn(&cur_call))
continue;
if (incomingonly && cur_call.dir == DIALOUT)
continue;
if (outgoingonly && cur_call.dir == DIALIN)
continue;
if (check_day_hour(days, hours, cur_call.t))
continue;
get_time_value(cur_call.t,&day,SET_TIME);
/* Andreas, warum ist diese Abfrage hier drin, warum soll das nicht moeglich
sein? */
if (cur_call.duration > 172800.0) /* laenger als 2 Tage? Das KANN nicht sein! */
cur_call.duration = 0;
set_alias(&cur_call,nx,myname);
if (day != lday) {
if (header)
print_header(lday);
lday = day;
if (!*start)
{
sprintf(start, "%s %s", get_time_value(0,NULL,GET_DATE),
get_time_value(0,NULL,GET_YEAR));
sprintf(stop, "%s %s", get_time_value(0,NULL,GET_DATE),
get_time_value(0,NULL,GET_YEAR));
}
else
sprintf(stop, "%s %s", get_time_value(0,NULL,GET_DATE),
get_time_value(0,NULL,GET_YEAR));
} /* if */
if (!cur_call.currency_factor)
einheit = 1.0;
else
einheit = cur_call.currency_factor;
print_entries(&cur_call,einheit,nx,myname);
} /* while */
fclose(fi);
if (delentries) /* Erzeugt neue verkuerzte Datei */
lday = UNKNOWN;
if (lday == UNKNOWN && html)
{
if (begintime == 0)
begintime = time(NULL);
get_time_value(begintime,&lday,SET_TIME);
sprintf(start, "%s %s", get_time_value(0,NULL,GET_DATE),
get_time_value(0,NULL,GET_YEAR));
if (endtime) {
get_time_value(endtime,&lday,SET_TIME);
sprintf(stop, "%s %s", get_time_value(0,NULL,GET_DATE),
get_time_value(0,NULL,GET_YEAR));
}
else {
strcpy(stop, start);
}
print_line2(F_1ST_LINE,"I S D N Connection Report");
print_line2(F_TEXT_LINE,"");
print_line2(F_TEXT_LINE,"no calls from %s to %s", start, stop);
print_line2(F_TEXT_LINE,"");
lday = UNKNOWN;
}
if (lday != UNKNOWN && header)
print_bottom(einheit, start, stop);
if (delentries) /* Erzeugt neue verkuerzte Datei */
{
rewind(ftmp);
if ((fi = fopen(logfile, "w")) == (FILE *)NULL)
{
print_msg(PRT_ERR, msg1, logfile, strerror(errno));
return(UNKNOWN);
}
while (fgets(s, BUFSIZ, ftmp))
fputs(s,fi);
fclose(fi);
fclose(ftmp);
}
if (html & H_PRINT_HEADER)
html_bottom(myname,start,stop);
return 0;
} /* read_logfile */
/*****************************************************************************/
static int print_bottom(double unit, char *start, char *stop)
{
auto char string[BUFSIZ], sx[BUFSIZ];
register int i, j, k;
register char *p = NULL;
sum_calls tmp_sum;
auto double s = 0.0, s2 = 0.0;
auto int s1 = 0;
auto int showIO = 1; /* display inbyte and outbyte */
if (timearea && summary < 2) {
strich(1);
print_sum_calls(&day_sum,0);
if (day_com_sum.eh)
{
print_sum_calls(&day_com_sum,1);
clear_sum(&tmp_sum);
add_sum_calls(&tmp_sum,&day_sum);
add_sum_calls(&tmp_sum,&day_com_sum);
strich(1);
print_sum_calls(&tmp_sum,0);
}
else
printf("\n");
} /* if */
add_sum_calls(&all_sum,&day_sum);
add_sum_calls(&all_com_sum,&day_com_sum);
strich(2);
print_sum_calls(&all_sum,0);
if (bill)
return(0);
if (all_com_sum.eh)
{
print_sum_calls(&all_com_sum,1);
clear_sum(&tmp_sum);
add_sum_calls(&tmp_sum,&all_sum);
add_sum_calls(&tmp_sum,&all_com_sum);
strich(2);
print_sum_calls(&tmp_sum,0);
}
else
printf("\n");
print_line2(F_BODY_BOTTOM2,"");
i = 0;
if (recalc.mode && recalc.unknown)
{
print_line2(F_TEXT_LINE, "Recomputed %d of %d qualified call(s)",
(recalc.count-recalc.unknown), recalc.count);
i++;
}
if (tolower(recalc.mode)=='b' &&
recalc.cheaper != recalc.count- recalc.unknown)
{
print_line2(F_TEXT_LINE, "Found cheaper provider for %d of %d call(s)",
recalc.cheaper, (recalc.count-recalc.unknown));
i++;
}
if (i)
print_line2(F_TEXT_LINE, "");
/* foreign caller summary (out and in) ------------------------------- */
/* strategy for width of summary lines:
* call entry format (-F, -s) with %I or %O ==> summary also
* call entry format longer than 80 chars ==> summary also
* summary header out is 72 chars log, header in 74 chars */
if ( !(strstr(lineformat, "%I") || strstr(lineformat, "%O")) )
showIO = 0;
if ( set_col_size() > 80 )
{
if (showIO)
get_format("%-25.25s %4d call(s) %10.10s %12s %-12s %-12s");
else
get_format("%-36.36s %4d call(s) %10.10s %12s");
}
else
{
if (showIO)
get_format("%-14.14s %4d call(s) %10.10s %12s %-12s %-12s");
else
get_format("%-36.36s %4d call(s) %10.10s %12s");
}
for (j = 0; j < 2; j++)
{
if ( (j == DIALOUT && !incomingonly && sel_sums[RESULT] & SUM_OUT) ||
(j == DIALIN && !outgoingonly && sel_sums[RESULT] & SUM_IN ) )
{
sprintf(string, "%s Summary for %s", (j == DIALOUT) ? "Outgoing calls (calling:)" : "Incoming calls (called by:)",
print_diff_date(start,stop));
h_percent = 80.0;
h_table_color = H_TABLE_COLOR2;
print_line2(F_BODY_HEADER,"");
print_line2(F_BODY_HEADERL,"%s",string);
strich(1);
for (i = 0 ; i < knowns; i++) {
if (known[i]->usage[j]) {
print_line3(NULL,
/*!numbers?*/known[i]->who/*:known[i]->num*/,
known[i]->usage[j],
double2clock(known[i]->dur[j]),
j==DIALOUT?print_currency(known[i]->pay,0):
fill_spaces(print_currency(known[i]->pay,0)),
set_byte_string(GET_IN|GET_BYTES,known[i]->ibytes[j]),
set_byte_string(GET_OUT|GET_BYTES,known[i]->obytes[j]));
/* the last two arguments may be excessive */
} /* if */
} /* for */
print_line2(F_BODY_BOTTOM2,"");
} /* /if show out|in summary */
}
if (sel_sums[RESULT] & SUM_INOUT) {
/* print mixed summary about foreign numbers */
sprintf(string, "Calls (incoming & outgoing) Summary for %s",
print_diff_date(start,stop));
h_percent = 80.0;
h_table_color = H_TABLE_COLOR2;
print_line2(F_BODY_HEADER,"");
print_line2(F_BODY_HEADERL,"%s",string);
strich(1);
for (i = 0 ; i < knowns; i++) {
if (known[i]->usage[DIALIN]||known[i]->usage[DIALOUT]) {
print_line3(NULL,
/*!numbers?*/known[i]->who/*:known[i]->num*/,
known[i]->usage[DIALIN] + known[i]->usage[DIALOUT],
double2clock(known[i]->dur[DIALIN] + known[i]->dur[DIALOUT]),
known[i]->usage[DIALOUT]?print_currency(known[i]->pay,0):
fill_spaces(print_currency(known[i]->pay,0)),
set_byte_string(GET_IN|GET_BYTES,
known[i]->ibytes[DIALIN] + known[i]->ibytes[DIALOUT]),
set_byte_string(GET_OUT|GET_BYTES,
known[i]->obytes[DIALIN] + known[i]->obytes[DIALOUT]) );
/* the last two arguments may be excessive */
} /* if */
} /* for */
print_line2(F_BODY_BOTTOM2,"");
} /* /if show foreign in&out summary */
if (!incomingonly && sel_sums[RESULT] & SUM_ZONE)
{
/* zone summary (outgoing) ----------------------------------------- */
int ztypes = 0;
/* prev.: 60.0 */
h_percent = 70.0;
h_table_color = H_TABLE_COLOR3;
/* prev.: "%-21.21s %4d call(s) %10.10s %12s" */
get_format("%-34.34s %4d call(s) %10.10s %12s");
print_line2(F_BODY_HEADER,"");
/* Fixme: zones are provider-specific
we are summing up zones for all provides here */
print_line2(F_BODY_HEADERL,"Outgoing calls ordered by Zone");
strich(1);
for (i = 0; i < MAXZONES /* + 1 */; i++)
if (zones_usage[i]) {
auto char s[BUFSIZ];
char zinfo=' ';
int *zflags=&(zones_src[i].flags);
if (*zflags & FZN_MNAME) {
zinfo = '*';
ztypes |= FZN_MNAME;
}
else if (*zflags & FZN_MPROV) {
zinfo = '+';
ztypes |= FZN_MPROV;
}
else if (*zflags & FZN_UNSURE) {
zinfo = '~';
ztypes |= FZN_UNSURE;
}
sprintf(s, "Zone %3d:%c%s", i, zinfo, zones_names[i]);
print_line3(NULL, s, zones_usage[i],
double2clock(zones_dur[i]),
print_currency(zones_dm[i], 0));
} /* if */
#if DEBUG
if (zones_usage[UNKNOWNZONE])
printf( "(%s)\n", unknownzones);
#endif
if (verbose && ztypes) { /* explain symbol in front of zone number */
if (ztypes & FZN_UNSURE)
print_line2(F_TABLE_LINE," ~ = Zone name not known for sure");
if (ztypes & FZN_MPROV)
print_line2(F_TABLE_LINE," + = Zone summed over several providers");
if (ztypes & FZN_MNAME)
print_line2(F_TABLE_LINE," * = Zone name differs with provider");
}
print_line2(F_BODY_BOTTOM2,"");
} /* /if show zone summary */
if (!incomingonly && sel_sums[RESULT] & SUM_PROV)
{
/* provider summary (outgoing) ------------------------------------- */
/* prev.: 60.0 */
h_percent = 80.0;
h_table_color = H_TABLE_COLOR4;
/* prev.: "%-8.8s %05s %-25.25s %4d call(s) %10.10s %12s %s" */
get_format("%-8.8s %8.8s %-24.24s %4d call(s) %10.10s %13.13s %-13s");
/* "Prov" vbn provstr no durat. cost ..avail */
/* 80 chars >| */
print_line2(F_BODY_HEADER,"");
print_line2(F_BODY_HEADERL,"Outgoing calls ordered by Provider");
strich(1);
for (i = 0; i < MAXPROVIDER; i++) {
prefix2provider(i, string);
if (usage_provider[i]) {
if (duration_provider[i])
sprintf(sx, "%5.1f%% avail.",
100.0 * (usage_provider[i] - provider_failed[i]) / usage_provider[i]);
else
*sx = 0;
p = getProvider(i);
if (!p || p[strlen(p) - 1] == '?') /* UNKNOWN Provider */
p = "UNKNOWN";
print_line3(NULL, "Provider", string, p,
usage_provider[i],
double2clock(duration_provider[i]),
print_currency(pay_provider[i], 0), sx);
} /* if */
} /* for */
print_line2(F_BODY_BOTTOM2,"");
} /* /if show provider summary */
if (!incomingonly && sel_sums[RESULT] & SUM_MSN)
{
/* MSN summary (outgoing) ------------------------------------------ */
h_percent = 60.0;
h_table_color = H_TABLE_COLOR5;
get_format("%-30.30s %4d call(s) %10.10s %12s");
print_line2(F_BODY_HEADER,"");
print_line2(F_BODY_HEADERL,"Outgoing calls ordered by MSN");
strich(1);
for (k = 0; k <= mymsns; k++) {
if (usage_sum[k]) { /* there have been calls with this MSN */
print_line3(NULL, ((k == mymsns) ? S_UNKNOWN : known[k]->who),
usage_sum[k],
double2clock(dur_sum[k]),
print_currency(msn_sum[k], 0));
s += msn_sum[k];
s1 += usage_sum[k];
s2 += dur_sum[k];
} /* if */
} /* for */
} /* /if show MSN summary */
#if 0
if (s) {
strich(2);
print_line3(NULL, "TOTAL", s1, double2clock(s2), print_currency(s, 0));
} /* if */
#endif
print_line2(F_BODY_BOTTOM2,"");
if (seeunknowns && unknowns) {
printf("\n\nUnknown caller(s)\n");
strich(3);
for (i = 0; i < unknowns; i++) {
#if 0
printf("%s %-14s ", unknown[i].called ? "called by" : " calling", unknown[i].num);
#else
if ((unknown[i].cause != 1) && /* Unallocated (unassigned) number */
(unknown[i].cause != 3) && /* No route to destination */
(unknown[i].cause != 28)) { /* Invalid number format (address incomplete) */
printf("%s ", unknown[i].called ? "Called by" : " Calling");
printf("??? %s\n\t\t\t ", unknown[i].num);
} /* if */
#endif
for (k = 0; k < unknown[i].connects; k++) {
strcpy(string, ctime(&unknown[i].connect[k]));
if ((p = strchr(string, '\n')))
*p = 0;
*(string + 19) = 0;
if (k && (k + 1) % 2) {
printf("\n\t\t\t ");
} /* if */
printf("%s%s", k & 1 ? ", " : "", string + 4);
} /* for */
printf("\n");
} /* for */
} /* if */
return 0;
}
/*****************************************************************************/
static int print_line3(const char *fmt, ...)
{
char *string = NULL;
char tmpstr[BUFSIZ*3];
auto va_list ap;
prt_fmt** fmtstring;
if (fmt == NULL)
fmtstring = get_format(NULL);
else
fmtstring = get_format(fmt);
if (fmtstring == NULL)
return(UNKNOWN);
va_start(ap, fmt);
while(*fmtstring != NULL)
{
if ((*fmtstring)->type == FMT_FMT)
{
switch((*fmtstring)->s_type)
{
case 's' : append_string(&string,*fmtstring,va_arg(ap,char*));
break;
case 'c' : sprintf(tmpstr,"%c",va_arg(ap,int));
append_string(&string,*fmtstring,tmpstr);
break;
case 'd' : sprintf(tmpstr,"%d",va_arg(ap,int));
append_string(&string,*fmtstring,tmpstr);
break;
case 'f' : sprintf(tmpstr,"%f",va_arg(ap,double));
append_string(&string,*fmtstring,tmpstr);
break;
default : print_msg(PRT_ERR, "isdnrep: internal Error: unknown format `%c'!\n",(*fmtstring)->s_type);
break;
}
}
else
if ((*fmtstring)->type == FMT_STR)
{
append_string(&string,NULL,(*fmtstring)->string);
}
else
print_msg(PRT_ERR, "isdnrep: internal Error: unknown format type `%d'!\n",(*fmtstring)->type);
fmtstring++;
}
va_end(ap);
print_line2(F_BODY_LINE,"%s",string);
free(string);
return 0;
}
/*****************************************************************************/
static int print_line2(int status, const char *fmt, ...)
{
char string[BUFSIZ*3];
auto va_list ap;
va_start(ap, fmt);
vsnprintf(string, BUFSIZ*3, fmt, ap);
va_end(ap);
if (!html)
status = 0;
switch (status)
{
case F_COUNT_ONLY : break;
case F_1ST_LINE : printf(H_1ST_LINE,string);
break;
case F_TEXT_LINE : printf(H_TEXT_LINE,string);
break;
case F_BODY_BOTTOM1:
case F_BODY_LINE : printf(H_BODY_LINE,string);
break;
case F_BODY_HEADER : printf(H_BODY_HEADER1,h_percent,h_table_color);
set_col_size();
break;
case F_BODY_HEADERL: printf(H_BODY_HEADER3,get_format_size(),string);
break;
case F_BODY_BOTTOM2: printf(H_BODY_BOTTOM2);
break;
case F_TABLE_LINE: printf(H_TABLE_LINE, get_format_size(), html_conv(string));
break;
default : printf("%s\n",string);
break;
}
return 0;
}
/*****************************************************************************/
static int print_line(int status, one_call *cur_call, int computed, char *overlap)
{
char *string = NULL;
char help[32];
prt_fmt **fmtstring = get_format(NULL);
int dir;
int i = 0;
int free_col;
int last_free_col = UNKNOWN;
if (colsize == NULL || status == F_COUNT_ONLY)
{
free(colsize);
if ((colsize = (int*) calloc(get_format_size()+1,sizeof(int))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
}
while (*fmtstring != NULL)
{
free_col = 0;
if ((*fmtstring)->type == FMT_FMT)
{
switch((*fmtstring)->s_type)
{
/* time: */
case 'X': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring, get_time_value(0,NULL,GET_TIME));
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, fill_spaces(get_time_value(0,NULL,GET_TIME)));
}
break;
/* date (normal format with year): */
case 'x': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring, get_time_value(0,NULL,GET_DATE2));
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, fill_spaces(get_time_value(0,NULL,GET_DATE2)));
}
break;
/* date (without year): */
case 'y': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring, get_time_value(0,NULL,GET_DATE));
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, fill_spaces(get_time_value(0,NULL,GET_DATE)));
}
break;
/* year: */
case 'Y': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring, get_time_value(0,NULL,GET_YEAR));
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, fill_spaces(get_time_value(0,NULL,GET_YEAR)));
}
break;
/* duration: */
case 'D': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring, double2clock(cur_call->duration));
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, fill_spaces(double2clock(cur_call->duration)));
}
break;
/* Home (if possible the name): */
/* Benoetigt Range! */
case 'H': if (status == F_BODY_LINE)
{
dir = cur_call->dir?CALLED:CALLING;
if (!numbers)
{
colsize[i] = append_string(&string,*fmtstring,
cur_call->who[dir][0]?cur_call->who[dir]:cur_call->num[dir]);
break;
}
}
/* Home (number): */
/* Benoetigt Range! */
case 'h': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring,
cur_call->num[cur_call->dir?CALLED:CALLING]);
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, "");
}
break;
/* The other (if possible the name): */
/* Benoetigt Range! */
case 'F': if (status == F_BODY_LINE)
{
dir = cur_call->dir?CALLING:CALLED;
if (!numbers)
{
colsize[i] = append_string(&string,*fmtstring,
cur_call->who[dir][0]?cur_call->who[dir]:cur_call->num[dir]);
break;
}
}
/* The other (number): */
/* Benoetigt Range! */
case 'f': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring,
cur_call->num[cur_call->dir?CALLING:CALLED]);
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, "");
}
break;
/* The home location: */
/* Benoetigt Range! */
case 'L': if (status == F_BODY_LINE)
{
dir = cur_call->dir?CALLED:CALLING;
colsize[i] = append_string(&string,*fmtstring, cur_call->sarea[dir]);
}
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, "");
}
break;
/* The remote location: */
/* Benoetigt Range! */
case 'l': if (status == F_BODY_LINE)
{
dir = cur_call->dir?CALLING:CALLED;
colsize[i] = append_string(&string,*fmtstring, cur_call->sarea[dir]);
}
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, "");
}
break;
/* The "To"-sign (from home to other) (-> or <-): */
case 'T': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring, cur_call->dir?"<-":"->");
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, " ");
}
break;
/* The "To"-sign (from other to home) (-> or <-): */
case 't': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring, cur_call->dir?"->":"<-");
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, " ");
}
break;
/* The units (if exists): */
/* Benoetigt Range! */
case 'u': if (cur_call->eh > 0)
{
sprintf(help,"%d EH",cur_call->eh);
colsize[i] = append_string(&string,*fmtstring, help);
}
else
colsize[i] = append_string(&string,*fmtstring, "");
break;
/* The money or/and a message: */
case 'U': if (cur_call->duration || cur_call->eh > 0 || cur_call->pay > 0)
{
if (cur_call->dir)
colsize[i] = append_string(&string,NULL," ");
else
colsize[i] = append_string(&string,*fmtstring,print_currency(cur_call->pay,computed));
}
else
if ((status == F_BODY_LINE) &&
(cur_call->cause != UNKNOWN) &&
(cur_call->cause != 0x10) && /* Normal call clearing */
(cur_call->cause != 0x1f)) /* Normal, unspecified */
colsize[i] = append_string(&string,*fmtstring,qmsg(TYPE_CAUSE, VERSION_EDSS1, cur_call->cause));
else
colsize[i] = append_string(&string,NULL," ");
break;
/* In-Bytes: */
/* Benoetigt Range! */
case 'I': colsize[i] = append_string(&string,*fmtstring,set_byte_string(GET_IN|GET_BYTES,(double)cur_call->ibytes));
break;
/* Out-Bytes: */
/* Benoetigt Range! */
case 'O': colsize[i] = append_string(&string,*fmtstring,set_byte_string(GET_OUT|GET_BYTES,(double)cur_call->obytes));
break;
/* In-Bytes per second: */
/* Benoetigt Range! */
case 'P': colsize[i] = append_string(&string,*fmtstring,set_byte_string(GET_IN|GET_BPS,cur_call->duration?cur_call->ibytes/(double)cur_call->duration:0.0));
break;
/* Out-Bytes per second: */
/* Benoetigt Range! */
case 'p': colsize[i] = append_string(&string,*fmtstring,set_byte_string(GET_OUT|GET_BPS,cur_call->duration?cur_call->obytes/(double)cur_call->duration:0.0));
break;
/* SI: */
case 'S': if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring,int2str(cur_call->si,2));
else
colsize[i] = append_string(&string,*fmtstring," ");
break;
/* provider name (from ratefile): */
/* should have range */
case 'j': if (status == F_BODY_LINE)
{
/* if (!numbers) */ /* there is no numeric alternative */
{
register char *p;
p = (cur_call->provider >= 0) ? getProvider(cur_call->provider) : "";
if (cur_call->dir == DIALIN)
p = "";
colsize[i] = append_string(&string,*fmtstring, p);
break;
}
}
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring, "");
}
break;
/* v: vbn aka carrier selection prefix (B: tag in ratefile) */
case 'v': if (status == F_BODY_LINE)
{
char help2[16];
if (cur_call->dir == DIALIN)
help[0] = '\0';
else
prefix2provider(cur_call->provider, help);
snprintf(help2, 16, "%-8s", help);
colsize[i] = append_string(&string,*fmtstring, help2);
}
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring,
" ");
}
break;
/* V: vbn and provider variant, e. g. "01012_3" */
case 'V': if (status == F_BODY_LINE)
{
char help2[16];
if (cur_call->dir == DIALIN)
help[0] = '\0';
else
prefix2provider_variant(cur_call->provider, help);
snprintf(help2, 16, "%-10s", help);
colsize[i] = append_string(&string,*fmtstring, help2);
}
else
{
free_col = 1;
if (!html || status == F_COUNT_ONLY)
colsize[i] = append_string(&string,*fmtstring,
" ");
}
break;
/* Link for answering machine! */
case 'C': if (html)
{
if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring,get_links(cur_call->t,C_VBOX));
else
colsize[i] = append_string(&string,*fmtstring," ");
}
else
print_msg(PRT_ERR, "isdnrep: unknown format %%C!\n");
break;
/* Link for fax! */
case 'G': if (html)
{
if (status == F_BODY_LINE)
colsize[i] = append_string(&string,*fmtstring,get_links(cur_call->t,C_FAX));
else
colsize[i] = append_string(&string,*fmtstring," ");
}
else
print_msg(PRT_ERR, "isdnrep: unknown format %%G!\n");
break;
/* there are dummy entries */
case 'c':
case 'd':
case 's': if (status != F_BODY_LINE)
free_col = 1;
colsize[i] = append_string(&string,*fmtstring, " ");
break;
default : print_msg(PRT_ERR, "isdnrep: internal Error: unknown format `%c'!\n",(*fmtstring)->s_type);
break;
}
}
else
if ((*fmtstring)->type == FMT_STR)
{
if (!html || status == F_COUNT_ONLY || status == F_BODY_LINE || last_free_col != i-1)
colsize[i] = append_string(&string,NULL,(*fmtstring)->string);
else
free_col = 1;
}
else
print_msg(PRT_ERR, "isdnrep: internal Error: unknown format type `%d'!\n",(*fmtstring)->type);
if (html && status == F_BODY_BOTTOM1 && free_col && last_free_col == i-1)
last_free_col = i;
fmtstring++;
i++;
}
if (last_free_col != UNKNOWN)
{
char *help2 = NULL;
if ((help2 = (char*) calloc(strlen(H_BODY_BOTTOM1)+(string?strlen(string):0)+strlen(overlap)+1,sizeof(char))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
sprintf(help2,H_BODY_BOTTOM1,last_free_col+1,overlap,string?string:"");
free(string);
string = help2;
overlap = NULL;
}
colsize[i] = UNKNOWN;
if (status == F_COUNT_ONLY)
return (string) ? strlen(string) : 0; /* do not call strlen(0) */
else
print_line2(status,"%s",overlap_string(string,overlap));
free(string);
return 0;
}
/*****************************************************************************/
static void bprint(one_call *call)
{
register char *p = call->num[CALLED];
auto char target[BUFSIZ], s[BUFSIZ];
auto TELNUM number;
if (call->duration) {
if (!memcmp(call->num[CALLED], mycountry, strlen(mycountry))) { /* eigenes Land */
p += strlen(mycountry);
sprintf(target, "0%s", p);
}
else
sprintf(target, "%s", p);
printf( "%s %s %-16s ",
get_time_value(0,NULL, GET_TIME),
double2clock(call->duration),
target);
if (call->duration) {
printf( "%s %-15s",
print_currency(call->pay * 100.0 / 116.0, 0), getProvider(call->provider));
strcpy(s, call->num[CALLED]);
number.nprovider=call->provider;
normalizeNumber(s, &number, TN_NO_PROVIDER);
printf( "%s\n", formatNumber("%A", &number));
}
else
printf( "%*s** %s\n", 30, "", qmsg(TYPE_CAUSE, VERSION_EDSS1, call->cause));
} /* if */
} /* bprint */
/*****************************************************************************/
static int append_string(char **string, prt_fmt *fmt_ptr, char* value)
{
char tmpstr[BUFSIZ*3];
char tmpfmt2[20];
char *tmpfmt;
char *htmlfmt;
int condition = html && (*value == ' ' || fmt_ptr == NULL || (fmt_ptr->s_type!='C' && fmt_ptr->s_type!='G'));
if (fmt_ptr != NULL)
sprintf(tmpfmt2,"%%%ss",fmt_ptr->range);
else
strcpy(tmpfmt2,"%s");
if (html)
{
switch (fmt_ptr==NULL?'\0':fmt_ptr->range[0])
{
case '-' : htmlfmt = H_LEFT;
break;
case '\0': htmlfmt = H_CENTER;
break;
default : htmlfmt = H_RIGHT;
break;
}
if (!strncmp(STR_FAX,value,strlen(STR_FAX)))
htmlfmt = H_LEFT;
if ((tmpfmt = (char*) alloca(sizeof(char)*(strlen(htmlfmt)+strlen(tmpfmt2)+1))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
sprintf(tmpfmt,htmlfmt,tmpfmt2);
}
else
tmpfmt = tmpfmt2;
app_fmt_string(tmpstr,BUFSIZ*3-1,tmpfmt,condition,value);
if (*string == NULL)
*string = (char*) calloc(strlen(tmpstr)+1,sizeof(char));
else
*string = (char*) realloc(*string,sizeof(char)*(strlen(*string)+strlen(tmpstr)+1));
if (*string == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
strcat(*string,tmpstr);
return strlen(tmpstr);
}
/*****************************************************************************/
static char *html_conv(char *string)
{
static char RetCode[BUFSIZ];
char *ptr = RetCode;
int i;
int empty = 1;
if (string == NULL)
return NULL;
do
{
for(i = 0; htmlconv[i][0][0] != '\0'; i++)
{
if (htmlconv[i][0][0] == *string)
{
strcpy(ptr,htmlconv[i][1]);
while (*ptr != '\0') ptr++;
break;
}
}
if (htmlconv[i][0][0] == '\0')
*ptr++ = *string;
if (*string != '\0' && !isspace(*string))
empty = 0;
}
while(*string++ != '\0');
if (empty)
return H_EMPTY;
return RetCode;
}
/*****************************************************************************/
static char *set_byte_string(int flag, double Bytes)
{
static char string[4][20];
static int num = 0;
int factor = 1;
char prefix = ' ';
num = (num+1)%4;
if (!Bytes)
{
if (flag & GET_BPS)
strcpy(string[num]," ");
else
strcpy(string[num]," ");
}
else
{
if (Bytes >= 9999999999.0)
{
factor = 1073741824;
prefix = 'G';
}
else
if (Bytes >= 9999999)
{
factor = 1048576;
prefix = 'M';
}
else
if (Bytes >= 9999)
{
factor = 1024;
prefix = 'k';
}
sprintf(string[num],"%c=%s %cB%s",flag&GET_IN?'I':'O',double2str(Bytes/factor,7,2,0),prefix,flag&GET_BPS?"/s":"");
}
return string[num];
}
/*****************************************************************************/
static int set_col_size(void)
{
one_call *tmp_call;
int size = 0;
int i = 0;
if ((tmp_call = (one_call*) calloc(1,sizeof(one_call))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
print_line(F_COUNT_ONLY,tmp_call,0,NULL);
while(colsize[i] != UNKNOWN)
if (html)
printf(H_BODY_HEADER2,colsize[i++]);
else
size += colsize[i++];
free(tmp_call);
return size;
}
/*****************************************************************************/
static int get_format_size(void)
{
int i = 0;
prt_fmt** fmt = get_format(NULL);
if (fmt == NULL)
return 0;
while(*fmt++ != NULL) i++;
return i;
}
/*****************************************************************************/
static char *overlap_string(char *s1, char *s2)
{
int i = 0;
if (s1 == NULL || s2 == NULL)
return s1;
while(s1[i] != '\0' && s2[i] != '\0')
{
if (isspace(s1[i]))
s1[i] = s2[i];
i++;
}
return s1;
}
/*****************************************************************************/
static char* fill_spaces(char *string)
{
static char RetCode[256];
char *Ptr = RetCode;
while (*string != '\0')
{
*Ptr++ = ' ';
string++;
}
*Ptr = '\0';
return RetCode;
}
/*****************************************************************************/
static void free_format(prt_fmt** ptr)
{
prt_fmt** ptr2 = ptr;
if (ptr == NULL)
return;
while(*ptr != NULL)
{
free((*ptr)->string);
free((*ptr)->range);
free((*ptr++));
}
free(ptr2);
free(colsize);
colsize = NULL;
}
/*****************************************************************************/
static prt_fmt** get_format(const char *format)
{
static prt_fmt **RetCode = NULL;
prt_fmt *fmt = NULL;
char *Ptr = NULL;
char *string = NULL;
char *start = NULL;
char *End = NULL;
char Range[20] = "";
int num;
char Type;
if (format == NULL)
return RetCode;
free_format(RetCode);
RetCode = NULL;
if ((End = (char*) alloca(sizeof(char)*(strlen(format)+1))) == NULL ||
(string = (char*) alloca(sizeof(char)*(strlen(format)+1))) == NULL )
{
print_msg(PRT_ERR, nomemory);
return NULL;
}
Ptr = start = strcpy(string,format);
do
{
if (*Ptr == C_BEGIN_FMT)
{
if (Ptr[1] != C_BEGIN_FMT)
{
if (Ptr != start)
{
if ((fmt = (prt_fmt*) calloc(1,sizeof(prt_fmt))) == NULL)
{
print_msg(PRT_ERR, nomemory);
delete_element(&RetCode,0);
return NULL;
}
*Ptr = '\0';
fmt->string= strdup(start);
fmt->type = FMT_STR;
append_element(&RetCode,fmt);
}
*Range = *End = '\0';
if ((num = sscanf(Ptr+1,"%[^a-zA-Z]%c%[^\n]",Range,&Type,End)) > 1 ||
(num = sscanf(Ptr+1,"%c%[^\n]",&Type,End)) > 0 )
{
if (!isalpha(Type))
print_msg(PRT_ERR, "isdnrep: warning: invalid token in format type `%c'!\n",Type);
if ((fmt = (prt_fmt*) calloc(1,sizeof(prt_fmt))) == NULL)
{
print_msg(PRT_ERR, nomemory);
delete_element(&RetCode,0);
return NULL;
}
switch (Type)
{
case 'C': read_path |= F_VBOX;
break;
case 'G': read_path |= F_FAX;
break;
default : break;
}
fmt->s_type= Type;
fmt->range = strdup(Range);
fmt->type = FMT_FMT;
append_element(&RetCode,fmt);
*Range = '\0';
if (*End != '\0')
Ptr = start = strcpy(string,End);
else
Ptr = start = "";
}
else
{
print_msg(PRT_ERR, "isdnrep: error: invalid token in format string `%s'!\n",format);
return NULL;
}
}
else
{
memmove(Ptr,Ptr+1,strlen(Ptr));
Ptr++;
}
}
else
Ptr++;
}
while(*Ptr != '\0');
if (Ptr != start)
{
if ((fmt = (prt_fmt*) calloc(1,sizeof(prt_fmt))) == NULL)
{
print_msg(PRT_ERR, nomemory);
delete_element(&RetCode,0);
return NULL;
}
fmt->string= strdup(start);
fmt->type = FMT_STR;
append_element(&RetCode,fmt);
}
return RetCode;
}
/*****************************************************************************/
static int print_entries(one_call *cur_call, double unit, int *nx, char *myname)
{
register int i, zone, computed = 0;
if (1 /* cur_call->dir == DIALOUT */) {
zone = (cur_call->zone >= 0) ? cur_call->zone : UNKNOWNZONE;
zones[zone] += cur_call->eh;
zones_dm[zone] += cur_call->pay;
if (cur_call->duration > 0)
zones_dur[zone] += cur_call->duration;
zones_usage[zone] += 1;
#if DEBUG
if (zone == UNKNOWNZONE) {
assert(strlen(unknownzones) + 4 < sizeof(unknownzones));
if (*unknownzones)
strcat(unknownzones, ", ");
assert(strlen(unknownzones) + strlen(cur_call->num[1]) < sizeof(unknownzones));
strcat(unknownzones, cur_call->num[1]);
} /* if */
#endif
add_one_call(computed ? &day_com_sum : &day_sum, cur_call, unit);
if (cur_call->dir) {
if (nx[CALLING] == UNKNOWN) {
known[knowns - 1]->usage[DIALIN]++;
known[knowns - 1]->ibytes[DIALIN] += cur_call->ibytes;
known[knowns - 1]->obytes[DIALIN] += cur_call->obytes;
if (cur_call->duration > 0)
known[knowns-1]->dur[DIALIN] += cur_call->duration;
}
else {
known[nx[CALLING]]->usage[cur_call->dir]++;
known[nx[CALLING]]->dur[cur_call->dir] += cur_call->duration;
known[nx[CALLING]]->ibytes[DIALIN] += cur_call->ibytes;
known[nx[CALLING]]->obytes[DIALIN] += cur_call->obytes;
} /* else */
}
else {
usage_provider[cur_call->provider]++;
if ((cur_call->cause == 0x22) || /* No circuit/channel available */
(cur_call->cause == 0x2a)) /* Switching equipment congestion */
provider_failed[cur_call->provider]++;
duration_provider[cur_call->provider] += cur_call->duration;
pay_provider[cur_call->provider] += cur_call->pay;
if (nx[CALLED] == UNKNOWN) {
known[knowns-1]->eh += cur_call->eh;
known[knowns-1]->pay += cur_call->pay;
known[knowns-1]->ibytes[DIALOUT] += cur_call->ibytes;
known[knowns-1]->obytes[DIALOUT] += cur_call->obytes;
known[knowns-1]->usage[DIALOUT]++;
if (cur_call->duration > 0)
known[knowns-1]->dur[DIALOUT] += cur_call->duration;
}
else {
known[nx[CALLED]]->eh += cur_call->eh;
known[nx[CALLED]]->pay += cur_call->pay;
known[nx[CALLED]]->usage[cur_call->dir]++;
known[nx[CALLED]]->dur[cur_call->dir] += cur_call->duration;
known[nx[CALLED]]->ibytes[DIALOUT] += cur_call->ibytes;
known[nx[CALLED]]->obytes[DIALOUT] += cur_call->obytes;
} /* if */
} /* else */
}
else
add_one_call(computed ? &day_com_sum : &day_sum, cur_call, unit);
if (cur_call->dir == DIALOUT) {
int first_found = UNKNOWN;
for (i = 0; i < mymsns; i++) {
if (!n_match(known[i]->num, cur_call->num[0], cur_call->version)) {
/* Ermitteln der ersten passenden MSN (lt. README) */
if (first_found == UNKNOWN)
first_found = i;
/* exakte Uebereinstimmung inkl. SI */
if (known[i]->si == cur_call->si) {
msn_sum[i] += cur_call->pay;
usage_sum[i]++;
dur_sum[i] += cur_call->duration;
break;
} /* if */
} /* if */
} /* for */
if (i == mymsns) {
/* keine exakte Uebereinstimmung, aber ohne SI */
if (first_found != UNKNOWN)
i = first_found;
msn_sum[i] += cur_call->pay;
usage_sum[i]++;
dur_sum[i] += cur_call->duration;
} /* if */
} /* if */
if (bill) {
if (cur_call->dir == DIALOUT)
bprint(cur_call);
}
else if(!summary)
print_line(F_BODY_LINE,cur_call,computed,NULL);
return(0);
} /* print_entries */
/*****************************************************************************/
static int print_header(int lday)
{
sum_calls tmp_sum;
time_t now;
if (lday == UNKNOWN) { /* first day, print overall header, no day sum */
time(&now);
if (bill)
print_line2(F_1ST_LINE, "Ihre Verbindungen im einzelnen - %s", ctime(&now));
else
print_line2(F_1ST_LINE,"I S D N Connection Report - %s", ctime(&now));
if (recalc.mode)
{
char s[80];
char *prov, *vbn;
if (recalc.mode == '-')
snprintf(s, 80, "Connection fees recomputed");
else if (tolower(recalc.mode) == 'b')
snprintf(s, 80, "Connection fees recomputed using the cheapest "
"of all %sproviders", (recalc.mode=='b')?"booked ":"");
else
{
prov = getProvider(recalc.prefix);
vbn = getProviderVBN(recalc.prefix);
if (strstr(prov, vbn)) /* don't show vbn twice */
snprintf(s, 80, "Connection fees recomputed for provider %s",
prov);
else
snprintf(s, 80, "Connection fees recomputed for provider %s %s",
vbn, prov);
}
print_line2(F_TEXT_LINE, "%s", s);
}
/* TODO: consistent terminology. fees vs. costs (tobiasb|200407) */
if (modcost.mode)
print_line2(F_TEXT_LINE, "All displayed costs have been %s by %s.",
modcost.mode == 2 ? "divided" : "multiplied", modcost.numstr);
}
else
{
if (summary >= 2)
return 0;
strich(1);
print_sum_calls(&day_sum,0);
if (day_com_sum.eh)
{
print_sum_calls(&day_com_sum,1);
clear_sum(&tmp_sum);
add_sum_calls(&tmp_sum,&day_sum);
add_sum_calls(&tmp_sum,&day_com_sum);
strich(1);
print_sum_calls(&tmp_sum,0);
}
else
printf("\n\n");
add_sum_calls(&all_sum,&day_sum);
clear_sum(&day_sum);
add_sum_calls(&all_com_sum,&day_com_sum);
clear_sum(&day_com_sum);
print_line2(F_BODY_BOTTOM2,"");
} /* if */
h_percent = 100.0;
h_table_color = H_TABLE_COLOR1;
print_line2(F_BODY_HEADER,"");
if (summary < 2)
print_line2(F_BODY_HEADERL,"%s %s", get_time_value(0,NULL,GET_DATE),
get_time_value(0,NULL,GET_YEAR));
else /* show timespam "from .. to" for options -SS */
{
char s[80];
s[0]=0;
strcat(s, get_time_value(0, NULL, GET_DATE));
strcat(s, " ");
strcat(s, get_time_value(0, NULL, GET_YEAR));
strcat(s, " .. ");
get_time_value(endtime, &lday, SET_TIME);
strcat(s, get_time_value(0, NULL, GET_DATE));
strcat(s, " ");
strcat(s, get_time_value(0, NULL, GET_YEAR));
print_line2(F_BODY_HEADERL, "%s", s);
}
return 0;
}
/*****************************************************************************/
static char *get_time_value(time_t t, int *day, int flag)
{
static char time_string[4][18] = {"","",""};
static int oldday = UNKNOWN;
static int oldyear = UNKNOWN;
struct tm *tm;
if (flag & SET_TIME)
{
tm = localtime(&t);
/*sprintf(time_string[0],"%d:%d:%d",tm->tm_hour,tm->tm_min,tm->tm_sec);*/
strftime(time_string[0],17,"%X",tm);
if (oldday != tm->tm_yday || oldyear != tm->tm_year)
{
*day = tm->tm_mday;
Tarif96 = tm->tm_year > 95;
/* Ab Juli '96 gibt's noch mal eine Senkung in den Zonen 3 und 4
genaue Preise sind jedoch noch nicht bekannt. FIX-ME */
Tarif962 = (Tarif96 && (tm->tm_mon > 5)) || (tm->tm_year > 96);
strftime(time_string[1],17,"%a %b %d",tm);
strftime(time_string[2],17,"%x",tm);
oldday = tm->tm_yday;
if (oldyear != tm->tm_year)
{
sprintf(time_string[3],"%d",1900+tm->tm_year);
oldyear = tm->tm_year;
}
}
}
if (flag & GET_TIME)
return time_string[0];
else
if (flag & GET_DATE)
return time_string[1];
else
if (flag & GET_DATE2)
return time_string[2];
else
if (flag & GET_YEAR)
return time_string[3];
return NULL;
}
/*****************************************************************************/
static int set_alias(one_call *cur_call, int *nx, char *myname)
{
auto int n, cc, i, j;
auto int hit;
for (n = CALLING; n <= CALLED; n++) {
nx[n] = UNKNOWN;
hit = 0;
if (!*(cur_call->num[n])) {
// if (!numbers)
{
cur_call->num[n][0] = C_UNKNOWN;
cur_call->num[n][1] = '\0';
}
/* Wenn keine Nummer, dann Name "UNKNOWN" */
hit++;
} else {
/* In der folg. Schleife werden Nummern durch Namen ersetzt */
cc = 0;
for (j = 0; ((j < 2) && !cc); j++) {
for (i = 0; i < knowns; i++) {
if (cur_call->version[0] != '\0')
{
if (!strcmp(cur_call->version,LOG_VERSION_2) ||
!strcmp(cur_call->version,LOG_VERSION_3) ||
!strcmp(cur_call->version,LOG_VERSION_4) ||
!strcmp(cur_call->version,LOG_VERSION) )
cc = ((known[i]->si == cur_call->si) || j) &&
!n_match(known[i]->num, cur_call->num[n], cur_call->version);
}
else
{
if (*cur_call->num[n] != '0') {
/* Alte Syntax der "isdn.log" : Ohne vorlaufene "0" */
cc = ((known[i]->si == cur_call->si) || j) &&
!match(known[i]->num+1, cur_call->num[n], 0);
if (!cc) {
/* Ganz alte Syntax der "isdn.log" : Ohne Vorwahl */
cc = ((known[i]->si == cur_call->si) || j) &&
!n_match(known[i]->num, cur_call->num[n], LOG_VERSION_1);
} /* if */
}
}
if (cc) {
Strncpy(cur_call->who[n], known[i]->who,RETSIZE);
nx[n] = i;
hit++;
break;
} /* if */
} /* for */
} /* for */
/* In der naechsten Schleife werden die unbekannten Nummern
registriert */
if (!hit && seeunknowns) {
for (i = 0; i < unknowns; i++)
if (!strcmp(unknown[i].num, cur_call->num[n])) {
hit++;
break;
} /* if */
strcpy(unknown[i].num, cur_call->num[n]);
strcpy(unknown[i].mynum, cur_call->num[1 - n]);
unknown[i].si1 = cur_call->si1;
unknown[i].called = !n;
unknown[i].connect[unknown[i].connects] = cur_call->t;
unknown[i].cause = cur_call->cause;
/* ACHTUNG: MAXCONNECTS und MAXUNKNOWN sollten unbedingt groesser sein ! */
if (unknown[i].connects + 1 < MAXCONNECTS)
unknown[i].connects++;
else
print_msg(PRT_ERR, "%s: WARNING: too many unknown connections from %s\n", myname, unknown[i].num);
if (!hit) {
if (unknowns < MAXUNKNOWN)
unknowns++;
else
print_msg(PRT_ERR, "%s: WARNING: too many unknown numbers\n", myname);
} /* if */
} /* if */
} /* else */
} /* for */
return 0;
}
static void repair(one_call *cur_call)
{
RATE Rate, lcrRate;
TELNUM srcnum, destnum;
int have_z; /* Zone Rate.z from getZone valid or not */
int best_zone; /* =Rate.z if valid or =Rate.zone if Rate.z invalid */
int is_defsrc = 0; /* default source number used or not */
if (cur_call->dir == DIALOUT && !*cur_call->num[CALLING] && defsrc.mode > 0) {
Strncpy(cur_call->num[CALLING], defsrc.number, NUMSIZE);
++is_defsrc;
}
if (*cur_call->num[CALLING]) {
normalizeNumber(cur_call->num[CALLING],&srcnum,TN_ALL);
strcpy(cur_call->sarea[CALLING], srcnum.sarea);
}
else
*cur_call->sarea[CALLING] = 0;
if (*cur_call->num[CALLED]) {
destnum.nprovider = cur_call->provider;
Strncpy(destnum.provider,getProvider(cur_call->provider), TN_MAX_PROVIDER_LEN);
normalizeNumber(cur_call->num[CALLED], &destnum, TN_NO_PROVIDER);
strcpy(cur_call->sarea[CALLED], destnum.sarea);
}
else
*cur_call->sarea[CALLED] = 0;
if ((cur_call->dir == DIALOUT) &&
(cur_call->duration > 0) &&
*cur_call->num[CALLED]
) {
call[0].connect = cur_call->t;
call[0].disconnect = cur_call->t + cur_call->duration;
call[0].intern[CALLED] = strlen(cur_call->num[CALLED]) < interns0;
call[0].provider = cur_call->provider;
call[0].aoce = cur_call->eh;
call[0].dialin = 0;
strcpy(call[0].num[CALLED], cur_call->num[CALLED]);
strcpy(call[0].onum[CALLED], cur_call->num[CALLED]);
call[0].sondernummer[CALLED] = destnum.ncountry==0;
clearRate(&Rate);
Rate.src[0] = srcnum.country;
Rate.src[1] = srcnum.area;
Rate.src[2] = "";
Rate.dst[0] = destnum.country;
Rate.dst[1] = destnum.area;
Rate.dst[2] = destnum.msn;
Rate.start = cur_call->t;
Rate.now = call[0].disconnect;
Rate.prefix = cur_call->provider;
if (recalc.mode) {
recalc.count++;
if (recalc.mode == 'p' || recalc.mode == 'v')
Rate.prefix = recalc.prefix;
if (!getRate(&Rate,0)) {
if ( (tolower(recalc.mode) == 'b') && /* find new provider with lcr */
!getPrsel(cur_call->num[CALLED], &Rate.prefix, NULL, NULL) &&
getLeastCost (&Rate, &lcrRate, recalc.mode=='b', Rate.prefix)
!= UNKNOWN &&
lcrRate.Charge < Rate.Charge &&
!strcmp(lcrRate.dst[1], Rate.dst[1]) /* no new special number */
) {
recalc.cheaper++;
cur_call->pay = lcrRate.Charge;
cur_call->provider = lcrRate.prefix;
}
else { /* lcr failed (error or no cheaper provider) or not requested */
cur_call->pay = Rate.Charge;
cur_call->provider = Rate.prefix;
}
}
else { /* fall back to logged provider for zone name etc */
recalc.unknown++;
Rate.prefix = cur_call->provider;
Rate._zone = Rate._area = Rate.zone = UNKNOWN;
}
}
if (!getRate(&Rate,0)) {
#if DEBUG
fprintf(stderr,"Rate.zone=%i Rate.z=%i Rate.domestic=%i call.[0]so..r[CALLED]=%i\n", Rate.zone, Rate.z, Rate.domestic, call[0].sondernummer[CALLED]);
#endif
have_z = (Rate.domestic && !call[0].sondernummer[CALLED] && Rate.z>0);
best_zone = have_z ? Rate.z : Rate.zone;
if(strcmp(cur_call->version, LOG_VERSION)) {
/* LOG_VERSION is "3.2" since 1999-01-24 or isdnlog-3.33, earlier
* calls are recalculated. At least for Germany this makes nowadays
* (2003-02) no sense, since rates _have_ changed and the Euro was
* introduced on 2002-01-01. */
cur_call->pay = Rate.Charge; /* Fixme: is that ok, propably rates have changed */
cur_call->zone = (best_zone < MAXZONES) ? best_zone : UNKNOWN;
}
else {
/* A patched isdnlog-4.64 or later versions may have written the zone
* in the last field of the log entry. In this case, keep this zone.
* isdnlog-3.32 and earlier did so too, but with an older LOG_VERSION
* which triggered recalculation above.
* As the zone summation is carried out over all providers, using
* the zone number from the rate-file (Rate.zone) seems a little bit
* closer to the desired result as the internal zone index (Rate._zone)
*/
if (cur_call->zone == UNKNOWN)
cur_call->zone = (best_zone < MAXZONES) ? best_zone : UNKNOWN;
}
/* Next difficulty: We need a zone name for the zone summation. These
* names may differ between different providers. Even with a recorded
* zone from the logfile, we need a name.
* As before duplicated strings (strdup) are not released
* TODO: Use the zone names from the preselected provider with
* priority instead of the current use of the first `best' name. */
if (cur_call->zone != UNKNOWN) { /* valid index for zones_-arrays */
int *zflags=&(zones_src[cur_call->zone].flags);
if ( cur_call->provider>0 && zones_src[cur_call->zone].first_prov>0
&& zones_src[cur_call->zone].first_prov != cur_call->provider)
*zflags |= FZN_MPROV; /* zone is used at different providers */
if (!zones_names[cur_call->zone]) { /* no zone name yet */
/* get a name in any circumstands */
if (Rate.Zone) {
zones_names[cur_call->zone] = strdup(Rate.Zone);
*zflags |= FZN_KNOWN;
if (Rate.zone!=cur_call->zone && !have_z && Rate.z!=cur_call->zone)
/* zone number from logfile does not match zone from rate file */
*zflags |= FZN_UNSURE;
}
else {
zones_names[cur_call->zone] = strdup("??"); /* old behaviour */
}
zones_src[cur_call->zone].first_prov = cur_call->provider;
}
else { /* got already a zone name */
if ( !(*zflags & FZN_KNOWN) && Rate.Zone ) {
/* get a name better than ?? */
zones_names[cur_call->zone] = strdup(Rate.Zone);
*zflags |= FZN_KNOWN;
if (Rate.zone!=cur_call->zone && !have_z && Rate.z!=cur_call->zone)
*zflags |= FZN_UNSURE;
}
else if ( *zflags & FZN_UNSURE && Rate.Zone &&
( Rate.zone==cur_call->zone ||
(have_z && Rate.z==cur_call->zone) ) ) {
/* get a name without zone number difference between log and rate */
zones_names[cur_call->zone] = strdup(Rate.Zone);
zones_src[cur_call->zone].flags &= ~FZN_UNSURE;
}
else {
/* zone name not replaced, Rate.Zone could be NULL */
if ( (*zflags & (FZN_KNOWN|FZN_UNSURE|FZN_MNAME|FZN_MPROV)) == (FZN_KNOWN|FZN_MPROV)
&& (!Rate.Zone||strcmp(zones_names[cur_call->zone], Rate.Zone)) )
*zflags |= FZN_MNAME; /* diff. names at diff. providers */
}
} /* if zone name first time */
} /* if valid zones_.. index */
} /* if getRate successful */
} /* if DIALOUT && duration > && num[CALLED] */
if (is_defsrc && defsrc.mode == 2) /* do not display default source number */
*cur_call->num[CALLING] = 0;
} /* repair */
/*****************************************************************************/
static int set_caller_infos(one_call *cur_call, char *string, time_t from)
{
int rc;
register int i = 0, adapt = 0;
auto char **array;
auto double dur1 = 0.0, dur2 = 0.0;
array = string_to_array(string);
if (array[5] == NULL)
return(UNKNOWN);
cur_call->t = atol(array[5]);
rc = 0;
if (delentries && cur_call->t < endtime)
rc = UNKNOWN; /* return this, but first process the record */
else if (timearea && (cur_call->t < begintime || cur_call->t > endtime))
return(UNKNOWN);
else
if (cur_call->t < from)
return(UNKNOWN);
cur_call->eh = 0;
cur_call->dir = UNKNOWN;
cur_call->cause = UNKNOWN;
cur_call->ibytes = cur_call->obytes = 0L;
cur_call->pay = 0.0;
cur_call->version[0] = '\0';
cur_call->si = cur_call->si1 = 0;
cur_call->dir = DIALOUT;
cur_call->who[0][0] = '\0';
cur_call->who[1][0] = '\0';
cur_call->provider = UNDEFINED;
cur_call->zone = UNDEFINED;
for (i = 1; array[i] != NULL; i++)
{
switch (i)
{
case 0 : cur_call->t = atom(array[i]);
break;
case 1 : strcpy(cur_call->num[0], Kill_Blanks(array[i]));
break;
case 2 : strcpy(cur_call->num[1], Kill_Blanks(array[i]));
/* Korrektur der falschen Eintraege aus den ersten Januar-Tagen 1998 */
if (!memcmp(cur_call->num[1], "+491019", 7)) {
cur_call->provider = 19;
memmove(cur_call->num[1] + 3, cur_call->num[1] + 8, strlen(cur_call->num[1]) - 7);
adapt++;
}
else if (!memcmp(cur_call->num[1], "+491033", 7)) {
cur_call->provider = 33;
memmove(cur_call->num[1] + 3, cur_call->num[1] + 8, strlen(cur_call->num[1]) - 7);
adapt++;
}
else if (!memcmp(cur_call->num[1], "+491070", 7)) {
cur_call->provider = 70;
memmove(cur_call->num[1] + 3, cur_call->num[1] + 8, strlen(cur_call->num[1]) - 7);
adapt++;
} /* else */
if (adapt)
strcpy(cur_call->version, LOG_VERSION_4);
break;
case 3 : dur1 = cur_call->duration = strtod(array[i],NULL);
if (dur1 < 0) /* wrong entry on some incoming voice calls */
dur1 = cur_call->duration = 0;
break;
case 4 : dur2 = cur_call->duration = strtod(array[i],NULL)/100;
break;
case 5 : /*cur_call->t = atol(array[i]);*/
break;
case 6 : cur_call->eh = atoi(array[i]);
break;
case 7 : cur_call->dir = (*array[i] == 'I') ? DIALIN : DIALOUT;
break;
case 8 : cur_call->cause = atoi(array[i]);
break;
case 9 : cur_call->ibytes = atol(array[i]);
break;
case 10: cur_call->obytes = atol(array[i]);
break;
case 11: if (!adapt)
strcpy(cur_call->version,array[i]);
break;
case 12: cur_call->si = atoi(array[i]);
break;
case 13: cur_call->si1 = atoi(array[i]);
break;
case 14: cur_call->currency_factor = atof(array[i]);
break;
case 15: strncpy(cur_call->currency, array[i], 3);
break;
case 16: cur_call->pay = atof(array[i]);
/* Korrektur der falschen Eintr<74>ge vor dem 16-Jan-99 */
if (cur_call->pay == -1.0)
cur_call->pay = 0.0;
break;
case 17: if (!adapt) {
cur_call->provider = atoi(array[i]);
/* Korrektur der falschen Eintrage bis zum 16-Jan-99 */
if (cur_call->provider <= UNKNOWN)
cur_call->provider = preselect;
/* -lt- provider-# may change during time */
cur_call->provider = pnum2prefix(cur_call->provider,cur_call->t);
/* provider from logfile unknown in ratefile or rateconf
* --> default to preselected provider */
if (cur_call->provider == UNKNOWN)
cur_call->provider = pnum2prefix(preselect, cur_call->t);
} /* if */
break;
/* Seit 21-Jan-99 steht die Zone im Logfile */
case 18: cur_call->zone = atoi(array[i]);
break;
default : print_msg(PRT_ERR, "isdnrep: unknown element found `%s'!\n",array[i]);
break;
}
}
if (i < 3)
return(UNKNOWN);
/* alle Eintraege vor dem 21-Jan-99 ergaenzen:
- zone fehlte
- pay war falsch
*/
{
#if DEBUG
auto char yy[BUFSIZ];
#endif
if (abs((int)dur1 - (int)dur2) > 1) {
#if DEBUG
sprintf(yy, "\nWARNING: Wrong duration! dur1=%f, dur2=%f, durdiff=%f\n",
dur1, dur2, dur1 - dur2);
printf( yy);
#endif
cur_call->duration = dur1;
}
}
/* repair() recalculates the connection cost for entries with LOG_VERSION
* older than the current and sets cur_call->zone for outgoing calls with
* recorded one of -1 (=UNKNWON). The necessary information is taken from
* the current rate-file. The -r and -U options are also handled there.
*/
repair(cur_call);
if (cur_call->pay != 0.0 && modcost.mode)
{
if (modcost.mode == 1)
cur_call->pay *= modcost.number;
else if (modcost.mode == 2)
cur_call->pay /= modcost.number;
}
return(rc);
}
/*****************************************************************************/
static char **string_to_array(char *string)
{
static char *array[30];
auto char *ptr;
auto int i = 0;
memset(array, 0, sizeof(array));
if ((ptr = strrchr(string,C_DELIM)) != NULL)
*ptr = '\0';
array[0] = string;
while((string = strchr(string,C_DELIM)) != NULL)
{
*string++ = '\0';
array[++i] = string;
}
array[++i] = NULL;
return array;
}
/*****************************************************************************/
/* called for -p ... command line options */
int set_msnlist(char *String)
{
int Cnt;
int Value = 1;
char *Ptr = String;
if (ShowMSN)
return 0;
while((Ptr = strchr(Ptr,',')) != NULL)
{
Ptr++;
Value++;
}
ShowMSN = (char**) calloc(Value+1,sizeof(char*));
for(Cnt = 0; Cnt < Value; Cnt++)
ShowMSN[Cnt] = (char*) calloc(NUMSIZE,sizeof(char));
if (!ShowMSN)
{
print_msg(PRT_ERR, nomemory);
exit(1);
}
if (*String == 'n')
{
++String;
invertnumbers++;
}
Cnt = 0;
while(String)
{
if (*String == 'm')
{
Value = atoi(++String);
if (Value > 0 && Value <= mymsns)
{
strcpy(ShowMSN[Cnt],known[Value-1]->num);
Cnt++;
}
else
{
print_msg(PRT_ERR, "isdnrep: invalid MSN %d!\n", Cnt);
}
}
else
sscanf(String,"%[^,],",ShowMSN[Cnt++]);
String = strchr(String,',');
if (String) String++;
}
return 0;
}
/*****************************************************************************/
static int show_msn(one_call *cur_call)
{
int Cnt;
for(Cnt = 0; ShowMSN[Cnt] != NULL; Cnt++)
if (!num_match(ShowMSN[Cnt], cur_call->num[0]) ||
!num_match(ShowMSN[Cnt] , cur_call->num[1]))
return !invertnumbers;
else
if (!strcmp(ShowMSN[Cnt],"0"))
return !invertnumbers;
return invertnumbers;
}
/*****************************************************************************/
static char *print_currency(double money, int computed)
{
static char RetCode[256];
sprintf(RetCode,"%s %s%c", double2str(money, 8, 4, 0), currency, computed ? '*' : ' ');
return RetCode;
}
/*****************************************************************************/
static int print_sum_calls(sum_calls *s, int computed)
{
static char String[256];
one_call *tmp_call;
int RetCode;
if (bill)
printf( "%*s%s\n", 36, "", print_currency(s->pay, 0));
else {
if ((tmp_call = (one_call*) calloc(1,sizeof(one_call))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
tmp_call->eh = s->eh;
tmp_call->pay = s->pay;
tmp_call->obytes = s->obytes;
tmp_call->ibytes = s->ibytes;
sprintf(String,"%3d IN=%s, %3d OUT=%s, %3d failed",
s->in,
double2clock(s->din),
s->out,
double2clock(s->dout),
s->err);
RetCode = print_line(F_BODY_BOTTOM1,tmp_call,computed,String);
free(tmp_call);
} /* else */
return RetCode;
}
/*****************************************************************************/
static int add_one_call(sum_calls *s1, one_call *s2, double units)
{
if (s2->dir == DIALIN)
{
s1->in++;
s1->din += s2->duration > 0?s2->duration:0;
}
else
{
s1->out++;
s1->dout += s2->duration > 0?s2->duration:0;
s1->eh += s2->eh;
s1->pay += s2->pay;
}
s1->ibytes += s2->ibytes;
s1->obytes += s2->obytes;
return 0;
}
/*****************************************************************************/
static int clear_sum(sum_calls *s1)
{
s1->in = 0;
s1->out = 0;
s1->eh = 0;
s1->err = 0;
s1->din = 0;
s1->dout = 0;
s1->pay = 0;
s1->ibytes = 0L;
s1->obytes = 0L;
return 0;
}
/*****************************************************************************/
static int add_sum_calls(sum_calls *s1, sum_calls *s2)
{
s1->in += s2->in;
s1->out += s2->out;
s1->eh += s2->eh;
s1->err += s2->err;
s1->din += s2->din;
s1->dout += s2->dout;
s1->pay += s2->pay;
s1->ibytes += s2->ibytes;
s1->obytes += s2->obytes;
return 0;
}
/*****************************************************************************/
static void strich(int type)
{
if (html)
{
switch (type) {
case 3 :
case 1 : printf(H_LINE,get_format_size(),1);
break;
case 2 : printf(H_LINE,get_format_size(),3);
break;
default: print_msg(PRT_ERR, "isdnrep: internal error: invalid line flag!\n");
break;
} /* switch */
}
else
{
char *string;
int size = set_col_size();
if ((string = (char*) calloc(size+1,sizeof(char))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return;
}
while (size>0)
string[--size] = type==2?'=':'-';
printf("%s\n",string);
free(string);
}
} /* strich */
/*****************************************************************************/
static int n_match(char *Pattern, char* Number, char* version)
{
int RetCode = UNKNOWN;
char s[SHORT_STRING_SIZE];
if (!strcmp(version,LOG_VERSION_3) || !strcmp(version,LOG_VERSION_4) || !strcmp(version,LOG_VERSION))
{
RetCode = num_match(Pattern,Number);
}
else
if (!strcmp(version,LOG_VERSION_2))
{
strcpy(s,expand_number(Number));
RetCode = num_match(Pattern,s);
}
else
if (!strcmp(version,LOG_VERSION_1))
{
if ((RetCode = match(Pattern, Number,0)) != 0 &&
!strncmp(Pattern,areaprefix,strlen(areaprefix)) )
{
sprintf(s,"*%s%s",myarea/*+strlen(areaprefix)*/,Pattern);
RetCode = match(s,Number,0);
}
}
else
print_msg(PRT_ERR, "isdnrep: unknown version of logfile entries!\n");
return RetCode;
}
/*****************************************************************************/
static int html_header(void)
{
printf("Content-Type: text/html\n\n");
printf("<HTML>\n");
printf("<BODY bgcolor=%s>\n",H_BG_COLOR);
return 0;
}
/*****************************************************************************/
static int html_bottom(char *_progname, char *start, char *stop)
{
int value;
int value2;
char *progname = strdup(_progname);
char *ptr = strrchr(progname,'.');
if (ptr)
*ptr = '\0';
/*
printf(H_FORM_ON,_myname);
printf(H_FORM_DAY,"Date:","-t",40,10);
printf(H_FORM_OFF);
*/
if (!incomingonly)
{
value = incomingonly;
value2 = outgoingonly;
incomingonly++;
outgoingonly = 0;
if ((ptr = get_time_string(_begintime,endtime,0,0)) != NULL)
printf(H_LINK_DAY,_myname,ptr,"incoming only");
incomingonly = value;
outgoingonly = value2;
}
if (!outgoingonly)
{
value = incomingonly;
value2 = outgoingonly;
incomingonly = 0;
outgoingonly++;
if ((ptr = get_time_string(_begintime,endtime,0,0)) != NULL)
printf(H_LINK_DAY,_myname,ptr,"outgoing only");
incomingonly = value;
outgoingonly = value2;
}
if (outgoingonly || incomingonly)
{
value = incomingonly;
value2 = outgoingonly;
incomingonly = outgoingonly = 0;
if ((ptr = get_time_string(_begintime,endtime,0,0)) != NULL)
printf(H_LINK_DAY,_myname,ptr,"all calls");
incomingonly = value;
outgoingonly = value2;
}
value = print_failed;
print_failed = !print_failed;
if ((ptr = get_time_string(_begintime,endtime,0,0)) != NULL)
printf(H_LINK_DAY,_myname,ptr,value?"print_failed off":"print_failed on");
print_failed = value;
if ((ptr = get_time_string(_begintime,endtime,0,-1)) != NULL)
printf(H_LINK_DAY,_myname,ptr,"previous month");
if ((ptr = get_time_string(_begintime,endtime,-1,0)) != NULL)
printf(H_LINK_DAY,_myname,ptr,"previous day");
if ((ptr = get_time_string(_begintime,endtime,1,0)) != NULL)
printf(H_LINK_DAY,_myname,ptr,"next day");
if ((ptr = get_time_string(_begintime,endtime,0,1)) != NULL)
printf(H_LINK_DAY,_myname,ptr,"next month");
printf("\n<BR><H6>%s %s %s</H6>\n",progname,VERSION,__DATE__);
printf("\n</BODY>\n");
printf("<HEAD><TITLE>%s %s\n",progname,print_diff_date(start,stop));
printf("</TITLE>\n");
printf("</HTML>\n");
free(progname);
return 0;
}
/*****************************************************************************/
static char *print_diff_date(char *start, char *stop)
{
static char RetCode[64];
if (strcmp(start,stop))
sprintf(RetCode,"%s .. %s",start,stop);
else
sprintf(RetCode,"%s",start);
return RetCode;
}
/*****************************************************************************/
static int get_file_list(void)
{
if (read_path & F_VBOX)
set_dir_entries(vboxpath,set_vbox_entry);
if (read_path & F_FAX)
set_dir_entries(mgettypath,set_mgetty_entry);
qsort(file_root,file_root_member,sizeof(file_list*),Compare_files);
return 0;
}
/*****************************************************************************/
static int set_dir_entries(char *directory, int (*set_fct)(const char *, const char *))
{
struct dirent *eptr;
DIR *dptr;
if (directory != NULL)
{
if ((dptr = opendir(directory)) != NULL)
{
while ((eptr = readdir(dptr)) != NULL)
{
if (eptr->d_name[0] != '.')
{
if (set_fct(directory,eptr->d_name))
return(UNKNOWN);
}
}
closedir(dptr);
}
else
{
print_msg(PRT_ERR, "isdnrep: can't open directory `%s': %s!\n", directory, strerror(errno));
return(UNKNOWN);
}
}
return 0;
}
/*****************************************************************************/
static int set_vbox_entry(const char *path, const char *file)
{
struct tm tm;
file_list *lptr = NULL;
char string[PATH_MAX];
int cnt;
FILE *fp;
vaheader_t ptr;
sprintf(string,"%s%c%s",path,C_SLASH,file);
if ((fp = fopen(string,"r")) == NULL)
{
print_msg(PRT_ERR, msg1, string, strerror(errno));
return(UNKNOWN);
}
fread(&ptr,sizeof(vaheader_t),1,fp);
fclose(fp);
if (strncmp(ptr.magic,"VBOX",4))
{
/* Version 0.x and 1.x of vbox! */
if ((cnt = sscanf(file,"%2d%2d%2d%2d%2d%2d",
&(tm.tm_year),
&(tm.tm_mon),
&(tm.tm_mday),
&(tm.tm_hour),
&(tm.tm_min),
&(tm.tm_sec))) != 6)
{
print_msg(PRT_ERR, "isdnrep: invalid file name `%s'!\n",file);
return(UNKNOWN);
}
if ((lptr = (file_list*) calloc(1,sizeof(file_list))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
if (tm.tm_mday > 31)
{
int help = tm.tm_mday;
tm.tm_mday = tm.tm_year;
tm.tm_year = help;
}
tm.tm_mon--;
tm.tm_isdst = UNKNOWN;
lptr->name = strdup(file);
lptr->time = mktime(&tm);
lptr->type = C_VBOX;
lptr->used = 0;
lptr->version = 1;
lptr->compression = 0;
}
else
{
/* Version 2.x of vbox! */
if ((lptr = (file_list*) calloc(1,sizeof(file_list))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
lptr->name = strdup(file);
lptr->time = ntohl(ptr.time);
lptr->type = C_VBOX;
lptr->used = 0;
lptr->version = 2;
lptr->compression = ntohl(ptr.compression);
}
/*
else
{
print_msg(PRT_ERR, "Version %d of vbox is not implemented yet!\n",vboxversion);
print_msg(PRT_ERR, "Invalid version %d of vbox!\n",vboxversion);
return(UNKNOWN);
}
*/
return set_element_list(lptr);
}
/*****************************************************************************/
static int set_mgetty_entry(const char *path, const char *file)
{
file_list *lptr = NULL;
char string[PATH_MAX];
sprintf(string,"%s%c%s",path,C_SLASH,file);
if (access(string,R_OK))
{
print_msg(PRT_ERR, msg1, string, strerror(errno));
return(UNKNOWN);
}
if ((lptr = (file_list*) calloc(1,sizeof(file_list))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
lptr->name = strdup(file);
strcpy(string,"0x3");
strncpy(string+3,file+2,7);
lptr->time = strtol(string,NIL,0);
lptr->type = C_FAX;
lptr->used = 0;
lptr->version = 3;
lptr->compression = 0;
return set_element_list(lptr);
}
/*****************************************************************************/
static int set_element_list(file_list* elem)
{
if (file_root_size == file_root_member)
{
file_root_size += 10;
if ((file_root = (file_list**) realloc(file_root,sizeof(file_list*)*file_root_size)) == NULL)
{
print_msg(PRT_ERR, nomemory);
return(UNKNOWN);
}
}
file_root[file_root_member++] = elem;
return 0;
}
/*****************************************************************************/
static int Compare_files(const void *e1, const void *e2)
{
if ((*(file_list**) e1)->time > (*(file_list**) e2)->time)
return 1;
else
if ((*(file_list**) e1)->time < (*(file_list**) e2)->time)
return(UNKNOWN);
return 0;
}
/*****************************************************************************/
static file_list *get_file_to_call(time_t filetime, char type)
{
static file_list **ptr = NULL;
static int cnt;
static time_t _filetime;
int interval;
if (filetime == 0)
{
if (ptr != NULL)
{
ptr++;
cnt--;
}
}
else
{
ptr = file_root;
cnt = file_root_member;
_filetime = filetime;
}
while (cnt > 0 && (interval = time_in_interval((*ptr)->time,_filetime,type)) < 1)
{
if (interval == 0 && (*ptr)->used == 0 && (*ptr)->type == type)
{
(*ptr)->used = 1;
return (*ptr);
}
ptr++;
cnt--;
}
return NULL;
}
/*****************************************************************************/
static int time_in_interval(time_t t1, time_t t2, char type)
{
int begin;
int end;
switch (type)
{
case C_VBOX : begin = 0;
end = 10;
break;
case C_FAX : begin = -2;
end = 1;
break;
default : begin = 0;
end = 0;
break;
}
if ((int) t1 < ((int) t2) + begin)
return(-1);
if ((int) t1 > ((int) t2) + end)
return(1);
return 0;
}
/*****************************************************************************/
static char *get_links(time_t filetime, char type)
{
static char *string[5] = {NULL,NULL,NULL,NULL,NULL};
static int cnt = UNKNOWN;
file_list *ptr;
cnt = (cnt+1) % 5;
free(string[cnt]);
string[cnt] = NULL;
if (type == C_VBOX)
{
if ((ptr = get_file_to_call(filetime,type)) != NULL)
{
if ((string[cnt] = (char*) calloc(SHORT_STRING_SIZE,sizeof(char))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return NULL;
}
sprintf(string[cnt],H_LINK,_myname,type,ptr->version,nam2html(ptr->name),"phone");
}
}
else
if (type == C_FAX)
{
while((ptr = get_file_to_call(filetime,type)) != NULL)
{
append_fax(&(string[cnt]),ptr->name,type,ptr->version);
filetime = 0;
}
}
else
{
print_msg(PRT_ERR, "isdnrep: internal error: invalid type %d of file!\n", (int)type);
return NULL;
}
return string[cnt]?string[cnt]:" ";
}
/*****************************************************************************/
static char *append_fax(char **string, char *file, char type, int version)
{
static int cnt = 0;
char help[BUFSIZ];
char help2[20];
if (*string == NULL)
cnt = 1;
else
cnt++;
sprintf(help2,"&lt;%d&gt;",cnt);
sprintf(help,H_LINK,_myname,type,version,nam2html(file),help2);
if (*string == NULL)
*string = strdup(STR_FAX);
if ((*string = (char*) realloc(*string,sizeof(char)*(strlen(*string)+strlen(help)+2))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return NULL;
}
strcat(*string,help);
strcat(*string," ");
return *string;
}
/*****************************************************************************/
static char *nam2html(char *file)
{
static char RetCode[SHORT_STRING_SIZE];
char *ptr = RetCode;
while (*file != '\0')
{
switch (*file)
{
case '+': strcpy(ptr,"%2b");
ptr += 3;
file++;
break;
default : *ptr++ = *file++;
break;
}
}
*ptr = '\0';
return RetCode;
}
/*****************************************************************************/
static char *get_a_day(time_t t, int d_diff, int m_diff, int flag)
{
static char string[16];
struct tm *tm;
time_t cur_time;
char flag2 = 0;
if (t == 0)
{
if (flag & F_END)
return NULL;
time(&t);
flag2 = 1;
}
if (flag & F_END)
t++;
tm = localtime(&t);
tm->tm_mday += d_diff;
tm->tm_mon += m_diff;
tm->tm_isdst = UNKNOWN;
if (flag2 == 1)
{
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
}
t = mktime(tm);
if (flag & F_END)
t-=2;
time(&cur_time);
if (cur_time < t)
{
if (!(flag & F_END))
return NULL;
/*
if (flag & F_END)
t = cur_time;
else
return NULL;
*/
}
tm = localtime(&t);
sprintf(string,"%02d%02d%02d%02d%04d.%02d",tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_year+1900,tm->tm_sec);
return string;
}
/*****************************************************************************/
static char *get_time_string(time_t begin, time_t end, int d_diff, int m_diff)
{
static char string[256];
char *ptr = NULL;
strcpy(string,get_default_html_params());
if ((ptr = get_a_day(begin,d_diff,m_diff,F_BEGIN)) != NULL)
{
strcat(string,"+-t");
strcat(string,ptr);
if ((ptr = get_a_day(end,d_diff,m_diff,F_END)) != NULL)
{
strcat(string,"-");
strcat(string,ptr);
}
return string;
}
return NULL;
}
/*****************************************************************************/
static char *get_default_html_params(void)
{
static char string[50];
sprintf(string,"-w%d%s%s%s",
html-1,
/* ^^---sehr gefaehrlich, da eine UND-Verknuepfung!!! */
print_failed?"+-E":"",
outgoingonly?"+-o":"",
incomingonly?"+-i":"");
return string;
}
/*****************************************************************************/
static char *create_vbox_file(char *file, int *compression)
{
int fdin, fdout, len;
char string[BUFSIZ];
char *fileout = NULL;
vaheader_t header;
if ((fdin = open(file,O_RDONLY)) == -1)
{
print_msg(PRT_ERR, msg1, file, strerror(errno));
return NULL;
}
if (read(fdin,&header,sizeof(vaheader_t)) == sizeof(vaheader_t))
{
if (compression != NULL)
*compression = ntohl(header.compression);
fileout = strdup("/tmp/isdnrepXXXXXX");
if( (fdout = mkstemp(fileout)) < 0 )
{
print_msg(PRT_ERR, msg1, fileout, strerror(errno));
close(fdin);
free(fileout);
return NULL;
}
while((len = read(fdin,string,BUFSIZ)) > 0)
{
if (write(fdout,string,len) != len)
{
print_msg(PRT_ERR, "isdnrep: can't write to file `%s': %s!\n", fileout, strerror(errno));
close(fdout);
close(fdin);
unlink(fileout);
free(fileout);
return NULL;
}
}
close(fdout);
if (len < 0)
{
print_msg(PRT_ERR, "isdnrep: can't read from file `%s': %s!\n", file, strerror(errno));
close(fdin);
unlink(fileout);
free(fileout);
return NULL;
}
}
close(fdin);
return fileout;
}
/*****************************************************************************/
static int htoi(char *s)
{
int value;
char c;
c = s[0];
if (isupper(c))
c = tolower(c);
value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
c = s[1];
if (isupper(c))
c = tolower(c);
value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
return (value);
}
/*****************************************************************************/
static char *url_unescape(char *str)
{
char *RetCode = str;
char *dest = str;
while (str[0])
{
if (str[0] == '+')
dest[0] = ' ';
else if (str[0] == '%' && isxdigit(str[1]) && isxdigit(str[2]))
{
dest[0] = (unsigned char) htoi(str + 1);
str += 2;
}
else
dest[0] = str[0];
str++;
dest++;
}
dest[0] = '\0';
return RetCode;
}
/*****************************************************************************/
int new_args(int *nargc, char ***nargv)
{
int index = *nargc;
int index2 = 1;
char **h_args;
char *h_env;
if ((h_env = getenv(H_ENV_VAR)) == NULL)
return 1;
if ((h_args = get_http_args(h_env,&index)) == NULL)
return 2;
while (index2 < *nargc)
h_args[index++] = (*nargv)[index2++];
h_args[0] = (*nargv)[0];
h_args[index] = NULL;
*nargc = index;
*nargv = h_args;
unlink("/tmp/iii");
{
FILE *fp = fopen("/tmp/iii","w");
for(index2=0;index2 < index;index2++)
{
fputs(h_args[index2],fp);
fputs("*\n",fp);
}
fclose(fp);
}
return 0;
}
/*****************************************************************************/
static char **get_http_args(char *str, int *index)
{
char **RetCode = NULL;
if (index == NULL)
return NULL;
if (*index < 0)
*index = 0;
str = url_unescape(strdup(str));
if (str == NULL)
return NULL;
if (str == '\0')
{
free(str);
return NULL;
}
if ((RetCode = (char**) calloc(20+(*index),sizeof(char*))) == NULL)
{
print_msg(PRT_ERR, nomemory);
return NULL;
}
*index = 1;
RetCode[0] = NULL;
RetCode[(*index)++] = str;
while(*str != '\0')
{
if (*str == ' ' || *str == '=')
{
*str++ = '\0';
if (*str != ' ' && *str != '=' && *str != '\0')
RetCode[(*index)++] = str;
}
else
str++;
}
RetCode[*index] = NULL;
return RetCode;
}
/*****************************************************************************/
static int find_format_length(char *string)
{
int len;
char type;
char* dest;
if (string == NULL)
return(UNKNOWN);
while (*string != '\0')
{
if (*string++ == '%')
{
if (*string == '%')
{
string++;
continue;
}
while(index("0123456789-",*string)) string++;
if (*string == '\0')
return(UNKNOWN);
if (*string == '.')
{
if (sscanf(++string,"%d%c",&len,&type) == 2 && type == 's' && len >= 0)
{
if ((dest = index(--string,'s')) == NULL)
return(UNKNOWN);
memmove(string,dest,strlen(dest)+1);
return len;
}
if (*string == 's')
return 0;
return(UNKNOWN);
}
else if (*string == 's')
return(UNKNOWN);
}
}
return(UNKNOWN);
}
/*****************************************************************************/
static int app_fmt_string(char *target, int targetlen, char *fmt, int condition, char *value)
{
char tmpfmt[BUFSIZ];
char tmpvalue[BUFSIZ];
int len;
strcpy(tmpfmt,fmt);
strcpy(tmpvalue,value);
len = find_format_length(tmpfmt);
if (len != UNKNOWN && len > 0 && strlen(tmpvalue) > len)
tmpvalue[len] = '\0';
value = condition?html_conv(tmpvalue):tmpvalue;
return snprintf(target,targetlen,tmpfmt,value);
}
/*****************************************************************************/
/* returns 0 if check is allowed by -x option, 1 if not, 2 in case of error */
static int check_day_hour(bitfield *days, bitfield *hours, const time_t check)
{
struct tm *tp, t;
if (!days[INCLUDE] && !days[EXCLUDE] && !hours[INCLUDE] && !hours[EXCLUDE])
return 0;
if ( !(tp = localtime(&check)) )
return 2;
t = *tp; /* save result from further time.h functioncalls */
if ( hours[INCLUDE] && !(hours[INCLUDE] & (1 << t.tm_hour)) )
return 1; /* hour is not included */
if ( hours[EXCLUDE] && hours[EXCLUDE] & (1 << t.tm_hour) )
return 1; /* hour is excluded */
if ( days[INCLUDE] && !isDay(&t, days[INCLUDE], 0) )
return 1; /* day is not included */
if ( days[EXCLUDE] && isDay(&t, days[EXCLUDE], 0) )
return 1; /* day is excluded */
return 0;
} /* /check_day_hour() */
/*****************************************************************************/
/* find provider for recalculation of connection fees (-r Option) */
int prep_recalc (void)
{
int pnum;
char *variant;
/* eror messages should work in HTML mode (text/html) too */
if (recalc.mode == '-' || /* just recalc, no different provider */
recalc.mode == 'b' || /* do lcr with booked providers */
recalc.mode == 'B' ) /* do lcr with all providers */
return 1;
if (recalc.mode == 'p')
{
if (strchr(recalc.input, '_')) /* -rp21_0 */
{
recalc.prefix = pnum2prefix_variant(recalc.input, 0);
}
else /* -rp21 */
{
pnum = atoi(recalc.input);
recalc.prefix = pnum2prefix(pnum, 0);
}
}
else if (recalc.mode == 'v')
{
if ( (variant = strchr(recalc.input, '_')) )
{ /* -rv01021_0 */
int p;
char *vbn;
char s[16];
variant++;
for (p=0; p<getNProvider(); p++)
{ /* something like vbn2prefix_variant */
vbn = getProviderVBN(p);
if (strncmp(vbn, recalc.input, strlen(vbn)))
continue;
pnum = prefix2pnum(p);
snprintf(s, 12, "%d_%s", pnum, variant );
if ( (recalc.prefix = pnum2prefix_variant(s, 0)) != UNKNOWN )
break;
}
}
else /* -rv01021 */
{
int l;
recalc.prefix = vbn2prefix(recalc.input, &l);
}
}
else
{
printf("Unknown provider selection mode in option -r: %c.\n", recalc.mode);
return 0;
}
if (recalc.prefix == UNKNOWN)
{
printf("No provider found in ratefile for %s %s.\n",
(recalc.mode=='p') ? "Pnum" : "VBN", recalc.input);
return 0;
}
return 1;
}
/*****************************************************************************/
/* parse contents of select summaries option,
* with NULL as input, all summaries are enabled as default */
int select_summaries(int *list, char *input)
{
int bit=1;
char *s=SUM__CHARS;
if (input)
while (*s)
{
if ( strchr(input, *s) )
list[INCLUDE] |= bit;
if ( strchr(input, toupper(*s)) )
list[EXCLUDE] |= bit;
bit <<= 1;
s++;
}
list[RESULT] = list[INCLUDE] ? list[INCLUDE] : SUM_ALL;
list[RESULT] &= ~list[EXCLUDE];
return list[RESULT];
}
/*****************************************************************************/
/* parse contents of select day/hour option,
* result is NULL for correct option or pointer to first failed char */
char *select_day_hour(bitfield *days, bitfield *hours, char *input)
{
char *s=input, *t;
int inex;
char a, b, c;
int i, j, k;
if (!s || !*s)
return NULL;
s--; /* char before [dDhH] */
do
{
/* first char selects day/hour include/EXCLUDE */
inex = islower(*++s) ? INCLUDE : EXCLUDE;
if (tolower(*s) == 'd')
{
do
{
t = ++s; /* move behind 'd', 'D', or ',' */
if (isdigit(*s))
{
a = b = *s++;
if (*s == '-')
{
s++;
b = *s++;
}
if (a < '1' || b < '1' || a > '7' || b > '7')
return t;
if (a <= b)
for (c=a; c <= b; c++) /* e.g. 1-1 or 1-5 */
days[inex] |= 1 << (MONDAY + (c - '1'));
else
{
for (c=a; c <= '7'; c++) /* e.g. 6-1 -> 6-7, 1-1 */
days[inex] |= 1 << (MONDAY + (c - '1'));
for (c='1'; c <= b; c++)
days[inex] |= 1 << (MONDAY + (c - '1'));
}
}
else
{
if (*s == 'W')
days[inex] |= 1 << WORKDAY;
else if (*s == 'E')
days[inex] |= 1 << WEEKEND;
else if (*s == 'H')
days[inex] |= 1 << HOLIDAY;
else if (*s == '*')
days[inex] |= 1 << EVERYDAY;
else
return s;
s++;
}
}
while (*s == ',');
}
else if (tolower(*s) == 'h')
{
do
{
t = ++s; /* move behind 'h', 'H', or ',' */
if (*s == '*')
{
i = 0; j = 24;
s++;
}
else
{
errno = 0;
i = j = (int) strtol(s, &s, 10);
if (errno)
return s;
if (*s == '-')
{
s++;
errno = 0;
j = (int) strtol(s, &s, 10);
if (errno)
return s;
}
i = (i==24) ? 0 : i;
j = (j==24) ? 0 : j;
j = (i==j) ? j+1 : j; /* e.g. 17-17 (wrong) -> 17-18 */
j = (j==24) ? 0 : j;
if (i < 0 || j < 0 || i > 23 || j > 23)
return t; /* wrong values in range */
}
if (i <= j)
for (k=i; k < j; k++) /* e.g. 09-18 */
hours[inex] |= 1 << k;
else
{
for (k=i; k < 24; k++) /* e.g. 18-09 -> 18-00, 00-18 */
hours[inex] |= 1 << k;
for (k=0; k < j; k++)
hours[inex] |= 1 << k;
}
}
while (*s == ',');
}
else
return s;
}
while (*s == ':');
if (*s)
return s;
#if DEBUG
fprintf(stderr, "xopt: d= %04X, D= %04X, h= %07X, H= %07X\n",
(int) days[INCLUDE], (int) days[EXCLUDE],
(int) hours[INCLUDE], (int) hours[EXCLUDE]);
#endif
return NULL;
} /* /select_day_hour() */
/* vim:set ts=2: */
/*****************************************************************************/