isdn4k-utils/isdnlog/isdnlog/isdnlog.c

1881 lines
56 KiB
C
Raw Blame History

/* $Id: isdnlog.c,v 1.77 2007/01/05 04:23:58 tobiasb Exp $
*
* ISDN accounting for isdn4linux. (log-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
*
* $Log: isdnlog.c,v $
* Revision 1.77 2007/01/05 04:23:58 tobiasb
* Made isdnrep and isdnrate buildable under cygwin. See ChangeLog for details.
*
* Revision 1.76 2005/02/23 14:33:39 tobiasb
* New feature: provider skipping.
* Certain providers can be completely ignored (skipped) when loading the
* rate-file. The selection is done by Q: tags in rate.conf or by skipProv=
* in the parameter file. The syntax is explained in the new manual page
* rate.conf(5). Absurd settings for provider skipping may cause trouble.
* The version number will change to 4.70 in a few days after an update
* of the rate-de.dat.
*
* Revision 1.75 2004/12/16 22:40:30 tobiasb
* Fix for rate computation of outgoing calls from other devices and for logging
* of calls from and to the observed card (simultaneous SETUP messages).
* Area code setting also in parameterfile.
*
* Revision 1.74 2004/09/29 21:02:01 tobiasb
* Changed handling of multiple "calling party number" information elements.
* The network provided number is now preferred in any case. The other
* number (typical set by originating user) can be ignored using the
* ignoreCOLP or -U setting, which allows different values for COLP and CLIP
* now. (The old behaviour was to use the first number if ignoreCOLP was set
* and the network provided number regardless of order otherwise.)
*
* Revision 1.73 2004/09/05 22:04:55 tobiasb
* New parameter file entry "ignoreUPD" for suppressing "Unexpected
* discrimator (...)" messages, demanded by G<>nther J. Niederwimmer
* on the suse-isdn mailing list.
*
* Revision 1.72 2004/01/28 14:27:46 tobiasb
* Second step in restricting fds at isdnlog restart and script starting.
* The fd limit is now taken from getrlimit() instead of NR_OPEN.
* Close_Fds(first) which tries to close all possible fds is generally
* built in but the execution must be requested with "closefds=yes" in
* the parameterfile otherwise the isdnlog behaviour remains unchanged.
*
* Revision 1.71 2004/01/26 15:20:08 tobiasb
* First step to close all unnecessary open file descriptors before
* starting a start script as reaction to a call. The same applies to the
* restart of isdnlog using SIGHUP. Till now each restart increases the
* number of used fds.
* For now the modifications are inactive by default. They can be enabled
* by adding the line "DEFS += -DFD_AT_EXEC_MODE=1" to ../Makefile.in.
* The next isdnlog (4.68) will have this enabled per default.
* The upper limit for fd numbers is taken from NR_OPEN in <linux/limits.h>.
* If there is a smarter way to access this limit, please let me know.
* Another approach would be to set the close-on-exec flag on each fd
* directly after it is opened. This would require more extensive changes.
* I'd like to thank Jan Bernhardt for discovering this problem.
*
* Revision 1.70 2004/01/04 02:22:53 tobiasb
* Show supported database(s) at startup.
*
* Revision 1.69 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.68 2001/10/15 19:51:48 akool
* isdnlog-4.53
* - verified Leo's correction of Paul's byte-order independent Patch to the CDB
* (now it's Ok, Leo, and *many* thanks to Paul!)
* - "rate-de.dat" updated
* - added "-Q" option to isdnlog
*
* Revision 1.67 2001/08/18 12:01:25 paul
* Close stdout and stderr if we're becoming a daemon.
*
* Revision 1.66 2000/09/05 08:05:02 paul
* Now isdnlog doesn't use any more ISDN_XX defines to determine the way it works.
* It now uses the value of "COUNTRYCODE = 999" to determine the country, and sets
* a variable mycountrynum to that value. That is then used in the code to set the
* way isdnlog works.
* It works for me, please check it! No configure.in / doc changes yet until
* it has been checked to work.
* So finally a version of isdnlog that can be compiled and distributed
* internationally.
*
* Revision 1.65 2000/07/19 19:41:32 akool
* isdnlog-4.34
* - since around Linux-2.2.16 signals are *not* reset to their default
* behavior when raised :-( (bug or feature?).
* - isdnlog/rate-pl.dat ... changes from Karsten Voss <vossdoku@gmx.net>
* - populated "samples/isdn.conf.de" with all german Internet-by-Call numbers
*
* Revision 1.64 2000/07/18 22:26:05 akool
* isdnlog-4.33
* - isdnlog/tools/rate.c ... Bug fixed
* - isdnlog/isdnlog/isdnlog.c ... check for callfmt
* - "rate-de.dat" corrected (duplicates removed)
*
* Revision 1.63 2000/06/29 17:38:27 akool
* - Ported "imontty", "isdnctrl", "isdnlog", "xmonisdn" and "hisaxctrl" to
* Linux-2.4 "devfs" ("/dev/isdnctrl" -> "/dev/isdn/isdnctrl")
*
* Revision 1.62 2000/06/20 17:09:59 akool
* isdnlog-4.29
* - better ASN.1 display
* - many new rates
* - new Option "isdnlog -Q" dump's "/etc/isdn/isdn.conf" into a SQL database
*
* Revision 1.61 2000/04/02 17:35:07 akool
* isdnlog-4.18
* - isdnlog/isdnlog/isdnlog.8.in ... documented hup3
* - isdnlog/tools/dest.c ... _DEMD1 not recogniced as key
* - mySQL Server version 3.22.27 support
* - new rates
*
* Revision 1.60 2000/03/09 18:50:02 akool
* isdnlog-4.16
* - isdnlog/samples/isdn.conf.no ... changed VBN
* - isdnlog/isdnlog/isdnlog.c .. ciInterval
* - isdnlog/isdnlog/processor.c .. ciInterval
* - isdnlog/tools/tools.h .. ciInterval, abclcr conf option
* - isdnlog/tools/isdnconf.c .. ciInterval, abclcr conf option
* - isdnlog/tools/isdnrate.c .. removed a warning
* - isdnlog/NEWS ... updated
* - isdnlog/README ... updated
* - isdnlog/isdnlog/isdnlog.8.in ... updated
* - isdnlog/isdnlog/isdnlog.5.in ... updated
* - isdnlog/samples/provider ... NEW
*
* ==> Please run a make clean, and be sure to read isdnlog/NEWS for changes
* ==> and new features.
*
* Revision 1.59 2000/02/11 10:41:52 akool
* isdnlog-4.10
* - Set CHARGEINT to 11 if < 11
* - new Option "-dx" controls ABC_LCR feature (see README for infos)
* - new rates
*
* Revision 1.58 2000/02/03 18:24:50 akool
* isdnlog-4.08
* isdnlog/tools/rate.c ... LCR patch again
* isdnlog/tools/isdnrate.c ... LCR patch again
* isdnbill enhanced/fixed
* DTAG AktivPlus fixed
*
* Revision 1.57 2000/02/02 22:43:09 akool
* isdnlog-4.07
* - many new rates per 1.2.2000
*
* Revision 1.56 1999/12/31 13:30:01 akool
* isdnlog-4.00 (Millenium-Edition)
* - Oracle support added by Jan Bolt (Jan.Bolt@t-online.de)
*
* Revision 1.55 1999/11/08 21:09:39 akool
* isdnlog-3.65
* - added "B:" Tag to "rate-xx.dat"
*
* Revision 1.54 1999/11/07 13:29:27 akool
* isdnlog-3.64
* - new "Sonderrufnummern" handling
*
* Revision 1.53 1999/10/30 18:03:31 akool
* - fixed "-q" option
* - workaround for "Sonderrufnummern"
*
* Revision 1.52 1999/10/29 19:46:00 akool
* isdnlog-3.60
* - successfully ported/tested to/with:
* - Linux-2.3.24 SMP
* - egcs-2.91.66
* using -DBIG_PHONE_NUMBERS
*
* - finally added working support for HFC-card in "echo mode"
* try this:
* hisaxctrl bri 10 1
* hisaxctrl bri 12 1
* isdnlog -21 -1
* -----------------^^ new option
*
* Revision 1.51 1999/10/25 18:33:15 akool
* isdnlog-3.57
* WARNING: Experimental version!
* Please use isdnlog-3.56 for production systems!
*
* Revision 1.50 1999/09/26 10:55:20 akool
* isdnlog-3.55
* - Patch from Oliver Lauer <Oliver.Lauer@coburg.baynet.de>
* added hup3 to option file
* - changed country-de.dat to ISO 3166 Countrycode / Airportcode
*
* Revision 1.49 1999/09/11 22:28:23 akool
* isdnlog-3.50
* added 3. parameter to "-h" Option: Controls CHARGEHUP for providers like
* DTAG (T-Online) or AOL.
* Many thanks to Martin Lesser <m-lesser@lesser-com.de>
*
* Revision 1.48 1999/08/20 19:28:12 akool
* isdnlog-3.45
* - removed about 1 Mb of (now unused) data files
* - replaced areacodes and "vorwahl.dat" support by zone databases
* - fixed "Sonderrufnummern"
* - rate-de.dat :: V:1.10-Germany [20-Aug-1999 21:23:27]
*
* Revision 1.47 1999/06/28 19:16:03 akool
* isdnlog Version 3.38
* - new utility "isdnrate" started
*
* Revision 1.46 1999/06/16 23:37:31 akool
* fixed zone-processing
*
* Revision 1.45 1999/06/15 20:04:03 akool
* isdnlog Version 3.33
* - big step in using the new zone files
* - *This*is*not*a*production*ready*isdnlog*!!
* - Maybe the last release before the I4L meeting in Nuernberg
*
* Revision 1.44 1999/06/13 14:07:44 akool
* isdnlog Version 3.32
*
* - new option "-U1" (or "ignoreCOLP=1") to ignore CLIP/COLP Frames
* - TEI management decoded
*
* Revision 1.43 1999/05/22 10:18:28 akool
* isdnlog Version 3.29
*
* - processing of "sonderrufnummern" much more faster
* - detection for sonderrufnummern of other provider's implemented
* (like 01929:FreeNet)
* - Patch from Oliver Lauer <Oliver.Lauer@coburg.baynet.de>
* - Patch from Markus Schoepflin <schoepflin@ginit.de>
* - easter computing corrected
* - rate-de.dat 1.02-Germany [22-May-1999 11:37:33] (from rate-CVS)
* - countries-de.dat 1.02-Germany [22-May-1999 11:37:47] (from rate-CVS)
* - new option "-B" added (see README)
* (using "isdnlog -B16 ..." isdnlog now works in the Netherlands!)
*
* Revision 1.42 1999/05/13 11:39:18 akool
* isdnlog Version 3.28
*
* - "-u" Option corrected
* - "ausland.dat" removed
* - "countries-de.dat" fully integrated
* you should add the entry
* "COUNTRYFILE = /usr/lib/isdn/countries-de.dat"
* into section "[ISDNLOG]" of your config file!
* - rate-de.dat V:1.02-Germany [13-May-1999 12:26:24]
* - countries-de.dat V:1.02-Germany [13-May-1999 12:26:26]
*
* Revision 1.41 1999/05/04 19:32:37 akool
* isdnlog Version 3.24
*
* - fully removed "sondernummern.c"
* - removed "gcc -Wall" warnings in ASN.1 Parser
* - many new entries for "rate-de.dat"
* - better "isdnconf" utility
*
* Revision 1.40 1999/04/10 16:35:27 akool
* isdnlog Version 3.13
*
* WARNING: This is pre-ALPHA-dont-ever-use-Code!
* "tarif.dat" (aka "rate-xx.dat"): the next generation!
*
* You have to do the following to test this version:
* cp /usr/src/isdn4k-utils/isdnlog/holiday-de.dat /etc/isdn
* cp /usr/src/isdn4k-utils/isdnlog/rate-de.dat /usr/lib/isdn
* cp /usr/src/isdn4k-utils/isdnlog/samples/rate.conf.de /etc/isdn/rate.conf
*
* After that, add the following entries to your "/etc/isdn/isdn.conf" or
* "/etc/isdn/callerid.conf" file:
*
* [ISDNLOG]
* SPECIALNUMBERS = /usr/lib/isdn/sonderrufnummern.dat
* HOLIDAYS = /usr/lib/isdn/holiday-de.dat
* RATEFILE = /usr/lib/isdn/rate-de.dat
* RATECONF = /etc/isdn/rate.conf
*
* Please replace any "de" with your country code ("at", "ch", "nl")
*
* Good luck (Andreas Kool and Michael Reinelt)
*
* Revision 1.39 1999/03/25 19:39:51 akool
* - isdnlog Version 3.11
* - make isdnlog compile with egcs 1.1.7 (Bug report from Christophe Zwecker <doc@zwecker.com>)
*
* Revision 1.38 1999/03/24 19:37:46 akool
* - isdnlog Version 3.10
* - moved "sondernnummern.c" from isdnlog/ to tools/
* - "holiday.c" and "rate.c" integrated
* - NetCologne rates from Oliver Flimm <flimm@ph-cip.uni-koeln.de>
* - corrected UUnet and T-Online rates
*
* Revision 1.37 1999/03/20 14:33:02 akool
* - isdnlog Version 3.08
* - more tesion)) Tarife from Michael Graw <Michael.Graw@bartlmae.de>
* - use "bunzip -f" from Franz Elsner <Elsner@zrz.TU-Berlin.DE>
* - show another "cheapest" hint if provider is overloaded ("OVERLOAD")
* - "make install" now makes the required entry
* [GLOBAL]
* AREADIFF = /usr/lib/isdn/vorwahl.dat
* - README: Syntax description of the new "rate-at.dat"
* - better integration of "sondernummern.c" from mario.joussen@post.rwth-aachen.de
* - server.c: buffer overrun fix from Michael.Weber@Post.RWTH-Aachen.DE (Michael Weber)
*
* Revision 1.36 1999/03/14 14:26:28 akool
* - isdnlog Version 3.05
* - new Option "-u1" (or "ignoreRR=1")
* - added version information to "sonderrufnummern.dat"
* - added debug messages if sonderrufnummern.dat or tarif.dat could not be opened
* - sonderrufnummern.dat V 1.01 - new 01805 rates
*
* Revision 1.35 1999/02/28 19:32:38 akool
* Fixed a typo in isdnconf.c from Andreas Jaeger <aj@arthur.rhein-neckar.de>
* CHARGEMAX fix from Oliver Lauer <Oliver.Lauer@coburg.baynet.de>
* isdnrep fix from reinhard.karcher@dpk.berlin.fido.de (Reinhard Karcher)
* "takt_at.c" fixes from Ulrich Leodolter <u.leodolter@xpoint.at>
* sondernummern.c from Mario Joussen <mario.joussen@post.rwth-aachen.de>
* Reenable usage of the ZONE entry from Schlottmann-Goedde@t-online.de
* Fixed a typo in callerid.conf.5
*
* Revision 1.34 1999/01/24 19:01:31 akool
* - second version of the new chargeint database
* - isdnrep reanimated
*
* Revision 1.33 1999/01/10 15:23:13 akool
* - "message = 0" bug fixed (many thanks to
* Sebastian Kanthak <sebastian.kanthak@muehlheim.de>)
* - CITYWEEKEND via config-file possible
* - fixes from Michael Reinelt <reinelt@eunet.at>
* - fix a typo in the README from Sascha Ziemann <szi@aibon.ping.de>
* - Charge for .at optimized by Michael Reinelt <reinelt@eunet.at>
* - first alpha-Version of the new chargeinfo-Database
* ATTENTION: This version requires the following manual steps:
* cp /usr/src/isdn4k-utils/isdnlog/tarif.dat /usr/lib/isdn
* cp /usr/src/isdn4k-utils/isdnlog/samples/tarif.conf /etc/isdn
*
* Revision 1.32 1998/12/31 09:58:50 paul
* converted termio calls to termios
*
* Revision 1.31 1998/12/09 20:39:28 akool
* - new option "-0x:y" for leading zero stripping on internal S0-Bus
* - new option "-o" to suppress causes of other ISDN-Equipment
* - more support for the internal S0-bus
* - Patches from Jochen Erwied <mack@Joker.E.Ruhr.DE>, fixes TelDaFax Tarif
* - workaround from Sebastian Kanthak <sebastian.kanthak@muehlheim.de>
* - new CHARGEINT chapter in the README from
* "Georg v.Zezschwitz" <gvz@popocate.hamburg.pop.de>
*
* Revision 1.30 1998/11/24 20:51:31 akool
* - changed my email-adress
* - new Option "-R" to supply the preselected provider (-R24 -> Telepassport)
* - made Provider-Prefix 6 digits long
* - full support for internal S0-bus implemented (-A, -i Options)
* - isdnlog now ignores unknown frames
* - added 36 allocated, but up to now unused "Auskunft" Numbers
* - added _all_ 122 Providers
* - Patch from Jochen Erwied <mack@Joker.E.Ruhr.DE> for Quante-TK-Anlagen
* (first dialed digit comes with SETUP-Frame)
*
* Revision 1.29 1998/11/17 00:37:39 akool
* - fix new Option "-i" (Internal-S0-Bus)
* - more Providers (Nikoma, First Telecom, Mox)
* - isdnrep-Bugfix from reinhard.karcher@dpk.berlin.fido.de (Reinhard Karcher)
* - Configure.help completed
*
* Revision 1.28 1998/11/07 17:12:56 akool
* Final cleanup. This _is_ isdnlog-3.00
*
* Revision 1.27 1998/11/01 08:49:43 akool
* - fixed "configure.in" problem with NATION_*
* - DESTDIR fixes (many thanks to Michael Reinelt <reinelt@eunet.at>)
* - isdnrep: Outgoing calls ordered by Zone/Provider/MSN corrected
* - new Switch "-i" -> running on internal S0-Bus
* - more providers
* - "sonderrufnummern.dat" extended (Frag Fred, Telegate ...)
* - added AVM-B1 to the documentation
* - removed the word "Teles" from the whole documentation ;-)
*
* Revision 1.26 1998/10/26 20:21:14 paul
* thinko in check for symlink in /tmp
*
* Revision 1.25 1998/10/22 14:10:52 paul
* Check that /tmp/isdnctrl0 is not a symbolic link, which is a potential
* security threat (it can point to /etc/passwd or so!)
*
* Revision 1.24 1998/10/18 20:13:33 luethje
* isdnlog: Added the switch -K
*
* Revision 1.23 1998/10/06 12:50:57 paul
* As the exec is done within the signal handler, SIGHUP was blocked after the
* first time. Now SIGHUP is unblocked so that you can send SIGHUP more than once.
*
* Revision 1.22 1998/09/26 18:29:07 akool
* - quick and dirty Call-History in "-m" Mode (press "h" for more info) added
* - eat's one more socket, Stefan: sockets[3] now is STDIN, FIRST_DESCR=4 !!
* - Support for tesion)) Baden-Wuerttemberg Tarif
* - more Providers
* - Patches from Wilfried Teiken <wteiken@terminus.cl-ki.uni-osnabrueck.de>
* - better zone-info support in "tools/isdnconf.c"
* - buffer-overrun in "isdntools.c" fixed
* - big Austrian Patch from Michael Reinelt <reinelt@eunet.at>
* - added $(DESTDIR) in any "Makefile.in"
* - new Configure-Switches "ISDN_AT" and "ISDN_DE"
* - splitted "takt.c" and "tools.c" into
* "takt_at.c" / "takt_de.c" ...
* "tools_at.c" / "takt_de.c" ...
* - new feature
* CALLFILE = /var/log/caller.log
* CALLFMT = %b %e %T %N7 %N3 %N4 %N5 %N6
* in "isdn.conf"
* - ATTENTION:
* 1. "isdnrep" dies with an seg-fault, if not HTML-Mode (Stefan?)
* 2. "isdnlog/Makefile.in" now has hardcoded "ISDN_DE" in "DEFS"
* should be fixed soon
*
* Revision 1.21 1998/06/21 11:52:46 akool
* First step to let isdnlog generate his own AOCD messages
*
* Revision 1.20 1998/06/07 21:08:31 akool
* - Accounting for the following new providers implemented:
* o.tel.o, Tele2, EWE TEL, Debitel, Mobilcom, Isis, NetCologne,
* TelePassport, Citykom Muenster, TelDaFax, Telekom, Hutchison Telekom,
* tesion)), HanseNet, KomTel, ACC, Talkline, Esprit, Interoute, Arcor,
* WESTCom, WorldCom, Viag Interkom
*
* Code shamelessly stolen from G.Glendown's (garry@insider.regio.net)
* program http://www.insider.org/tarif/gebuehr.c
*
* - Telekom's 10plus implemented
*
* - Berechnung der Gebuehrenzone implementiert
* (CityCall, RegioCall, GermanCall, GlobalCall)
* The entry "ZONE" is not needed anymore in the config-files
*
* you need the file
* http://swt.wi-inf.uni-essen.de/~omatthes/tgeb/vorwahl2.exe
* and the new entry
* [GLOBAL]
* AREADIFF = /usr/lib/isdn/vorwahl.dat
* for that feature.
*
* Many thanks to Olaf Matthes (olaf.matthes@uni-essen.de) for the
* Data-File and Harald Milz for his first Perl-Implementation!
*
* - Accounting for all "Sonderrufnummern" (0010 .. 11834) implemented
*
* You must install the file
* "isdn4k-utils/isdnlog/sonderrufnummern.dat.bz2"
* as "/usr/lib/isdn/sonderrufnummern.dat"
* for that feature.
*
* ATTENTION: This is *NO* production-code! Please test it carefully!
*
* Revision 1.19 1998/05/19 15:55:51 paul
* Moved config stuff for City Weekend from isdnlog.c to tools/isdnconf.c, so
* that isdnrep also understands a "cityweekend=y" line in isdn.conf.
*
* Revision 1.18 1998/05/19 15:47:03 paul
* If logfile name is specified with leading '+', the logfile is not truncated
* when isdnlog starts; instead, new messages are appended.
*
* Revision 1.17 1998/03/29 23:18:07 luethje
* mySQL-Patch of Sascha Matzke
*
* Revision 1.16 1998/03/08 12:13:38 luethje
* Patches by Paul Slootman
*
* Revision 1.15 1998/03/08 11:42:50 luethje
* I4L-Meeting Wuerzburg final Edition, golden code - Service Pack number One
*
* Revision 1.14 1998/02/08 09:36:51 calle
* fixed problems with FD_ISSET and glibc, if descriptor is not open.
*
* Revision 1.13 1997/06/22 23:03:23 luethje
* In subsection FLAGS it will be checked if the section name FLAG is korrect
* isdnlog recognize calls abroad
* bugfix for program starts
*
* Revision 1.12 1997/05/25 19:40:58 luethje
* isdnlog: close all files and open again after kill -HUP
* isdnrep: support vbox version 2.0
* isdnconf: changes by Roderich Schupp <roderich@syntec.m.EUnet.de>
* conffile: ignore spaces at the end of a line
*
* Revision 1.11 1997/05/09 23:30:47 luethje
* isdnlog: new switch -O
* isdnrep: new format %S
* bugfix in handle_runfiles()
*
* Revision 1.10 1997/05/06 22:13:26 luethje
* bugfixes in HTML-Code of the isdnrep
*
* Revision 1.9 1997/05/04 20:19:47 luethje
* README completed
* isdnrep finished
* interval-bug fixed
*
* Revision 1.8 1997/04/17 20:09:32 luethje
* patch of Ingo Schneider
*
* Revision 1.7 1997/04/08 21:56:48 luethje
* Create the file isdn.conf
* some bug fixes for pid and lock file
* make the prefix of the code in `isdn.conf' variable
*
* Revision 1.6 1997/04/08 00:02:14 luethje
* Bugfix: isdnlog is running again ;-)
* isdnlog creates now a file like /var/lock/LCK..isdnctrl0
* README completed
* Added some values (countrycode, areacode, lock dir and lock file) to
* the global menu
*
*/
#define _ISDNLOG_C_
/* included via isdnlog/isdnlog.h -> tools/tools.h -> ../lib/libisdn.h
#include <linux/limits.h> */
#include <termios.h>
#include "isdnlog.h"
#include "dest.h"
#include "rate_skip.h"
#ifdef POSTGRES
#include "postgres.h"
#endif
#ifdef MYSQLDB
#include "mysqldb.h"
#endif
#ifdef ORACLE
#include "oracle.h"
#endif
#define FD_SET_MAX(desc, set, max) { if (desc > max) max=desc; FD_SET(desc,set); }
#ifdef Q931
#define Q931dmp q931dmp
#else
#define Q931dmp 0
#endif
/*****************************************************************************/
/* Letzte Exit-Nummer: 47 */
/*****************************************************************************/
#define X_FD_ISSET(fd, mask) ((fd) >= 0 && FD_ISSET(fd,mask))
static void loop(void);
static void init_variables(int argc, char* argv[]);
static int set_options(int argc, char* argv[]);
static void hup_handler(int isig);
static void exit_on_signal(int Sign);
int print_in_modules(const char *fmt, ...);
static int read_param_file(char *FileName);
/*****************************************************************************/
static char usage[] = "%s: usage: %s [ -%s ] file\n";
#ifdef Q931
static char options[] = "qav:sp:x:m:l:rt:c:C:w:SVTDPMh:nW:H:f:bL:NFA:2:O:Ki:R:0:ou:B:U:1d:I:Q:";
#else
static char options[] = "av:sp:x:m:l:rt:c:C:w:SVTDPMh:nW:H:f:bL:NFA:2:O:Ki:R:0:ou:B:U:1d:I:Q:";
#endif
static char msg1[] = "%s: Can't open %s (%s)\n";
static char *ptty = NULL;
static section *opt_dat = NULL;
static char **hup_argv; /* args to restart with */
static int sqldump = 0;
static char *param_myarea = NULL;
static char *param_skipprov = NULL;
/*****************************************************************************/
static void exit_on_signal(int Sign)
{
signal(Sign, SIG_DFL);
print_msg(PRT_NORMAL, "Got signal %d\n", Sign);
Exit(7);
} /* exit_on_signal */
/*****************************************************************************/
static void hup_handler(int isig)
{
print_msg(PRT_INFO, "restarting %s\n", myname);
Exit(-9);
if (param_closefds)
Close_Fds(3); /* avoid duplicate fds after restart */
execv(myname, hup_argv);
print_msg(PRT_ERR,"Cannot restart %s: %s!\n", myname, strerror(errno));
} /* hup_handler */
/*****************************************************************************/
static void loop(void)
{
auto fd_set readmask;
auto fd_set exceptmask;
auto int maxdesc = 0;
auto int Cnt;
auto int len;
auto int queuenumber;
auto int NewSocket;
auto int NewClient = 0;
auto struct sockaddr incoming;
auto int Interval;
if (xinfo) {
first_descr++;
if ((NewSocket = listening(port)) >= 0) {
if (add_socket(&sockets, NewSocket))
Exit(11);
}
else
Exit(17);
}
else
if (add_socket(&sockets, -1))
Exit(11);
while (1) {
if (replay) {
if (trace)
dotrace();
if (!morectrl(0))
break;
}
else {
FD_ZERO(&readmask);
FD_ZERO(&exceptmask);
queuenumber = socket_size(sockets);
if (NewClient) {
/* Damit sich der neue Client anmelden kann, ohne
das was anderes dazwischen funkt ... */
if (sockets[NewClient].descriptor >= 0)
FD_SET_MAX(sockets[NewClient].descriptor, &readmask, maxdesc);
NewClient = 0;
}
else {
for (Cnt = 0; Cnt < queuenumber; Cnt++)
if (sockets[Cnt].descriptor >= 0)
FD_SET_MAX(sockets[Cnt].descriptor, &readmask, maxdesc);
for (Cnt = first_descr; Cnt < queuenumber; Cnt++)
if (sockets[Cnt].descriptor >= 0)
FD_SET_MAX(sockets[Cnt].descriptor, &exceptmask, maxdesc);
} /* else */
if (newcps && ((ifo[0].u & ISDN_USAGE_MASK) + (ifo[1].u & ISDN_USAGE_MASK)))
Interval = wakeup; /* AK:06-Jun-96 */
else
Interval = 0;
while ((Cnt = select(maxdesc+1, &readmask, NULL, &exceptmask, Get_Interval(Interval))) < 0 && (errno == EINTR));
if ((Cnt < 0) && (errno != EINTR)) { /* kill -HUP ausgeschlossen */
print_msg(PRT_DEBUG_CS, "Error select: %s\n", strerror(errno));
Exit(12);
} /* if */
processflow();
if (!Cnt) /* Abbruch durch Timeout -> Programm starten */
Start_Interval();
now();
/* processRate(-1); */
processcint();
for (Cnt = first_descr; Cnt < socket_size(sockets); Cnt++) {
if (X_FD_ISSET(sockets[Cnt].descriptor, &exceptmask)) {
if (sockets[Cnt].fp == NULL) {
disconnect_client(Cnt);
break;
}
else {
int event = sockets[Cnt].call_event;
int cur_call = sockets[Cnt].chan;
info_args *infoarg = sockets[Cnt].info_arg;
Ring(NULL, NULL, Cnt, 0);
if (infoarg->flag & RING_LOOP && call[cur_call].cur_event == event)
Start_Process(cur_call, infoarg, event);
break;
} /* else */
}
else if (X_FD_ISSET(sockets[Cnt].descriptor, &readmask)) {
if (sockets[Cnt].fp == NULL) {
eval_message(Cnt);
/* Arbeite immer nur ein Client ab, du weisst nicht, ob der
naechste noch lebt */
break;
}
else
Print_Cmd_Output(Cnt);
} /* else */
} /* for */
if (xinfo && X_FD_ISSET(sockets[IN_PORT].descriptor, &readmask)) {
len = sizeof(incoming);
if ((NewSocket = accept(sockets[IN_PORT].descriptor, &incoming, &len)) == -1)
print_msg(PRT_DEBUG_CS, "Error accept: %s\n", strerror(errno));
else {
if (add_socket(&sockets, NewSocket))
Exit(13);
queuenumber = socket_size(sockets);
sockets[queuenumber - 1].f_hostname = GetHostByAddr(&incoming);
sockets[queuenumber - 1].waitstatus = WF_ACC;
NewClient = queuenumber - 1;
} /* else */
}
else if (X_FD_ISSET(sockets[ISDNINFO].descriptor, &readmask))
moreinfo();
else if (X_FD_ISSET(sockets[ISDNCTRL].descriptor, &readmask))
(void)morectrl(0);
else if (X_FD_ISSET(sockets[ISDNCTRL2].descriptor, &readmask))
(void)morectrl(1);
else if (X_FD_ISSET(sockets[STDIN].descriptor, &readmask))
(void)morekbd();
} /* else */
} /* while */
} /* loop */
#undef X_FD_ISSET
/*****************************************************************************/
int print_in_modules(const char *fmt, ...)
{
auto va_list ap;
auto char String[LONG_STRING_SIZE];
va_start(ap, fmt);
(void)vsnprintf(String, LONG_STRING_SIZE, fmt, ap);
va_end(ap);
return print_msg(PRT_ERR, "%s", String);
} /* print_in_modules */
/*****************************************************************************/
static void init_variables(int argc, char* argv[])
{
flog = NULL; /* /var/adm/isdn.log */
fcons = NULL; /* /dev/ttyX (or stderr) */
fprot = NULL; /* /tmp/isdnctrl0 */
isdnctrl = NULL;
fout = NULL;
first_descr = FIRST_DESCR;
message = PRT_NORMAL | PRT_WARN | PRT_ERR | PRT_INFO;
syslogmessage = PRT_NOTHING;
xinfo = 0;
sound = 0;
trace = 0;
isdaemon = 0;
imon = 0;
port = 0;
wakeup = 1;
fullhour = 0;
tty_dv = 0;
net_dv = 0;
inf_dv = 0;
settime = 0;
replay = 0;
replaydev = 0;
verbose = 0;
synclog = 0;
any = 1;
stdoutput = 0;
allflags = 0;
newcps = 0;
chans = 2;
hupctrl = hup1 = hup2 = 0;
trim = trimi = trimo = 0;
bilingual = 0;
other = 0;
mcalls = MAX_CALLS_IN_QUEUE;
xlog = MAX_PRINTS_IN_QUEUE;
outfile = NULL;
readkeyboard = 0;
sockets = NULL;
known = NULL;
opt_dat = NULL;
newline = 1;
width = 0;
watchdog = 0;
use_new_config = 1;
ignoreRR = ignoreCOLP = ignoreCLIP = 0;
#ifdef Q931
q931dmp = 0;
#endif
#if 0 /* Fixme: remove */
CityWeekend = 0;
#endif
sprintf(mlabel, "%%s%s %%s%%s", "%e.%b %T %I");
amtsholung = NULL;
dual = 0;
dualfix = 0;
hfcdual = 0;
hup3 = 240;
abclcr = 0;
ciInterval = 0;
ehInterval = 0;
myname = argv[0];
myshortname = basename(myname);
} /* init_variables */
/*****************************************************************************/
#ifdef Q931
static void traceoptions()
{
q931dmp++;
// use_new_config = 0;
replay++;
port = 20012;
} /* traceoptions */
#endif
/*****************************************************************************/
int set_options(int argc, char* argv[])
{
register int c;
register char *p;
auto int defaultmsg = PRT_NORMAL | PRT_WARN | PRT_ERR | PRT_INFO;
auto int newmessage = 0;
if (!message)
message = defaultmsg;
#ifdef Q931
if (!strcmp(myshortname, "trace"))
traceoptions();
#endif
while ((c = getopt(argc, argv, options)) != EOF)
switch (c) {
case 'V' : print_version(myshortname);
exit(0);
break;
case 'v' : verbose = strtol(optarg, NIL, 0);
break;
case 's' : synclog++;
break;
case 'p' : port = strtol(optarg, NIL, 0);
break;
case 'm' : newmessage = strtol(optarg, NIL, 0);
if (!newmessage) {
newmessage = defaultmsg;
printf("%s: WARNING: \"-m\" Option now requires numeric Argument\n", myshortname);
} /* if */
break;
case 'l' : syslogmessage = strtol(optarg, NIL, 0);
if (!syslogmessage) {
syslogmessage = defaultmsg;
printf("%s: WARNING: \"-l\" Option requires numeric Argument\n", myshortname);
} /* if */
break;
case 'x' : xinfo = strtol(optarg, NIL, 0);
if (!xinfo)
xinfo = defaultmsg;
break;
case 'r' : replay++;
break;
case 't' : settime = strtol(optarg, NIL, 0); /* 1=once, 2=ever */
break;
case 'C' : ptty = strdup(optarg);
break;
case 'M' : imon++;
break;
case 'S' : sound++;
break;
case 'w' : wakeup = strtol(optarg, NIL, 0);
break;
case 'D' : isdaemon++;
break;
case 'T' : trace++;
break;
case 'a' : any = 0;
break;
case 'P' : stdoutput = PRT_LOG;
break;
case 'h' : hupctrl++;
if ((p = strchr(optarg, ':'))) {
*p = 0;
hup1 = atoi(optarg);
hup2 = atoi(p + 1);
if ((p = strchr(p + 1, ':')))
hup3 = atoi(p + 1);
}
else
printf("%s: WARNING: \"-h\" Option requires 2 .. 3 arguments\n", myshortname);
break;
case 'b' : bilingual++;
break;
case 'c' : mcalls = strtol(optarg, NIL, 0);
break;
case 'L' : xlog = strtol(optarg, NIL, 0);
break;
case 'f' : read_param_file(optarg);
break;
case 'n' : newline = 0;
break;
case 'W' : width = strtol(optarg, NIL, 0);
break;
case 'H' : watchdog = strtol(optarg, NIL, 0);
break;
case 'N' : use_new_config = 0;
break;
#ifdef Q931
case 'q' : traceoptions();
break;
#endif
#if 0 /* Fixme: remove */
case 'F' : CityWeekend++;
break;
#endif
case 'A' : amtsholung = strdup(optarg);
break;
case '1' : hfcdual = 1;
break;
case '2' : dual = strtol(optarg, NIL, 0);
dualfix = dual & ~0xFF;
dual &= 0xFF;
break;
case 'O' : outfile = strdup(optarg);
break;
case 'K' : readkeyboard++;
break;
case 'i' : interns0 = (int)strtol(optarg, NIL, 0);
break;
case 'R' : preselect = (int)strtol(optarg, NIL, 0);
break;
case '0' : trim++;
if ((p = strchr(optarg, ':'))) {
*p = 0;
trimi = atoi(optarg);
trimo = atoi(p + 1);
}
else
trimi = trimo = atoi(optarg);
break;
case 'o' : other++;
break;
case 'u' : ignoreRR = atoi(optarg);
break;
case 'U' :
if ((p = strchr(optarg, ':'))) {
*p = 0;
ignoreCOLP = atoi(optarg);
ignoreCLIP = atoi(p + 1);
}
else
ignoreCOLP = ignoreCLIP = atoi(optarg);
break;
case 'B' : free(vbn);
vbn = strdup(optarg);
break;
case 'd' : abclcr = atoi(optarg);
break;
case 'I' :
if ((p = strchr(optarg, ':'))) {
*p = 0;
ciInterval = atoi(optarg);
ehInterval = atoi(p + 1);
}
else
ciInterval = ehInterval = atoi(optarg);
break;
case 'Q' : sqldump = atoi(optarg);
break;
case '?' : printf(usage, myshortname, myshortname, options);
exit(1);
} /* switch */
if (newmessage)
message = newmessage;
if (readkeyboard && isdaemon) {
printf("%s","Can read from standard input daemonized!\n");
exit(20);
} /* if */
if (trace && isdaemon) {
printf("%s","Can not trace daemonized!\n");
exit(20);
} /* if */
if (stdoutput && isdaemon) {
printf("%s","Can not write to stdout as daemon!\n");
exit(21);
} /* if */
if (isdaemon) {
if (syslogmessage == -1)
syslogmessage = defaultmsg;
fflush(stdout); /* always advisable before a fork */
fflush(stderr);
switch (fork()) {
case -1 : print_msg(PRT_ERR,"%s","Can not fork()!\n");
Exit(18);
break;
case 0 : /* we're a daemon, so "close" stdout, stderr */
/* stdin is "closed" elsewhere */
freopen("/dev/null", "a+", stdout);
freopen("/dev/null", "a+", stderr);
break;
default : _exit(0);
}
/* Wenn message nicht explixit gesetzt wurde, dann gibt es beim daemon auch
kein Output auf der Console/ttyx */
if (!outfile && !newmessage && !ptty)
message = 0;
} /* if */
allflags = syslogmessage | message | xinfo | stdoutput;
return optind;
} /* set_options */
/*****************************************************************************/
static int read_param_file(char *FileName)
{
register char *p;
auto section *SPtr;
auto entry *Ptr;
if (opt_dat != NULL)
{
print_msg(PRT_ERR, "Only one option file allowed (file %s)!\n", FileName);
return -1;
}
if ((SPtr = opt_dat = read_file(NULL, FileName, 0)) == NULL)
return -1;
while (SPtr != NULL)
{
if (!strcmp(SPtr->name,CONF_SEC_OPT))
{
Ptr = SPtr->entries;
while (Ptr != NULL)
{
if (!strcmp(Ptr->name,CONF_ENT_DEV))
isdnctrl = Ptr->value;
else
if (!strcmp(Ptr->name,CONF_ENT_LOG))
verbose = (int)strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_FLUSH))
synclog = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_PORT))
port = strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_STDOUT))
message = strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_SYSLOG))
syslogmessage = strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_XISDN))
{
xinfo = strtol(Ptr->value, NIL, 0);
}
else
if (!strcmp(Ptr->name,CONF_ENT_TIME))
settime = (int)strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_CON))
ptty = Ptr->value;
else
if (!strcmp(Ptr->name,CONF_ENT_START))
sound = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_THRU))
wakeup = strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_DAEMON))
isdaemon = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_MON))
imon = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_PIPE))
stdoutput = toupper(*(Ptr->value)) == 'Y'?PRT_LOG:0;
else
if (!strcmp(Ptr->name,CONF_ENT_HANGUP)) {
hupctrl++;
if ((p = strchr(Ptr->value, ':'))) {
*p = 0;
hup1 = atoi(Ptr->value);
hup2 = atoi(p + 1);
if ((p = strchr(p + 1, ':')))
hup3 = atoi(p + 1);
} /* if */
else
printf("%s: WARNING: \"-h\" Option requires 2 .. 3 arguments\n", myshortname);
}
else
if (!strcmp(Ptr->name,CONF_ENT_PROVIDERCHANGE))
providerchange = strdup(Ptr->value);
else
if (!strcmp(Ptr->name,CONF_ENT_ABCLCR))
abclcr = atoi(Ptr->value);
else
if (!strcmp(Ptr->name, CONF_ENT_CIINTERVAL)) {
if ((p = strchr(Ptr->value, ':'))) {
*p = 0;
ciInterval = atoi(Ptr->value);
ehInterval = atoi(p + 1);
}
else
ciInterval = ehInterval = atoi(Ptr->value);
}
else
if (!strcmp(Ptr->name, CONF_ENT_TRIM)) {
trim++;
if ((p = strchr(Ptr->value, ':'))) {
*p = 0;
trimi = atoi(Ptr->value);
trimo = atoi(p + 1);
}
else
trimi = trimo = atoi(Ptr->value);
}
else
if (!strcmp(Ptr->name,CONF_ENT_BI))
bilingual = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_CALLS))
mcalls = strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_XLOG))
xlog = strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_NL))
newline = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_WIDTH))
width = (int)strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_DUAL)) {
dual = (int)strtol(Ptr->value, NIL, 0);
dualfix = dual & ~0xFF;
dual &= 0xFF;
}
else
if (!strcmp(Ptr->name,CONF_ENT_AMT))
amtsholung = strdup(Ptr->value);
else
#ifdef Q931
if (!strcmp(Ptr->name,CONF_ENT_Q931))
{
if(toupper(*(Ptr->value)) == 'Y')
traceoptions();
}
else
#endif
if (!strcmp(Ptr->name,CONF_ENT_WD))
watchdog = (int)strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_OUTFILE))
outfile = Ptr->value;
else
if (!strcmp(Ptr->name,CONF_ENT_KEYBOARD))
readkeyboard = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_INTERNS0))
interns0 = (int)strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_PRESELECT))
preselect = (int)strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_OTHER))
other = toupper(*(Ptr->value)) == 'Y'?1:0;
else
#if 0 /* Fixme: remove */
if (!strcmp(Ptr->name,CONF_ENT_CW))
CityWeekend++;
else
#endif
if (!strcmp(Ptr->name,CONF_ENT_IGNORERR))
ignoreRR = (int)strtol(Ptr->value, NIL, 0);
else
if (!strcmp(Ptr->name,CONF_ENT_IGNORECOLP)) {
if ((p = strchr(Ptr->value, ':'))) {
*p = 0;
ignoreCOLP = atoi(Ptr->value);
ignoreCLIP = atoi(p + 1);
}
else
ignoreCOLP = ignoreCLIP = (int)strtol(Ptr->value, NIL, 0);
}
else
if (!strcmp(Ptr->name,CONF_ENT_VBN)) {
free(vbn);
vbn = strdup(Ptr->value);
}
else
if (!strcmp(Ptr->name,CONF_ENT_VBNLEN)) {
free(vbnlen);
vbnlen = strdup(Ptr->value);
}
else
if (!strcmp(Ptr->name,CONF_ENT_CLOSEFDS))
param_closefds = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_IGNOREUPD))
ignore_unknown_PD = toupper(*(Ptr->value)) == 'Y'?1:0;
else
if (!strcmp(Ptr->name,CONF_ENT_AREA)) {
/* set area code like in Set_Codes, file ../../lib/isdnconf.c */
char *p;
if (strlen(Ptr->value) > strlen(areaprefix) &&
!strncmp(Ptr->value, areaprefix, strlen(areaprefix)))
p = strdup(Ptr->value + strlen(areaprefix));
else
p = strdup(Ptr->value);
if (p && *p)
param_myarea = p;
}
else
if (!strcmp(Ptr->name,CONF_ENT_SKIPPROV))
param_skipprov = strdup(Ptr->value);
else
print_msg(PRT_ERR,"Error: Invalid entry `%s'!\n",Ptr->name);
Ptr = Ptr->next;
}
}
else
print_msg(PRT_ERR,"Error: Invalid section `%s'!\n",SPtr->name);
SPtr = SPtr->next;
}
return 0;
}
/*****************************************************************************/
static void restoreCharge()
{
register int i, j, n = 0, nx = max(knowns, 1);
auto FILE *f;
auto char fn[BUFSIZ];
typedef struct {
char who[16];
int day;
double charge;
double scharge;
int month;
double online;
double sonline;
double bytes;
double sbytes;
} CHARGE;
auto CHARGE *charge;
if ((charge = (CHARGE *)malloc(sizeof(CHARGE) * nx)) != (CHARGE *)NULL) {
sprintf(fn, "%s/%s", confdir(), CHARGEFILE);
if ((f = fopen(fn, "r")) != (FILE *)NULL) {
while (fscanf(f, "%s %d %lg %lg %d %lg %lg %lg %lg\n",
charge[n].who, &charge[n].day, &charge[n].charge, &charge[n].scharge,
&charge[n].month, &charge[n].online, &charge[n].sonline,
&charge[n].bytes, &charge[n].sbytes) == 9) {
n++;
if (n == nx) {
nx++;
if ((charge = (CHARGE *)realloc((void *)charge, sizeof(CHARGE) * nx)) == (CHARGE *)NULL) {
fclose(f);
return;
} /* if */
} /* if */
} /* while */
if (n) {
for (i = 0; i < knowns; i++)
for (j = 0; j < n; j++)
if (!strcmp(known[i]->who, charge[j].who)) {
known[i]->day = charge[j].day;
known[i]->charge = charge[j].charge;
known[i]->scharge = charge[j].scharge;
known[i]->month = charge[j].month;
known[i]->online = charge[j].online;
known[i]->sonline = charge[j].sonline;
known[i]->bytes = charge[j].bytes;
known[i]->sbytes = charge[j].sbytes;
break;
} /* if */
} /* if */
fclose(f);
} /* if */
free(charge);
} /* if */
} /* restoreCharge */
/*****************************************************************************/
void raw_mode(int state)
{
static struct termios newterminfo, oldterminfo;
if (state) {
tcgetattr(fileno(stdin), &oldterminfo);
newterminfo = oldterminfo;
newterminfo.c_iflag &= ~(INLCR | ICRNL | IUCLC | ISTRIP);
newterminfo.c_lflag &= ~(ICANON | ECHO);
newterminfo.c_cc[VMIN] = 1;
newterminfo.c_cc[VTIME] = 1;
tcsetattr(fileno(stdin), TCSAFLUSH, &newterminfo);
}
else
tcsetattr(fileno(stdin), TCSANOW, &oldterminfo);
} /* raw_mode */
static int checkconfig(void) {
if (callfile && (!callfmt || !*callfmt)) {
print_msg(PRT_ERR, "No CALLFMT given.");
return -1;
}
/* there shold propably be more checks here */
return 0;
}
/*****************************************************************************/
int main(int argc, char *argv[], char *envp[])
{
register char *p;
register int i, res = 0;
auto int lastarg;
auto char rlogfile[PATH_MAX], s[BUFSIZ];
auto char *version;
auto char **devices = NULL;
sigset_t unblock_set;
#ifdef TESTCENTER
extern void test_center(char*);
#endif
if (getuid() != 0) {
fprintf(stderr,"Can only run as root!\n");
exit(35);
} /* if */
set_print_fct_for_lib(print_in_modules);
hup_argv = argv;
init_variables(argc, argv);
lastarg = set_options(argc,argv);
#ifdef TESTCENTER
test_center(argv[lastarg]);
#endif
if (outfile != NULL)
{
if (!message)
{
print_msg(PRT_ERR,"Can not set outfile `%s', when -m is not set!\n",outfile);
Exit(44);
}
else
{
char *openmode;
if (*outfile == '+')
{
outfile++;
openmode = "a";
}
else
{
openmode = "w";
}
if ((fout = fopen(outfile, openmode)) == NULL)
{
print_msg(PRT_ERR,"Can not open file `%s': %s!\n",outfile, strerror(errno));
Exit(45);
}
}
}
if (lastarg < argc)
isdnctrl = argv[lastarg];
if (isdnctrl == NULL) {
print_msg(PRT_ERR,"There is no valid input device!\n");
Exit(31);
}
else {
p = strrchr(isdnctrl, C_SLASH);
if (add_socket(&sockets, -1) || /* reserviert fuer isdnctrl */
add_socket(&sockets, -1) || /* reserviert fuer isdnctrl2 */
add_socket(&sockets, -1) || /* reserviert fuer isdninfo */
add_socket(&sockets, -1) ) /* reserviert fuer stdin */
Exit(19);
if (replay) {
verbose = 0;
synclog = 0;
settime = 0;
xinfo = 0;
*isdnctrl2 = 0;
}
else {
if (strcmp(isdnctrl, "-") && dual && !hfcdual) {
strcpy(isdnctrl2, isdnctrl);
p = strrchr(isdnctrl2, 0) - 1;
if (!isdigit(*p)) /* "/dev/isdnctrl" */
strcat(++p, "0");
if (isdigit(*(p - 1)))
p--;
i = atoi(p);
sprintf(p, "%d", i + 2);
}
else
*isdnctrl2 = 0;
} /* else */
openlog(myshortname, LOG_NDELAY, LOG_DAEMON);
if (xinfo && read_user_access())
Exit(22);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, hup_handler);
signal(SIGINT, exit_on_signal);
signal(SIGTERM, exit_on_signal);
signal(SIGALRM, exit_on_signal);
signal(SIGQUIT, exit_on_signal);
signal(SIGILL, exit_on_signal);
if (!(allflags & PRT_DEBUG_GENERAL))
signal(SIGSEGV, exit_on_signal);
/*
* If hup_handler() already did an execve(), then SIGHUP is still
* blocked, and so you can only send a SIGHUP once. Here we unblock
* SIGHUP so that this feature can be used more than once.
*/
sigemptyset(&unblock_set);
sigaddset(&unblock_set, SIGHUP);
sigprocmask(SIG_UNBLOCK, &unblock_set, NULL);
sockets[ISDNCTRL].descriptor = !strcmp(isdnctrl, "-") ? fileno(stdin) : open(isdnctrl, O_RDONLY | O_NONBLOCK);
if (*isdnctrl2)
sockets[ISDNCTRL2].descriptor = open(isdnctrl2, O_RDONLY | O_NONBLOCK);
if ((sockets[ISDNCTRL].descriptor >= 0) && (!*isdnctrl2 || (sockets[ISDNCTRL2].descriptor >= 0))) {
if (ptty != NULL)
fcons = fopen(ptty, "a");
if ((ptty == NULL) || (fcons != (FILE *)NULL)) {
if (verbose) {
struct stat st;
if ((p = strrchr(isdnctrl, '/')))
p++;
else
p = argv[lastarg];
sprintf(tmpout, "%s/%s", TMPDIR, p);
/*
* If tmpout is a symlink, refuse to write to it (security hole).
* E.g. someone can create a link /tmp/isdnctrl0 -> /etc/passwd.
*/
if (!lstat(tmpout, &st) && S_ISLNK(st.st_mode)) {
print_msg(PRT_ERR, "File \"%s\" is a symlink, not writing to it!\n", tmpout);
verbose = 0;
}
} /* if */
if (!verbose || ((fprot = fopen(tmpout, "a")) != (FILE *)NULL)) {
for (i = 0; i < MAXCHAN; i++)
clearchan(i, 1);
#ifdef Q931AK
if (q931dmp) {
mymsns = 3;
mycountry = "+49";
mycountrynum = 49;
myarea = "6171";
currency = NULL;
dual = 1;
chargemax = 0.0;
connectmax = 0.0;
bytemax = 0.0;
connectmaxmode = 0;
bytemaxmode = 0;
knowns = retnum = 0;
known = (KNOWN **)NULL;
start_procs.infoargs = NULL;
start_procs.flags = 0;
preselect = 33; /* Telekomik */
vbn = "010"; /* Germany */
vbnlen = "2:3";
setDefaults();
}
else
#endif
{
if (!Q931dmp)
print_msg(PRT_NORMAL, "%s Version %s starting\n", myshortname, VERSION);
if (readconfig(myshortname) < 0)
Exit(30);
if (param_myarea) {
print_msg(PRT_INFO, "(new area code: %s, old: %s)\n",
param_myarea, myarea);
myarea = param_myarea;
}
if (checkconfig() < 0)
Exit(30);
restoreCharge();
} /* if */
if (replay) {
sprintf(rlogfile, "%s.rep", logfile);
logfile = rlogfile;
}
else {
append_element(&devices,isdnctrl);
switch (i = handle_runfiles(myshortname,devices,START_PROG)) {
case 0 : break;
case -1 : print_msg(PRT_ERR,"Can not open pid/lock file: %s!\n", strerror(errno));
Exit(36);
default : Exit(37);
} /* switch */
} /* if */
if (!replay) {
sockets[ISDNINFO].descriptor = open("/dev/isdn/isdninfo", O_RDONLY | O_NONBLOCK);
if (sockets[ISDNINFO].descriptor<0)
sockets[ISDNINFO].descriptor = open("/dev/isdninfo", O_RDONLY | O_NONBLOCK);
}
if (replay || (sockets[ISDNINFO].descriptor >= 0)) {
if (readkeyboard) {
raw_mode(1);
sockets[STDIN].descriptor = dup(fileno(stdin));
} /* if */
now();
#ifdef POSTGRES
dbOpen();
#endif
#ifdef MYSQLDB
mysql_dbOpen();
#endif
#ifdef ORACLE
oracle_dbOpen();
#endif
#if defined(POSTGRES)||defined(MYSQLDB)||defined(ORACLE)
print_msg(PRT_NORMAL, "Supported SQL-database(s):%s%s%s\n",
#ifdef POSTGRES
" Postgres95",
#else
"",
#endif
#ifdef MYSQLDB
" MySQL",
#else
"",
#endif
#ifdef ORACLE
" Oracle"
#else
""
#endif
);
#endif
sprintf(s, "%s%s", mycountry, myarea);
mynum = strdup(s);
myicountry = atoi(mycountry + strlen(countryprefix));
if (!Q931dmp) {
initHoliday(holifile, &version);
if (*version)
print_msg(PRT_NORMAL, "%s\n", version);
initDest(destfile, &version);
if (*version)
print_msg(PRT_NORMAL, "%s\n", version);
if (param_skipprov) {
i = add_skipped_provider(param_skipprov, &version);
if (i)
print_msg(PRT_WARN, "%s in parameter file contains an error: %s\n",
CONF_ENT_SKIPPROV, version);
i = dump_skipped_provider(s, sizeof s);
if (i > -1)
print_msg(PRT_DEBUG_GENERAL, "dump_skipped_provider after "
"add_skipped_provider for parameter file: >%s< (%i).\n",
s, i);
else
print_msg(PRT_DEBUG_GENERAL, "dump_skipped_provider after "
"add_skipped_provider for parameter file: FAILED.\n");
free(param_skipprov);
param_skipprov = NULL;
}
initRate(rateconf, ratefile, zonefile, &version);
if (*version)
print_msg(PRT_NORMAL, "%s\n", version);
} /* if */
i = dump_skipped_provider(s, sizeof s);
if (i > -1)
print_msg(PRT_DEBUG_GENERAL, "dump_skipped_provider after initRate:"
" >%s< (%i).\n", s, i);
else
print_msg(PRT_DEBUG_GENERAL, "dump_skipped_provider after initRate:"
"FAILED.\n");
i = clear_skipped_provider();
print_msg(PRT_DEBUG_GENERAL, "clear_skipped_provider: %i freed.\n", i);
if (sqldump) {
auto FILE *fo = fopen(((sqldump == 2) ? "/tmp/isdnconf.csv" : "/tmp/isdn.conf.sql"), "w");
register int i;
register char *p1, *p2;
if (fo != (FILE *)NULL) {
if (sqldump == 1) {
fprintf(fo, "USE isdn;\n");
fprintf(fo, "DROP TABLE IF EXISTS conf;\n");
fprintf(fo, "CREATE TABLE conf (\n");
fprintf(fo, " MSN char(32) NOT NULL,\n");
fprintf(fo, " SI tinyint(1) DEFAULT '1' NOT NULL,\n");
fprintf(fo, " ALIAS char(64) NOT NULL,\n");
fprintf(fo, " KEY MSN (MSN)\n");
fprintf(fo, ");\n");
}
else
fprintf(fo, "\"Vorname\",\"Nachname\",\"Firma\",\"Stra<EFBFBD>e gesch<63>ftlich\",\"Ort gesch<63>ftlich\",\"Postleitzahl gesch<63>ftlich\",\"Fax gesch<63>ftlich\",\"Telefon gesch<63>ftlich\",\"Mobiltelefon\",\"E-Mail-Adresse\",\"E-Mail: Angezeigter Name\",\"Geburtstag\",\"Webseite\"\n");
for (i = 0; i < knowns; i++) {
p1 = known[i]->num;
while ((p2 = strchr(p1, ','))) {
*p2 = 0;
if (sqldump == 1)
fprintf(fo, "INSERT INTO conf VALUES('%s',%d,'%s');\n",
p1, known[i]->si, known[i]->who);
else
fprintf(fo, "\"\",\"%s\",\"\",\"\",\"\",\"\",\"\",\"%s\",\"\",\"\",\"\",\"\",\"\"\n",
known[i]->who, p1);
*p2 = ',';
p1 = p2 + 1;
while (*p1 == ' ')
p1++;
} /* while */
if (sqldump == 1)
fprintf(fo, "INSERT INTO conf VALUES('%s',%d,'%s');\n",
p1, known[i]->si, known[i]->who);
else
fprintf(fo, "\"\",\"%s\",\"\",\"\",\"\",\"\",\"\",\"%s\",\"\",\"\",\"\",\"\",\"\"\n",
known[i]->who, p1);
} /* for */
} /* if */
fclose(fo);
exit(0);
} /* if */
loop();
if (sockets[ISDNINFO].descriptor >= 0)
close(sockets[ISDNINFO].descriptor);
}
else {
print_msg(PRT_ERR, msg1, myshortname, "/dev/isdninfo", strerror(errno));
res = 7;
} /* else */
if (verbose)
fclose(fprot);
}
else {
print_msg(PRT_ERR, msg1, myshortname, tmpout, strerror(errno));
res = 5;
} /* else */
if (ptty != NULL)
fclose(fcons);
}
else {
print_msg(PRT_ERR, msg1, myshortname, ptty, strerror(errno));
res = 3;
} /* else */
if (strcmp(isdnctrl, "-"))
close(sockets[ISDNCTRL].descriptor);
if (*isdnctrl2)
close(sockets[ISDNCTRL2].descriptor);
if (readkeyboard) {
raw_mode(0);
close(sockets[STDIN].descriptor);
} /* if */
}
else {
print_msg(PRT_ERR, msg1, myshortname, isdnctrl, strerror(errno));
res = 2;
} /* else */
if (!Q931dmp)
print_msg(PRT_NORMAL, "%s Version %s exiting\n", myshortname, VERSION);
} /* else */
Exit(res);
return(res);
} /* main */
/* vim:set ts=2: */