isdn4k-utils/isdnlog/isdnlog/processor.c

5125 lines
176 KiB
C
Raw Blame History

/* $Id: processor.c,v 1.89 1999/11/07 13:29:27 akool Exp $
*
* ISDN accounting for isdn4linux. (log-module)
*
* Copyright 1995, 1999 by Andreas Kool (akool@isdn4linux.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.
*
* $Log: processor.c,v $
* Revision 1.89 1999/11/07 13:29:27 akool
* isdnlog-3.64
* - new "Sonderrufnummern" handling
*
* Revision 1.88 1999/11/05 20:22:01 akool
* isdnlog-3.63
* - many new rates
* - cosmetics
*
* Revision 1.87 1999/10/30 14:38:47 akool
* isdnlog-3.61
*
* Revision 1.86 1999/10/30 13:42:36 akool
* isdnlog-3.60
* - many new rates
* - compiler warnings resolved
* - fixed "Sonderrufnummer" Handling
*
* Revision 1.85 1999/10/29 19:46:00 akool
* isdnlog-3.60
* - sucessfully 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.84 1999/10/26 18:17:13 akool
* isdnlog-3.58
* - big cleanup ( > 1.3 Mb removed!)
* - v0.02 of destination support - better, but not perfect
* (does't work with gcc-2.7.2.3 yet - use egcs!)
*
* Revision 1.83 1999/09/13 09:09:43 akool
* isdnlog-3.51
* - changed getProvider() to not return NULL on unknown providers
* many thanks to Matthias Eder <mateder@netway.at>
* - corrected zone-processing when doing a internal -> world call
*
* Revision 1.82 1999/09/11 22:28:24 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.81 1999/08/21 12:59:51 akool
* small fixes
*
* Revision 1.80 1999/08/20 19:28:18 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.79 1999/07/25 15:57:21 akool
* isdnlog-3.43
* added "telnum" module
*
* Revision 1.78 1999/07/24 08:44:19 akool
* isdnlog-3.42
* rate-de.dat 1.02-Germany [18-Jul-1999 10:44:21]
* better Support for Ackermann Euracom
* WEB-Interface for isdnrate
* many small fixes
*
* Revision 1.77 1999/07/15 16:41:32 akool
* small enhancement's and fixes
*
* Revision 1.76 1999/07/11 15:30:55 akool
* Patch from Karsten (thanks a lot!)
*
* Revision 1.75 1999/07/01 20:39:52 akool
* isdnrate optimized
*
* Revision 1.74 1999/06/30 17:17:19 akool
* isdnlog Version 3.39
*
* Revision 1.73 1999/06/29 20:11:10 akool
* now compiles with ndbm
* (many thanks to Nima <nima_ghasseminejad@public.uni-hamburg.de>)
*
* Revision 1.72 1999/06/28 19:16:10 akool
* isdnlog Version 3.38
* - new utility "isdnrate" started
*
* Revision 1.71 1999/06/26 12:25:29 akool
* isdnlog Version 3.37
* fixed some warnings
*
* Revision 1.70 1999/06/22 19:40:46 akool
* zone-1.1 fixes
*
* Revision 1.69 1999/06/21 19:33:53 akool
* isdnlog Version 3.35
* zone data for .nl (many thanks to Paul!)
*
* WARNING: This version of isdnlog dont even compile! *EXPERIMENTAL*!!
*
* Revision 1.68 1999/06/16 23:37:35 akool
* fixed zone-processing
*
* Revision 1.67 1999/06/15 20:04:09 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.66 1999/06/13 14:07:50 akool
* isdnlog Version 3.32
*
* - new option "-U1" (or "ignoreCOLP=1") to ignore CLIP/COLP Frames
* - TEI management decoded
*
* Revision 1.65 1999/06/09 19:58:26 akool
* isdnlog Version 3.31
* - Release 0.91 of zone-Database (aka "Verzonungstabelle")
* - "rate-de.dat" V:1.02-Germany [09-Jun-1999 21:45:26]
*
* Revision 1.64 1999/06/03 18:50:33 akool
* isdnlog Version 3.30
* - rate-de.dat V:1.02-Germany [03-Jun-1999 19:49:22]
* - small fixes
*
* Revision 1.63 1999/05/22 10:18:34 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.62 1999/05/13 11:39:24 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.61 1999/05/10 20:37:27 akool
* isdnlog Version 3.26
*
* - fixed the "0800" -> free of charge problem
* - *many* additions to "ausland.dat"
* - first relase of "rate-de.dat" from the CVS-Server of the I4L-Tarif-Crew
*
* Revision 1.60 1999/05/04 19:32:45 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.59 1999/04/30 19:07:56 akool
* isdnlog Version 3.23
*
* - changed LCR probing duration from 181 seconds to 153 seconds
* - "rate-de.dat" filled with May, 1. rates
*
* Revision 1.58 1999/04/29 19:03:24 akool
* isdnlog Version 3.22
*
* - T-Online corrected
* - more online rates for rate-at.dat (Thanks to Leopold Toetsch <lt@toetsch.at>)
*
* Revision 1.57 1999/04/26 22:12:00 akool
* isdnlog Version 3.21
*
* - CVS headers added to the asn* files
* - repaired the "4.CI" message directly on CONNECT
* - HANGUP message extended (CI's and EH's shown)
* - reactivated the OVERLOAD message
* - rate-at.dat extended
* - fixes from Michael Reinelt
*
* Revision 1.56 1999/04/25 17:34:45 akool
* isdnlog Version 3.20
*
* - added ASN.1 Parser from Kai Germaschewski <kai@thphy.uni-duesseldorf.de>
* isdnlog now fully support all fac- and cf-messages!
*
* - some additions to the "rate-de.dat"
*
* Revision 1.55 1999/04/19 19:24:45 akool
* isdnlog Version 3.18
*
* - countries-at.dat added
* - spelling corrections in "countries-de.dat" and "countries-us.dat"
* - LCR-function of isdnconf now accepts a duration (isdnconf -c .,duration)
* - "rate-at.dat" and "rate-de.dat" extended/fixed
* - holiday.c and rate.c fixed (many thanks to reinelt@eunet.at)
*
* Revision 1.54 1999/04/17 14:11:08 akool
* isdnlog Version 3.17
*
* - LCR functions of "isdnconf" fixed
* - HINT's fixed
* - rate-de.dat: replaced "1-5" with "W" and "6-7" with "E"
*
* Revision 1.53 1999/04/15 19:14:38 akool
* isdnlog Version 3.15
*
* - reenable the least-cost-router functions of "isdnconf"
* try "isdnconf -c <areacode>" or even "isdnconf -c ."
* - README: "rate-xx.dat" documented
* - small fixes in processor.c and rate.c
* - "rate-de.dat" optimized
* - splitted countries.dat into countries-de.dat and countries-us.dat
*
* Revision 1.52 1999/04/14 13:16:27 akool
* isdnlog Version 3.14
*
* - "make install" now install's "rate-xx.dat", "rate.conf" and "ausland.dat"
* - "holiday-xx.dat" Version 1.1
* - many rate fixes (Thanks again to Michael Reinelt <reinelt@eunet.at>)
*
* Revision 1.51 1999/04/10 17:19:51 akool
* fix a typo
*
* Revision 1.50 1999/04/10 16:35:35 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.49 1999/04/03 12:47:03 akool
* - isdnlog Version 3.12
* - "%B" tag in ILABEL/OLABEL corrected
* - isdnlog now register's incoming calls when there are no free B-channels
* (idea from sergio@webmedia.es)
* - better "samples/rate.conf.de" (suppress provider without true call-by-call)
* - "tarif.dat" V:1.17 [03-Apr-99]
* - Added EWE-Tel rates from Reiner Klaproth <rk1@msjohan.dd.sn.schule.de>
* - isdnconf can now be used to generate a Least-cost-router table
* (try "isdnconf -c .")
* - isdnlog now simulate a RELEASE COMPLETE if nothing happpens after a SETUP
* - CHARGEMAX Patches from Oliver Lauer <Oliver.Lauer@coburg.baynet.de>
*
* Revision 1.48 1999/03/25 19:40:01 akool
* - isdnlog Version 3.11
* - make isdnlog compile with egcs 1.1.7 (Bug report from Christophe Zwecker <doc@zwecker.com>)
*
* Revision 1.47 1999/03/24 19:37:55 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.46 1999/03/20 16:54:45 akool
* isdnlog 3.09 : support for all Internet-by-call numbers
*
* Revision 1.45 1999/03/20 14:33:07 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.44 1999/03/16 17:37:18 akool
* - isdnlog Version 3.07
* - Michael Reinelt's patch as of 16Mar99 06:58:58
* - fix a fix from yesterday with sondernummern
* - ignore "" COLP/CLIP messages
* - dont show a LCR-Hint, if same price
*
* Revision 1.43 1999/03/15 21:27:58 akool
* - isdnlog Version 3.06
* - README: explain some terms about LCR, corrected "-c" Option of "isdnconf"
* - isdnconf: added a small LCR-feature - simply try "isdnconf -c 069"
* - isdnlog: dont change CHARGEINT, if rate is't known!
* - sonderrufnummern 1.02 [15-Mar-99] :: added WorldCom
* - tarif.dat 1.09 [15-Mar-99] :: added WorldCom
* - isdnlog now correctly handles the new "Ortstarif-Zugang" of UUnet
*
* Revision 1.42 1999/03/14 18:47:44 akool
* damn CLIP :-( Internal call's are free of charge!!
*
* Revision 1.41 1999/03/14 14:26:38 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.40 1999/03/14 12:16:08 akool
* - isdnlog Version 3.04
* - general cleanup
* - new layout for "rate-xx.dat" and "holiday-xx.dat" files from
* Michael Reinelt <reinelt@eunet.at>
* unused by now - it's a work-in-progress !
* - bugfix for Wolfgang Siefert <siefert@wiwi.uni-frankfurt.de>
* The Agfeo AS 40 (Software release 2.1b) uses AOC_AMOUNT, not AOC_UNITS
* - bugfix for Ralf G. R. Bergs <rabe@RWTH-Aachen.DE> - 0800/xxx numbers
* are free of charge ;-)
* - tarif.dat V 1.08 - new mobil-rates DTAG
*
* Revision 1.39 1999/03/07 18:18:55 akool
* - new 01805 tarif of DTAG
* - new March 1999 tarife
* - added new provider "01051 Telecom"
* - fixed a buffer overrun from Michael Weber <Michael.Weber@Post.RWTH-Aachen.DE>
* - fixed a bug using "sondernnummern.c"
* - fixed chargeint change over the time
* - "make install" now install's "sonderrufnummern.dat", "tarif.dat",
* "vorwahl.dat" and "tarif.conf"! Many thanks to
* Mario Joussen <mario.joussen@post.rwth-aachen.de>
* - Euracom Frames would now be ignored
* - fixed warnings in "sondernnummern.c"
* - "10plus" messages no longer send to syslog
*
* Revision 1.38 1999/02/28 19:32:42 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.37 1999/01/24 19:01:40 akool
* - second version of the new chargeint database
* - isdnrep reanimated
*
* Revision 1.36 1999/01/10 15:23:23 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.35 1998/12/09 20:39:36 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.34 1998/11/24 20:51:45 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.33 1998/11/07 17:13:01 akool
* Final cleanup. This _is_ isdnlog-3.00
*
* Revision 1.32 1998/11/06 23:43:52 akool
* for Paul
*
* Revision 1.31 1998/11/06 14:28:31 calle
* AVM-B1 d-channel trace level 2 (newer firmware) now running with isdnlog.
*
* Revision 1.30 1998/11/05 19:09:49 akool
* - Support for all the new L2 frames from HiSax 3.0d (RR, UA, SABME and
* tei management)
* - CityWeekend reimplemented
* Many thanks to Rainer Gallersdoerfer <gallersd@informatik.rwth-aachen.de>
* for the tip
* - more providers
* - general clean-up
*
* Revision 1.29 1998/11/01 08:49:52 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.28 1998/10/04 12:04:05 akool
* - README
* New entries "CALLFILE" and "CALLFMT" documented
* Small Correction from Markus Werner <mw@empire.wolfsburg.de>
* cosmetics
*
* - isdnrep.c
* Bugfix (Thanks to Arnd Bergmann <arnd@uni.de>)
*
* - processor.c
* Patch from Oliver Lauer <Oliver.Lauer@coburg.baynet.de>
* Makes CHARGEMAX work without AOC-D
*
* Patch from Stefan Gruendel <sgruendel@adulo.de>
* gcc 2.7.2.1 Optimizer-Bug workaround
*
* Revision 1.27 1998/10/03 18:05:55 akool
* - processor.c, takt_at.c : Patch from Michael Reinelt <reinelt@eunet.at>
* try to guess the zone of the calling/called party
*
* - isdnrep.c : cosmetics (i hope, you like it, Stefan!)
*
* Revision 1.26 1998/09/27 11:47:28 akool
* fix segfault of isdnlog after each RELASE
*
* Revision 1.25 1998/09/26 18:29:15 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.24 1998/09/22 20:59:15 luethje
* isdnrep: -fixed wrong provider report
* -fixed wrong html output for provider report
* -fixed strange html output
* kisdnlog: -fixed "1001 message window" bug ;-)
*
* Revision 1.23 1998/08/04 08:17:41 paul
* Translated "CHANNEL: B1 gefordet" messages into English
*
* Revision 1.22 1998/06/21 11:52:52 akool
* First step to let isdnlog generate his own AOCD messages
*
* Revision 1.21 1998/06/16 15:05:31 paul
* isdnlog crashed with 1TR6 and "Unknown Codeset 7 attribute 3 size 5",
* i.e. IE 03 which is not Date/Time
*
* Revision 1.20 1998/06/14 15:33:51 akool
* AVM B1 support (Layer 3)
* Telekom's new currency DEM 0,121 supported
* Disable holiday rates #ifdef ISDN_NL
* memory leak in "isdnrep" repaired
*
* Revision 1.19 1998/06/07 21:08:43 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.18 1998/04/09 19:15:07 akool
* - CityPlus Implementation from Oliver Lauer <Oliver.Lauer@coburg.baynet.de>
* - dont change huptimeout, if disabled (via isdnctrl huptimeout isdnX 0)
* - Support for more Providers (TelePassport, Tele 2, TelDaFax)
*
* Revision 1.17 1998/03/25 20:58:34 luethje
* isdnrep: added html feature (verbose on/off)
* processor.c: Patch of Oliver Lauer
*
* Revision 1.16 1998/03/08 12:37:58 luethje
* last changes in Wuerzburg
*
* Revision 1.15 1998/03/08 12:13:40 luethje
* Patches by Paul Slootman
*
* Revision 1.14 1998/03/08 11:42:55 luethje
* I4L-Meeting Wuerzburg final Edition, golden code - Service Pack number One
*
* Revision 1.13 1998/02/05 08:23:24 calle
* decode also seconds in date_time if available, for the dutch.
*
* Revision 1.12 1997/10/08 05:37:10 calle
* Added AVM B1 support to isdnlog, patch is from i4l@tenere.saar.de.
*
* Revision 1.11 1997/09/07 00:43:12 luethje
* create new error messages for isdnrep
*
* Revision 1.10 1997/08/22 12:31:21 fritz
* isdnlog now handles chargeint/non-chargeint Kernels automatically.
* Manually setting of CONFIG_ISDNLOG_OLD_I4L no more needed.
*
* Revision 1.9 1997/06/22 23:03:25 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.8 1997/05/29 17:07:22 akool
* 1TR6 fix
* suppress some noisy messages (Bearer, Channel, Progress) - can be reenabled with log-level 0x1000
* fix from Bodo Bellut (bodo@garfield.ping.de)
* fix from Ingo Schneider (schneidi@informatik.tu-muenchen.de)
* limited support for Info-Element 0x76 (Redirection number)
*
* Revision 1.7 1997/05/28 21:22:53 luethje
* isdnlog option -b is working again ;-)
* isdnlog has new \$x variables
* README completed
*
* Revision 1.6 1997/04/20 22:52:14 luethje
* isdnrep has new features:
* -variable format string
* -can create html output (option -w1 or ln -s isdnrep isdnrep.cgi)
* idea and design from Dirk Staneker (dirk.staneker@student.uni-tuebingen.de)
* bugfix of processor.c from akool
*
* Revision 1.5 1997/03/31 20:50:59 akool
* fixed the postgres95 part of isdnlog
*
* Revision 1.4 1997/03/30 15:42:10 akool
* Ignore invalid time from VSt
*
* Revision 1.3 1997/03/29 09:24:25 akool
* CLIP presentation enhanced, new ILABEL/OLABEL operators
*
* Revision 1.2 1997/03/20 22:42:33 akool
* Some minor enhancements.
*
* Revision 1.1 1997/03/16 20:58:47 luethje
* Added the source code isdnlog. isdnlog is not working yet.
* A workaround for that problem:
* copy lib/policy.h into the root directory of isdn4k-utils.
*
* Revision 2.6.36 1997/02/10 09:30:43 akool
* MAXCARDS implemented
*
* Revision 2.6.30 1997/02/05 20:14:46 akool
* Dual-Teles Mode implemented
*
* Revision 2.6.24 1997/01/15 19:21:46 akool
* AreaCode 0.99 added
*
* Revision 2.6.20 1997/01/05 20:02:46 akool
* q931dmp added
* Automatische Erkennung "-r" -> "-R"
*
* Revision 2.6.19 1997/01/04 15:21:46 akool
* Korrektur bzgl. ISDN_CH
* Danke an Markus Maeder (mmaeder@cyberlink.ch)
*
* Revision 2.6.17 1997/01/03 16:26:46 akool
* BYTEMAX implemented
*
* Revision 2.6.15 1997/01/02 20:02:46 akool
* Hopefully fixed b2c() to suppress faulty messages in processbytes()
* CONNECTMAX implemented
*
* Revision 2.6.11 1996/12/31 15:11:46 akool
* general cleanup
*
* Revision 2.6.6 1996/11/27 22:12:46 akool
* CHARGEMAX implemented
*
* Revision 2.60 1996/11/03 09:31:46 akool
* mit -DCHARGEINT wird Ende jedes "echten" AOC-D angezeigt
*
* Revision 2.3.28 1996/05/06 22:18:46 akool
* "huptimeout" handling implemented (-hx)
*
* Revision 2.3.24 1996/05/04 23:03:46 akool
* Kleiner Fix am ASN.1 Parser von Bernhard Kruepl
* i/o byte Handing redesigned
*
* Revision 2.3.23 1996/04/28 12:44:46 akool
* PRT_SHOWIMON eingefuehrt
*
* Revision 2.3.21 1996/04/26 11:43:46 akool
* Faelschliche DM 0,12 Meldung an xisdn unterdrueckt
*
* Revision 2.3.19 1996/04/25 21:44:46 akool
* -DSELECT_FIX, new Option "-M"
* Optionen "-i" und "-c" entfernt
*
* Revision 2.3.17 1996/04/23 00:25:46 akool
* isdn4kernel-1.3.93 voll implementiert
*
* Revision 2.3.16 1996/04/22 22:58:46 akool
* Temp. Fix fuer isdn4kernel-1.3.91 implementiert
*
* Revision 2.3.15 1996/04/22 21:25:46 akool
* general cleanup
*
* Revision 2.3.13 1996/04/18 20:36:46 akool
* Fehlerhafte Meldung der Durchsatzrate auf unbenutztem Kanal unterdrueckt
*
* Revision 2.3.11 1996/04/14 21:26:46 akool
*
* Revision 2.3.4 1996/04/05 13:50:46 akool
* NEWCPS-Handling implemented
*
* Revision 2.2.5 1996/03/25 19:47:46 akool
* Fix in Exit() (sl)
* 1TR6-Unterstuetzung fertiggestellt
* Neuer Switch "-e" zum Unterdruecken der "tei" Angabe
*
* Revision 2.2.4 1996/03/24 12:17:46 akool
* 1TR6 Causes implemented
* 1TR6 / E-DSS1 Frames werden unterschieden
* Pipe-Funktionalitaet reaktiviert 19-03-96 Bodo Bellut (lasagne@garfield.ping.de)
* Alle Console-Ausgaben wieder mit \r
* Gebuehrenauswertung fuer 1TR6 implementiert (Wim Bonis (bonis@kiss.de))
*
* Revision 2.23 1996/03/17 12:26:46 akool
*
* Revision 2.20 1996/03/11 21:15:46 akool
* Calling/Called party decoding
*
* Revision 2.19 1996/03/10 19:46:46 akool
* Alarm-Handling fuer /dev/isdnctrl0 funzt!
*
* Revision 2.17 1996/02/25 19:23:46 akool
* Andy's Geburtstags-Release
*
* Revision 2.15 1996/02/21 20:38:46 akool
* sl's Server-Verschmelzung
* Gernot's Parken/Makeln
*
* Revision 2.15 1996/02/17 21:01:10 root
* Nun geht auch Parken und Makeln
*
* Revision 2.14 1996/02/17 16:00:00 root
* Zeitfehler weg
*
* Revision 2.15 1996/02/21 20:30:42 akool
* sl's Serververschmelzung
* Gernot's Makeln
*
* Revision 2.13 1996/02/15 21:03:42 akool
* ein kleiner noch
* Gernot's Erweiterungen implementiert
* MSG_CALL_INFO enthaelt nun State
*
* Revision 2.12 1996/02/13 20:08:43 root
* Nu geht's (oder?)
*
* Revision 1.4 1996/02/13 20:05:28 root
* so nun gehts
*
* Revision 1.3 1996/02/13 18:08:45 root
* Noch ein [ und ein ;
*
* Revision 1.2 1996/02/13 18:02:40 root
* Haben wir's drin - erster Versuch!
*
* Revision 1.1 1996/02/13 14:28:14 root
* Initial revision
*
* Revision 2.10 1996/02/12 20:38:16 akool
* TEI-Handling von Gernot Zander
*
* Revision 2.06 1996/02/10 20:10:16 akool
* Handling evtl. vorlaufender "0" bereinigt
*
* Revision 2.05 1996/02/05 21:42:16 akool
* Signal-Handling eingebaut
* AVON-Handling implementiert
*
* Revision 2.04 1996/01/31 18:30:16 akool
* Bugfix im C/S
* Neue Option "-R"
*
* Revision 2.03 1996/01/29 15:13:16 akool
* Bugfix im C/S
* Revision 2.02 1996/01/27 15:13:16 akool
* Stefan Luethje's Client-/Server Anbindung implementiert
* Bugfix bzgl. HANGUP ohne AOCE-Meldung
*
* Revision 2.01 1996/01/21 15:32:16 akool
* Erweiterungen fuer Michael 'Ghandi' Herold implementiert
* Syslog-Meldungen implementiert
* Reread der isdnlog.conf bei SIGHUP implementiert
* AOCD/AOCE Auswertungen fuer Oesterreich implementiert
*
* Revision 2.00 1996/01/10 20:10:16 akool
* Vollstaendiges Redesign, basierend auf der "call reference"
* WARNING: Requires Patch of 'q931.c'
*
* Revision 1.25 1995/11/18 14:38:16 akool
* AOC von Anrufen auf 0130-xxx werden korrekt ausgewertet
*
* Revision 1.24 1995/11/12 11:08:16 akool
* Auch die "call reference" wird (ansatzweise) ausgewertet
* Neue Option "-x" aktiviert X11-Popup
* Date/Time wird ausgewertet
* AOC-D wird korrekt ausgewertet
* Neue Option "-t" setzt Systemzeit auf die von der VSt gemeldete
* Die "-m" Option kann nun auch mehrfach (additiv) angegeben werden
*
* Revision 1.23 1995/11/06 18:03:16 akool
* "-m16" zeigt die Cause im Klartext an
* Auch Gebuehreneinheiten > 255 werden korrekt ausgewertet
*
* Revision 1.22 1995/10/22 14:43:16 akool
* General cleanup
* "isdn.log" um 'I' == dialin / 'O' == dialout erweitert
* Auch nicht zustande gekommene Verbindungen werden (mit cause)
* protokolliert
*
* Revision 1.21 1995/10/18 21:25:16 akool
* Option "-r" implementiert
* Charging-Infos waehrend der Verbindung (FACILITY) werden ignoriert
* "/etc/isdnlog.pid" wird erzeugt
*
* Revision 1.20 1995/10/15 17:23:16 akool
* Volles D-Kanal Protokoll implementiert (fuer Teles-0.4d Treiber)
*
* Revision 1.13 1995/09/30 09:34:16 akool
* Option "-m", Console-Meldung implementiert
* Flush bei SIGTERM implementiert
*
* Revision 1.12 1995/09/29 17:21:13 akool
* "isdn.log" um Zeiteintrag in UTC erweitert
*
* Revision 1.11 1995/09/28 18:51:17 akool
* First public release
*
* Revision 1.1 1995/09/16 16:54:12 akool
* Initial revision
*
*/
#define _PROCESSOR_C_
#include "isdnlog.h"
#include "sys/times.h"
#include "asn1.h"
#include "zone.h"
#include "telnum.h"
static int HiSax = 0, hexSeen = 0, uid = UNKNOWN, lfd = 0;
static char *asnp, *asnm;
static int chanused[2] = { 0, 0 };
#ifdef Q931
#define Q931dmp q931dmp
#else
#define Q931dmp 0
#endif
static void Q931dump(int mode, int val, char *msg, int version)
{
#ifdef Q931
switch (mode) {
case TYPE_STRING : if (val == -4)
fprintf(stdout, " ?? %s\n", msg);
else if (val == -3)
fprintf(stdout, "%s\n", msg);
else if (val == -2)
fprintf(stdout, " .. %s\n", msg);
else if (val == -1)
fprintf(stdout, " %s\n", msg);
else
fprintf(stdout, " %02x %s\n", val, msg);
break;
case TYPE_MESSAGE : fprintf(stdout, "\n%02x %s\n", val, qmsg(mode, version, val));
break;
case TYPE_ELEMENT : fprintf(stdout, "%02x ---> %s\n", val, qmsg(mode, version, val));
break;
case TYPE_CAUSE : fprintf(stdout, " %02x %s\n", val, qmsg(mode, version, val & 0x7f));
break;
} /* switch */
#endif
} /* Q931dump */
static void diag(int cref, int tei, int sapi, int dialin, int net, int type, int version)
{
char String[LONG_STRING_SIZE];
char TmpString[LONG_STRING_SIZE];
if (dialin != -1) {
sprintf(String," DIAG> %s: %3d/%3d %3d %3d %s %s %s-> ",
st + 4, cref, cref & 0x7f, tei, sapi,
((version == VERSION_1TR6) ? "1TR6" : "E-DSS1"),
dialin ? " IN" : "OUT",
net ? "NET" : "USR");
if ((cref > 128) && (type == SETUP_ACKNOWLEDGE)) {
sprintf(TmpString," *%d* ", cref);
strcat(String, TmpString);
} /* if */
} /* if */
print_msg(PRT_DEBUG_GENERAL, "%s%s\n", String, qmsg(TYPE_MESSAGE, VERSION_EDSS1, type));
} /* diag */
static char *location(int loc)
{
switch (loc) {
case 0x00 : return("User"); break;
case 0x01 : return("Private network serving local user"); break;
case 0x02 : return("Public network serving local user"); break;
case 0x03 : return("Transit network"); break;
case 0x04 : return("Public network serving remote user"); break;
case 0x05 : return("Private network serving remote user"); break;
case 0x07 : return("International network"); break;
case 0x0a : return("Network beyond inter-working point"); break;
default : return(""); break;
} /* switch */
} /* location */
void buildnumber(char *num, int oc3, int oc3a, char *result, int version,
int *provider, int *sondernummer, int *intern, int *local,
int dir, int who)
{
auto char n[BUFSIZ];
auto int partner = ((dir && (who == CALLING)) || (!dir && (who == CALLED)));
// *sondernummer = UNKNOWN;
*intern = 0;
*local = 0;
if (Q931dmp) {
register char *ps;
auto char s[BUFSIZ];
ps = s + sprintf(s, "Type of number: ");
switch (oc3 & 0x70) {
case 0x00 : sprintf(ps, "Unknown"); break;
case 0x10 : sprintf(ps, "International"); break;
case 0x20 : sprintf(ps, "National"); break;
case 0x30 : sprintf(ps, "Network specific"); break;
case 0x40 : sprintf(ps, "Subscriber"); break;
case 0x60 : sprintf(ps, "Abbreviated"); break;
case 0x70 : sprintf(ps, "Reserved for extension"); break;
} /* switch */
Q931dump(TYPE_STRING, oc3, s, version);
ps = s + sprintf(s, "Numbering plan: ");
switch (oc3 & 0x0f) {
case 0x00 : sprintf(ps, "Unknown"); break;
case 0x01 : sprintf(ps, "ISDN/telephony"); break;
case 0x03 : sprintf(ps, "Data"); break;
case 0x04 : sprintf(ps, "Telex"); break;
case 0x08 : sprintf(ps, "National standard"); break;
case 0x09 : sprintf(ps, "Private"); break;
case 0x0f : sprintf(ps, "Reserved for extension"); break;
} /* switch */
Q931dump(TYPE_STRING, -1, s, version);
if (oc3a != -1) {
ps = s + sprintf(s, "Presentation: ");
switch (oc3a & 0x60) {
case 0x00 : sprintf(ps, "allowed"); break;
case 0x20 : sprintf(ps, "restricted"); break;
case 0x40 : sprintf(ps, "Number not available due to internetworking"); break;
case 0x60 : sprintf(ps, "Reserved for extension"); break;
} /* switch */
Q931dump(TYPE_STRING, oc3a, s, version);
ps = s + sprintf(s, "Screening indicator: ");
switch (oc3a & 0x03) {
case 0x00 : sprintf(ps, "User provided, not screened"); break;
case 0x01 : sprintf(ps, "User provided, verified and passed"); break;
case 0x02 : sprintf(ps, "User provided, verified and failed"); break;
case 0x03 : sprintf(ps, "Network provided"); break;
} /* switch */
Q931dump(TYPE_STRING, -1, s, version);
} /* if */
sprintf(s, "\"%s\"", num);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
strcpy(n, num);
strcpy(result, "");
*intern = ((strlen(num) < interns0) || !isdigit(*num));
if (trim && !*intern) {
if (dir && (who == CALLING))
num += min(trimi, strlen(num));
else if (!dir && (who == CALLED))
num += min(trimo, strlen(num));
print_msg(PRT_DEBUG_DECODE, " TRIM> \"%s\" -> \"%s\" (trimi=%d, trimo=%d, %s, %s, %s)\n",
n, num, trimi, trimo, (dir ? "DIALIN" : "DIALOUT"), (who ? "CALLED" : "CALLING"), (partner ? "PARTNER" : "MYSELF"));
} /* if */
if (*num && !dir && (who == CALLED)) {
char *amt = amtsholung;
while (amt && *amt) {
int len = strchr(amt, ':') ? strchr(amt, ':') - amt : strlen(amt);
if (len && !strncmp(num, amt, len)) {
if (Q931dmp) {
auto char s[BUFSIZ], c;
c = num[len];
num[len] = 0;
sprintf(s, "Amtsholung: %s", num);
num[len] = c;
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
num += len;
break;
} /* if */
amt += len + (strchr(amt, ':') ? 1 : 0);
} /* while */
} /* if */
#if 0 /* Fixme: delete */
if (!dir && (who == CALLED) && !memcmp(num, vbn, strlen(vbn))) { /* Provider */
register int l, c;
l = strlen(vbn);
if (num[l] == '0') /* dreistellige Verbindungsnetzbetreiberkennzahl? */
l += 3;
else
l += 2;
c = num[l];
num[l] = 0;
*provider = atoi(num + strlen(vbn));
/* die dreistelligen Verbindungsnetzbetreiberkennzahlen werden
intern erst mal mit einem Offset von 100 verarbeitet
"010001 Netnet" -> "001" + 100 -> 101
Das geht gut, solange nur die ersten 99 der dreistelligen
vergeben werden ...
*/
if (l == 6) /* Fixme: German specific */
*provider += 100;
num[l] = c;
num += l;
if (Q931dmp) {
auto char s[BUFSIZ];
if (*provider < 100)
sprintf(s, "Via provider \"%s%02d\", %s", vbn, *provider, getProvider(*provider));
else
sprintf(s, "Via provider \"%s%03d\", %s", vbn, *provider - 100, getProvider(*provider));
Q931dump(TYPE_STRING, -1, s, version);
} /* if */
} /* if */
#else
if (!dir && (who == CALLED) && !*intern) { /* split Provider */
int l;
/* cool Kool :-) */
num += (l=provider2prefix(num, provider));
if (l && Q931dmp) {
auto char s[BUFSIZ];
auto char prov[TN_MAX_PROVIDER_LEN];
prefix2provider(*provider, prov);
sprintf(s, "Via provider \"%s\", %s", prov, getProvider(*provider));
Q931dump(TYPE_STRING, -1, s, version);
} /* if */
} /* if */
#endif
if (!*intern) {
if (*provider == UNKNOWN)
*provider = preselect;
if (*num && !dir && (who == CALLED) && getSpecial(num) && (*sondernummer == UNKNOWN))
*sondernummer = strlen(num);
} /* if */
if (Q931dmp) {
auto char s[BUFSIZ];
if (*sondernummer != UNKNOWN) {
sprintf(s, "(Sonderrufnummer %s, len=%d)", num, *sondernummer);
Q931dump(TYPE_STRING, -1, s, version);
} /* if */
if (*intern)
Q931dump(TYPE_STRING, -1, "(Interne Nummer)", version);
} /* if */
if ((*sondernummer == UNKNOWN) && !*intern) {
switch (oc3 & 0x70) { /* Calling party number Information element, Octet 3 - Table 4-11/Q.931 */
case 0x00 : if (*num) { /* 000 Unknown */
if (*num != '0') {
strcpy(result, mynum);
*local = 1;
}
else {
if (num[1] != '0') /* Falls es doch Ausland ist -> nichts machen!!! */
strcpy(result, mycountry);
else
strcpy(result, countryprefix);
while (*num == '0')
num++;
} /* else */
} /* if */
break;
case 0x10 : if (version != VERSION_1TR6)
strcpy(result, countryprefix); /* 001 International */
break;
case 0x20 : if (version != VERSION_1TR6) {
strcpy(result, mycountry); /* 010 National */
while (*num == '0')
num++;
} /* if */
break;
case 0x30 : break; /* 011 Network specific number */
case 0x40 : if (*num != '0') { /* 100 Subscriber number */
strcpy(result, mynum);
*local = 1;
}
else {
strcpy(result, mycountry);
while (*num == '0')
num++;
} /* else */
break;
case 0x60 : break; /* 110 Abbreviated number */
case 0x70 : break; /* 111 Reserved for extension */
} /* switch */
} /* if */
if (*num)
strcat(result, num);
else
strcpy(result, "");
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s: num=\"%s\", oc3=%s(%02x), result=\"%s\", sonder=%d, intern=%d, local=%d, partner=%d\n",
st + 4, n, i2a(oc3, 8, 2), oc3 & 0x70, result, *sondernummer, *intern, *local, partner);
} /* buildnumber */
void aoc_debug(int val, char *s)
{
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s: %s\n", st + 4, s);
if (Q931dmp)
Q931dump(TYPE_STRING, val, s, VERSION_EDSS1);
} /* aoc_debug */
/*
currency_mode := AOC_UNITS | AOC_AMOUNT
currency_factor :=
currency := " DM" | "SCHILLING" | "NLG" | "FR."
*/
static int parseRemoteOperationProtocol(char **asnp, Aoc *aoc)
{
auto Element el;
splitASN1(asnp, 0, &el);
printASN1(el, 0);
if (!ParseComponent(el, ASN1_NOT_TAGGED, aoc))
return(0);
return(1);
} /* parseRemoteOperationProtocol */
static int facility(int l, char* p)
{
auto int c;
static Aoc aoc;
asnp = p;
aoc.type = 0;
if (asnp == NULL)
return(AOC_OTHER);
c = strtol(asnp += 3, NIL, 16); /* Ext/Spare/Profile */
memset(&aoc, 0, sizeof(aoc));
switch (c) { /* Remote Operation Protocol */
case 0x91 : aoc_debug(c, "Remote Operation Protocol");
if (parseRemoteOperationProtocol(&asnp, &aoc)) {
switch (aoc.type) {
case 33 : // AOCD Currency
if (aoc.multiplier)
currency_factor = aoc.multiplier;
if (*aoc.currency)
currency = aoc.currency;
if (aoc.type_of_charging_info != 1) // if type_of_charging_info = 1 (total), treat AOCD as AOCE
aoc.amount *= -1;
// fall trough
case 35 : // AOCE Currency
if (aoc.multiplier)
currency_factor = aoc.multiplier;
if (*aoc.currency)
currency = aoc.currency;
return(aoc.amount);
case 34 : // AOCD ChargingUnits
aoc.amount *= -1;
// fall through
case 36 : // AOCE ChargingUnits
return(aoc.amount);
default : asnm = aoc.msg;
return(AOC_OTHER);
} /* switch */
}
else {
asnm = aoc.msg;
return(AOC_OTHER);
} /* else */
break;
case 0x92 : aoc_debug(c, "CMIP Protocol");
break;
case 0x93 : aoc_debug(c, "ACSE Protocol");
break;
default : aoc_debug(c, "UNKNOWN Protocol");
return(AOC_OTHER);
} /* switch */
return(AOC_OTHER);
} /* facility */
static int AOC_1TR6(int l, char *p)
{
auto int EH = 0;
auto int digit = 0;
#ifdef ISDN_NL /* Fixme: do this at runtime */
/*
* NL ISDN: N40*<Einheiten>#, mit Einheiten ASCII kodiert.
* Beispiel 30 Einheiten: N40*30#
* Ich weiss nicht, fuer was 'N40' steht... Skip it.
* Einheit ist NLG 0.15, uebrigens.
*/
p += 9;
l -= 3;
aoc_debug(-1, "AOC_INITIAL_NL");
#elif defined(ISDN_CH) /* Fixme: do this at runtime */
/*
* "FR. 0.10"
*
*
*/
p += 9;
l -= 3; /* Thanks to Markus Maeder (mmaeder@cyberlink.ch) */
aoc_debug(-1, "AOC_INITIAL_CH");
#else
aoc_debug(-1, "AOC_INITIAL_1TR6");
#endif
while (l--) {
digit = strtol(p += 3, NIL, 16) ;
if ((digit >= '0') && (digit <= '9')) {
EH = EH * 10;
EH += (digit - '0'); /* Einheiten sind in ASCII */
} /* if */
} /* while */
currency_mode = AOC_AMOUNT;
return(EH);
} /* AOC_1TR6 */
static int detach()
{
if (replay)
return(1);
if (!close(sockets[ISDNCTRL].descriptor)) {
if (!*isdnctrl2 || !close(sockets[ISDNCTRL2].descriptor)) {
if (!close(sockets[ISDNINFO].descriptor)) {
return(1);
}
else {
print_msg(PRT_DEBUG_CS, "cannot close \"%s\": %s\n", INFO, strerror(errno));
Exit(33);
} /* else */
}
else {
print_msg(PRT_DEBUG_CS, "cannot close \"%s\": %s\n", isdnctrl2, strerror(errno));
Exit(39);
} /* else */
}
else {
print_msg(PRT_DEBUG_CS, "cannot close \"%s\": %s\n", isdnctrl, strerror(errno));
Exit(31);
} /* else */
return(0);
} /* detach */
static int attach()
{
if (replay)
return(1);
if ((sockets[ISDNCTRL].descriptor = open(isdnctrl, O_RDONLY | O_NONBLOCK)) < 0) {
print_msg(PRT_DEBUG_CS, "cannot open \"%s\": %s\n", isdnctrl, strerror(errno));
Exit(30);
} /* if */
if (*isdnctrl2)
if ((sockets[ISDNCTRL2].descriptor = open(isdnctrl2, O_RDONLY | O_NONBLOCK)) < 0) {
print_msg(PRT_DEBUG_CS, "cannot open \"%s\": %s\n", isdnctrl2, strerror(errno));
Exit(38); /* cannot (re)open "/dev/isdnctrl2" */
} /* if */
if ((sockets[ISDNINFO].descriptor = open(INFO, O_RDONLY | O_NONBLOCK)) < 0) {
print_msg(PRT_DEBUG_CS, "cannot open \"%s\": %s\n", INFO, strerror(errno));
Exit(32);
} /* if */
return(0);
} /* attach */
static void chargemaxAction(int chan, double charge_overflow)
{
register int cc = 0, c = call[chan].confentry[OTHER];
auto char cmd[BUFSIZ], msg[BUFSIZ];
sprintf(cmd, "%s/dontstop", confdir());
if (access(cmd, F_OK)) {
sprintf(cmd, "%s/%s", confdir(), STOPCMD);
if (!access(cmd, X_OK)) {
sprintf(cmd, "%s/%s %s %s %s",
confdir(), STOPCMD, double2str((charge_overflow), 6, 3, DEB),
known[c]->who,
double2str(known[c]->scharge, 6, 3, DEB));
sprintf(msg, "CHARGEMAX exhausted: %s", cmd);
info(chan, PRT_ERR, STATE_AOCD, msg);
(void)detach();
cc = replay ? 0 : system(cmd);
(void)attach();
sprintf(msg, "CHARGEMAX exhausted: result = %d", cc);
info(chan, PRT_ERR, STATE_AOCD, msg);
} /* if */
else
{
sprintf(msg, "CHARGEMAX exhausted: stop script `%s' doesn't exist! - NO ACTION! (%s)", cmd, strerror(errno));
info(chan, PRT_ERR, STATE_AOCD, msg);
}
}
else {
sprintf(msg, "CHARGEMAX exhausted - NO ACTION!! - %s exists!", cmd);
info(chan, PRT_ERR, STATE_AOCD, msg);
} /* else */
} /* chargemaxAction */
static void emergencyStop(int chan, int strength)
{
register int cc = 0, c = call[chan].confentry[OTHER];
register char *p;
auto char cmd[BUFSIZ], msg[BUFSIZ];
if (strength == 1) {
if (c == -1)
strength++;
else if (*known[c]->interface < '@')
strength++;
} /* if */
sprintf(cmd, "%s/%s", confdir(), RELOADCMD);
if (strength == 2)
if (access(cmd, X_OK))
strength++;
switch (strength) {
case 1 : cc = replay ? 0 : ioctl(sockets[ISDNCTRL].descriptor, IIOCNETHUP, known[c]->interface);
if (cc < 0)
p = "failed";
else if (cc)
p = "not connected";
else
p = "hung up";
sprintf(msg, "EMERGENCY-STOP#%d: no traffic since %d EH: hangup %s = %s\007\007",
strength, call[chan].aoce - call[chan].traffic, known[c]->interface, p);
break;
case 2 : (void)detach();
cc = replay ? 0 : system(cmd);
(void)attach();
sprintf(msg, "EMERGENCY-STOP#%d: no traffic since %d EH: reload = %d\007\007",
strength, call[chan].aoce - call[chan].traffic, cc);
break;
case 3 : if (replay)
cc = 0;
else {
if ((cc = ioctl(sockets[ISDNCTRL].descriptor, IIOCSETGST, 1)) < 0)
;
else
cc = ioctl(sockets[ISDNCTRL].descriptor, IIOCSETGST, 0);
} /* if */
sprintf(msg, "EMERGENCY-STOP#%d: no traffic since %d EH: system off = %d\007\007",
strength, call[chan].aoce - call[chan].traffic, cc);
break;
case 4 : sprintf(msg, "EMERGENCY-STOP#%d: no traffic since %d EH: REBOOT!!\007\007",
strength, call[chan].aoce - call[chan].traffic);
info(chan, PRT_ERR, STATE_AOCD, msg);
if (!replay) {
Exit(-9); /* cleanup only! */
system(REBOOTCMD);
} /* if */
break;
} /* switch */
info(chan, PRT_ERR, STATE_AOCD, msg);
} /* emergencyStop */
static int expensive(int bchan)
{
return( (ifo[bchan].u & ISDN_USAGE_OUTGOING) &&
(((ifo[bchan].u & ISDN_USAGE_MASK) == ISDN_USAGE_NET) ||
((ifo[bchan].u & ISDN_USAGE_MASK) == ISDN_USAGE_MODEM)));
} /* expensive */
static void decode(int chan, register char *p, int type, int version, int tei)
{
register char *pd, *px, *py;
register int element, l, l1, c, oc3, oc3a, n, sxp = 0, warn;
auto int loc, cause;
auto char s[BUFSIZ], s1[BUFSIZ];
auto char sx[10][BUFSIZ];
auto int sn[10];
auto struct tm tm;
auto time_t t;
auto double tx, err, tack;
while (1) {
if (!*(p - 1) || !*(p + 2))
break;
element = strtol(p += 3, NIL, 16);
if (element < 128) {
l = strtol(p += 3, NIL, 16);
if (Q931dmp) {
auto char s[BUFSIZ];
Q931dump(TYPE_ELEMENT, element, NULL, version);
sprintf(s, "length=%d", l);
Q931dump(TYPE_STRING, l, s, version);
} /* if */
pd = qmsg(TYPE_ELEMENT, version, element);
if (strncmp(pd, "UNKNOWN", 7) == 0) {
register char *p1 = p, *p2;
register int i, c;
auto char s[LONG_STRING_SIZE];
p2 = s;
p2 += sprintf(p2, "UNKNOWN ELEMENT %02x:", element);
for (i = 0; i < l; i++)
p2 += sprintf(p2, " %02x", (int)strtol(p1 += 3, NIL, 16));
p2 += sprintf(p2, " [");
p1 = p;
for (i = 0; i < l; i++) {
c = (int)strtol(p1 += 3, NIL, 16);
p2 += sprintf(p2, "%c", isgraph(c) ? c : ' ');
} /* for */
p2 += sprintf(p2, "], length=%d", l);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s);
}
else
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s: ELEMENT %02x:%s (length=%d)\n", st + 4, element, pd, l);
switch (element) {
case 0x08 : /* Cause */
if (version == VERSION_1TR6) {
switch (l) {
case 0 : call[chan].cause = 0;
break;
case 1 : call[chan].cause = strtol(p += 3, NIL, 16) & 0x7f;
break;
case 2 : call[chan].cause = strtol(p += 3, NIL, 16) & 0x7f;
c = strtol(p += 3, NIL, 16); /* Sometimes it 0xc4 or 0xc5 */
break;
default : p += (l * 3);
print_msg(PRT_ERR, "Wrong Cause (more than two bytes)\n");
break;
} /* switch l */
info(chan, PRT_SHOWCAUSE, STATE_CAUSE, qmsg(TYPE_CAUSE, version, call[chan].cause));
if (sound) {
if (call[chan].cause == 0x3b) /* "User busy" */
ringer(chan, RING_BUSY);
else
ringer(chan, RING_ERROR);
} /* if */
}
else { /* E-DSS1 */
c = strtol(p + 3, NIL, 16);
if (Q931dmp) {
register char *ps;
auto char s[BUFSIZ];
ps = s + sprintf(s, "Coding: ");
switch (c & 0xf0) {
case 0x00 :
case 0x80 : sprintf(ps, "CCITT standardisierte Codierung"); break;
case 0x20 :
case 0xa0 : sprintf(ps, "Reserve"); break;
case 0x40 :
case 0xc0 : sprintf(ps, "reserviert fuer nationale Standards"); break;
case 0x60 :
case 0xe0 : sprintf(ps, "Standard bzgl. Localierung"); break;
default : sprintf(ps, "UNKNOWN #%d", c & 0xf0); break;
} /* switch */
Q931dump(TYPE_STRING, c, s, version);
ps = s + sprintf(s, "Location: %s", location(c & 0x0f));
Q931dump(TYPE_STRING, -1, s, version);
} /* if */
py = location(loc = (c & 0x0f));
c = strtol(p + 6, NIL, 16);
cause = c & 0x7f;
if ((tei != call[chan].tei) && (chan == 6)) { /* AK:26-Nov-98 */
if (Q931dmp) {
auto char s[256];
Q931dump(TYPE_CAUSE, c, NULL, version);
sprintf(s, "IGNORING CAUSE: tei=%d, call.tei=%d, chan=%d", tei, call[chan].tei, chan);
Q931dump(TYPE_STRING, -2, s, version);
}
p += (l * 3);
break;
} /* if */
/* Remember only the _first_ cause
except this was "Normal call clearing", "No user responding"
or "non-selected user clearing"
*/
if ((call[chan].cause == -1) || /* The first cause */
(call[chan].cause == 16) || /* "Normal call clearing" */
(call[chan].cause == 18) || /* "No user responding" */
(call[chan].cause == 26)) { /* "non-selected user clearing" */
call[chan].cause = cause;
call[chan].loc = loc;
} /* if */
if (Q931dmp)
Q931dump(TYPE_CAUSE, c, NULL, version);
if (HiSax || (
(call[chan].cause != 0x10) && /* "Normal call clearing" */
(call[chan].cause != 0x1a) && /* "non-selected user clearing" */
(call[chan].cause != 0x1f) && /* "Normal, unspecified" */
(call[chan].cause != 0x51))) { /* "Invalid call reference value" <- dies nur Aufgrund eines Bug im Teles-Treiber! */
sprintf(s, "%s (%s)", qmsg(TYPE_CAUSE, version, call[chan].cause), py);
if (tei == call[chan].tei)
info(chan, PRT_SHOWCAUSE, STATE_CAUSE, s);
else if (other) {
auto char sx[256];
sprintf(sx, "TEI %d : %s", tei, s);
info(chan, PRT_SHOWCAUSE, STATE_CAUSE, sx);
} /* else */
if (sound) {
if (call[chan].cause == 0x11) /* "User busy" */
ringer(chan, RING_BUSY);
else if ((call[chan].cause != 0x10) &&
(call[chan].cause != 0x1a) &&
(call[chan].cause != 0x1f) &&
(call[chan].cause != 0x51))
ringer(chan, RING_ERROR);
} /* if */
} /* if */
p += (l * 3);
} /* else */
break;
#if !defined(ISDN_NL) && !defined(ISDN_CH) /* -lt- else it will not compile */
case 0x28 : /* DISPLAY ... z.b. Makelweg, AOC-E ... */
{
auto char s[BUFSIZ];
register char *ps = s;
while (l--)
*ps++ = strtol(p += 3, NIL, 16);
*ps = 0;
if (Q931dmp)
Q931dump(TYPE_STRING, -2, s, version);
else
info(chan, PRT_SHOWNUMBERS, STATE_RING, s);
}
break;
#endif
case 0x2d : /* SUSPEND ACKNOWLEDGE (Parkweg) */
p += (l * 3);
break;
case 0x2e : /* RESUME ACKNOWLEDGE (Parkran) */
p += (l * 3);
/* ggf. neuer Channel kommt gleich mit */
break;
case 0x33 : /* makel resume acknowledge (Makelran) */
p += (l * 3);
/* ggf. neuer Channel kommt gleich mit */
break;
case 0x02 : /* Facility AOC-E on 1TR6 */
case 0x1c : /* Facility AOC-D/AOC-E on E-DSS1 */
#if defined(ISDN_NL) || defined(ISDN_CH) /* Fixme: do this at runtime */
case 0x28 : /* DISPLAY: Facility AOC-E on E-DSS1 in NL, CH */
#endif
if ((element == 0x02) && (version == VERSION_1TR6)) {
n = AOC_1TR6(l, p); /* Wieviele Einheiten? */
if (type == AOCD_1TR6) {
n = -n; /* Negativ: laufende Verbindung */
/* ansonsten wars ein AOCE */
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s: 1TR6 AOCD %i\n", st + 4, n);
} /* if */
}
else {
#if defined(ISDN_NL) || defined(ISDN_CH) /* Fixme: do this at runtime */
n = AOC_1TR6(l, p);
#else
n = facility(l, p);
#endif
if (n == AOC_OTHER) {
if (*asnm) {
(void)iprintf(s1, -1, mlabel, "", asnm, "\n");
print_msg(PRT_SHOWNUMBERS, "%s", s1);
} /* if */
}
else {
/* Dirty-Hack: Falls auch AOC-E als AOC-D gemeldet wird:
Ist Fehler in der VSt! Wird gerne bei nachtraeglicher
Beantragung von AOC-D falsch eingestellt :-(
-> Telekom treten!
*/
if ((type != FACILITY) && (n < 0)) {
aoc_debug(-1, "DIRTY-HACK: AOC-D -> AOC-E");
n = -n;
} /* if */
#if 1 /* AK:24-Apr-99 */
if (n < 0) { /* AOC-D */
if (call[chan].aoce == UNKNOWN) /* Firsttime */
call[chan].aoce = 1;
else
call[chan].aoce++;
}
else if (currency_mode == AOC_UNITS)
call[chan].aoce = n;
call[chan].aocpay = abs(n) * currency_factor;
if (n < 0) {
tx = cur_time - call[chan].connect;
if (tx)
sprintf(s, "%d.EH %s %s (%s)",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB),
double2clock(tx));
else
sprintf(s, "%d.EH %s %s",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB));
info(chan, PRT_SHOWAOCD, STATE_AOCD, s);
} /* if */
#endif
if (n < 0)
sprintf(s, "aOC-D=%d", -n);
else if (!n)
sprintf(s, "aOC-E=FREE OF CHARGE");
else
sprintf(s, "aOC-E=%d", n);
aoc_debug(-1, s);
if (!n) {
#if 0
/* Fixme: DTAG is specific to Germany */
if (call[chan].provider == DTAG) /* Only DTAG send's AOCD */
info(chan, PRT_SHOWAOCD, STATE_AOCD, "Free of charge");
#else
;
#endif
}
else if (n < 0) {
tx = cur_time - call[chan].connect;
if ((c = call[chan].confentry[OTHER]) > -1) {
tack = call[chan].Rate.Duration;
err = call[chan].tick - tx;
call[chan].tick += tack;
if (message & PRT_SHOWTICKS)
sprintf(s, "%d.EH %s %s (%s %d) C=%s",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB),
tx ? double2clock(tx) : "", (int)err,
double2clock(call[chan].tick - tx) + 4);
else {
if (tx)
sprintf(s, "%d.EH %s %s (%s)",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB),
double2clock(tx));
else
sprintf(s, "%d.EH %s %s",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB));
} /* else */
}
else if (-n > 1) { /* try to guess Gebuehrenzone */
RATE Guess = call[chan].Rate;
err = 0;
px = "";
if (guessZone(&Guess, -n) != UNKNOWN) {
px = Guess.Zone;
call[chan].tick += Guess.Duration;
err = call[chan].tick - tx;
}
if (message & PRT_SHOWTICKS)
sprintf(s, "%d.EH %s %s (%s %d %s?) C=%s",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB),
tx ? double2clock(tx) : "", (int)err, px,
double2clock(call[chan].tick - tx) + 4);
else {
if (tx)
sprintf(s, "%d.EH %s %s (%s)",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB),
double2clock(tx));
else
sprintf(s, "%d.EH %s %s",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB));
} /* else */
}
else {
sprintf(s, "%d.EH %s %s",
abs(call[chan].aoce),
currency,
double2str(call[chan].aocpay, 6, 3, DEB));
} /* else */
#if 0
info(chan, PRT_SHOWAOCD, STATE_AOCD, s);
#endif
if (sound)
ringer(chan, RING_AOCD);
/* kostenpflichtiger Rausruf (wg. FACILITY) */
/* muss mit Teles-Karte sein, da eigene MSN bekannt */
/* seit 2 Gebuehrentakten kein Traffic mehr! */
if (!replay && watchdog && ((c = call[chan].confentry[OTHER]) > -1)) {
if ((type == FACILITY) && (version == VERSION_EDSS1) && expensive(call[chan].bchan) && (*known[c]->interface > '@')) {
if (call[chan].aoce > call[chan].traffic + watchdog + 2)
emergencyStop(chan, 4);
else if (call[chan].aoce > call[chan].traffic + watchdog + 1)
emergencyStop(chan, 3);
else if (call[chan].aoce > call[chan].traffic + watchdog)
emergencyStop(chan, 2);
else if (call[chan].aoce > call[chan].traffic + watchdog - 1)
emergencyStop(chan, 1);
} /* if */
} /* if */
}
} /* if */
} /* if */
p += (l * 3);
break;
case 0x03 : /* Date/Time 1TR6 */
case 0x29 : /* Date/Time E-DSS1 */
if ((element == 0x03) && (version == VERSION_1TR6)) {
if (l != 17) /* 1TR6 date/time is always 17? */
/* "Unknown Codeset 7 attribute 3 size 5" */
goto UNKNOWN_ELEMENT;
tm.tm_mday = (strtol(p+=3,NIL,16)-'0') * 10;
tm.tm_mday += strtol(p+=3,NIL,16)-'0';
p += 3; /* skip '.' */
tm.tm_mon = (strtol(p+=3,NIL,16)-'0') * 10;
tm.tm_mon += strtol(p+=3,NIL,16)-'0' - 1;
p += 3; /* skip '.' */
tm.tm_year = (strtol(p+=3,NIL,16)-'0') * 10;
tm.tm_year += strtol(p+=3,NIL,16)-'0';
if (tm.tm_year < 70)
tm.tm_year += 100;
p += 3; /* skip '-' */
tm.tm_hour = (strtol(p+=3,NIL,16)-'0') * 10;
tm.tm_hour += strtol(p+=3,NIL,16)-'0';
p += 3; /* skip ':' */
tm.tm_min = (strtol(p+=3,NIL,16)-'0') * 10;
tm.tm_min += strtol(p+=3,NIL,16)-'0';
p += 3; /* skip ':' */
tm.tm_sec = (strtol(p+=3,NIL,16)-'0') * 10;
tm.tm_sec += strtol(p+=3,NIL,16)-'0';
}
else if ((element == 0x29) && (version != VERSION_1TR6)) {
tm.tm_year = strtol(p += 3, NIL, 16);
tm.tm_mon = strtol(p += 3, NIL, 16) - 1;
tm.tm_mday = strtol(p += 3, NIL, 16);
tm.tm_hour = strtol(p += 3, NIL, 16);
tm.tm_min = strtol(p += 3, NIL, 16);
if (l > 5)
tm.tm_sec = strtol(p += 3, NIL, 16);
else
tm.tm_sec = 0;
}
else {
goto UNKNOWN_ELEMENT; /* no choice... */
}
tm.tm_wday = tm.tm_yday = 0;
tm.tm_isdst = -1;
t = mktime(&tm);
if (t != (time_t)-1) {
call[chan].time = t;
if (settime) {
auto time_t tn;
auto struct tms tms;
time(&tn);
if (labs(tn - call[chan].time) > 61) {
(void)stime(&call[chan].time);
/* Nicht gerade sauber, sollte aber all zu
grosse Spruenge verhindern! */
if (replay)
cur_time = tt = tto = call[chan].time;
else {
time(&cur_time);
tt = tto = times(&tms);
} /* else */
set_time_str();
} /* if */
if (settime == 1)
settime--;
} /* if */
} /* if */
sprintf(s, "Time:%s", (t == (time_t)-1) ? "INVALID - ignored" : ctime(&call[chan].time));
if ((px = strchr(s, '\n')))
*px = 0;
if (Q931dmp) {
sprintf(s1, "Y=%02d M=%02d D=%02d H=%02d M=%02d",
tm.tm_year,
tm.tm_mon + 1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min);
Q931dump(TYPE_STRING, -2, s1, version);
Q931dump(TYPE_STRING, -2, s + 5, version);
} /* if */
info(chan, PRT_SHOWTIME, STATE_TIME, s);
break;
case 0x4c : /* COLP */
oc3 = strtol(p += 3, NIL, 16);
if (oc3 < 128) { /* Octet 3a : Screening indicator */
oc3a = strtol(p += 3, NIL, 16);
l--;
}
else
oc3a = -1;
pd = s;
while (--l)
*pd++ = strtol(p += 3, NIL, 16);
*pd = 0;
if (ignoreCOLP && !Q931dmp) /* FIXME */
break;
if (!*s) {
info(chan, PRT_SHOWNUMBERS, STATE_RING, "COLP *INVALID* -- ignored!");
break;
} /* if */
if (dual && !*s)
strcpy(s, call[chan].onum[CALLED]);
else
strcpy(call[chan].onum[CALLED], s);
/* bei "national" numbers evtl. fuehrende "0" davor */
if (((oc3 & 0x70) == 0x20) && (*s != '0')) {
sprintf(s1, "0%s", s);
strcpy(s, s1);
} /* if */
buildnumber(s, oc3, oc3a, call[chan].num[CALLED], version, &call[chan].provider, &call[chan].sondernummer[CALLED], &call[chan].intern[CALLED], &call[chan].local[CALLED], 0, CALLED);
if (!dual)
strcpy(call[chan].vnum[CALLED], vnum(chan, CALLED));
if (Q931dmp && (*call[chan].vnum[CALLED] != '?') && *call[chan].vorwahl[CALLED]
&& oc3 && ((oc3 & 0x70) != 0x40)) {
auto char s[BUFSIZ];
sprintf(s, "%s %s/%s, %s",
call[chan].areacode[CALLED],
call[chan].vorwahl[CALLED],
call[chan].rufnummer[CALLED],
call[chan].area[CALLED]);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
sprintf(s1, "COLP %s", call[chan].vnum[CALLED]);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s1);
break;
case 0x6c : /* Calling party number */
oc3 = strtol(p += 3, NIL, 16);
if (oc3 < 128) { /* Octet 3a : Screening indicator */
oc3a = strtol(p += 3, NIL, 16);
l--;
}
else
oc3a = -1;
/* Screening-Indicator:
-1 : UNKNOWN
0 : User-provided, not screened
1 : User-provided, verified and passed
2 : User-provided, verified and failed
3 : Network provided
*/
pd = s;
while (--l)
*pd++ = strtol(p += 3, NIL, 16);
*pd = 0;
warn = 0;
if (*call[chan].onum[CALLING]) { /* another Calling-party? */
if (strcmp(call[chan].onum[CALLING], s)) { /* different! */
if (ignoreCOLP && !Q931dmp) /* FIXME */
break;
if ((call[chan].screening == 3) && ((oc3a & 3) < 3)) { /* we believe the first one! */
strcpy(call[chan].onum[CLIP], s);
buildnumber(s, oc3, oc3a, call[chan].num[CLIP], version, &call[chan].provider, &call[chan].sondernummer[CLIP], &call[chan].intern[CLIP], &call[chan].local[CLIP], 0, 0);
strcpy(call[chan].vnum[CLIP], vnum(6, CLIP));
if (Q931dmp && (*call[chan].vnum[CLIP] != '?') && *call[chan].vorwahl[CLIP]
&& oc3 && ((oc3 & 0x70) != 0x40)) {
auto char s[BUFSIZ];
sprintf(s, "%s %s/%s, %s",
call[chan].areacode[CLIP],
call[chan].vorwahl[CLIP],
call[chan].rufnummer[CLIP],
call[chan].area[CLIP]);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
sprintf(s1, "CLIP %s", call[chan].vnum[CLIP]);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s1);
break;
}
else {
warn = 1;
strcpy(call[chan].onum[CLIP], call[chan].onum[CALLING]);
strcpy(call[chan].num[CLIP], call[chan].num[CALLING]);
strcpy(call[chan].vnum[CLIP], call[chan].vnum[CALLING]);
call[chan].confentry[CLIP] = call[chan].confentry[CALLING];
strcpy(call[chan].areacode[CLIP], call[chan].areacode[CALLING]);
strcpy(call[chan].vorwahl[CLIP], call[chan].vorwahl[CALLING]);
strcpy(call[chan].rufnummer[CLIP], call[chan].rufnummer[CALLING]);
strcpy(call[chan].alias[CLIP], call[chan].alias[CALLING]);
strcpy(call[chan].area[CLIP], call[chan].area[CALLING]);
/* fall thru, and overwrite ... */
} /* else */
} /* else */
} /* else */
call[chan].screening = (oc3a & 3);
strcpy(call[chan].onum[CALLING], s);
buildnumber(s, oc3, oc3a, call[chan].num[CALLING], version, &call[chan].provider, &call[chan].sondernummer[CALLING], &call[chan].intern[CALLING], &call[chan].local[CALLING], call[chan].dialin, CALLING);
strcpy(call[chan].vnum[CALLING], vnum(chan, CALLING));
if (Q931dmp && (*call[chan].vnum[CALLING] != '?') && *call[chan].vorwahl[CALLING]
&& oc3 && ((oc3 & 0x70) != 0x40)) {
auto char s[BUFSIZ];
sprintf(s, "%s %s/%s, %s",
call[chan].areacode[CALLING],
call[chan].vorwahl[CALLING],
call[chan].rufnummer[CALLING],
call[chan].area[CALLING]);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
if (callfile && call[chan].dialin) {
FILE *cl = fopen(callfile, "a");
/* Fixme: what is short for 'Calling Party Number'? */
sprintf(s1, "CPN %s", call[chan].num[CALLING]);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s1);
if (cl != NULL) {
iprintf(s1, chan, callfmt);
fprintf(cl, "%s\n", s1);
fclose(cl);
} /* if */
} /* if */
if (warn) {
sprintf(s1, "CLIP %s", call[chan].vnum[CLIP]);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s1);
} /* if */
break;
case 0x70 : /* Called party number */
oc3 = strtol(p += 3, NIL, 16);
pd = s;
while (--l)
*pd++ = strtol(p += 3, NIL, 16);
*pd = 0;
if (dual && ((type == INFORMATION) || ((type == SETUP) && OUTGOING))) { /* Digit's beim waehlen mit ISDN-Telefon */
strcat(call[chan].digits, s);
strcpy(call[chan].onum[CALLED], s);
call[chan].oc3 = oc3;
if (Q931dmp)
buildnumber(s, oc3, -1, call[chan].num[CALLED], version, &call[chan].provider, &call[chan].sondernummer[CALLED], &call[chan].intern[CALLED], &call[chan].local[CALLED], call[chan].dialin, CALLED);
buildnumber(call[chan].digits, oc3, -1, call[chan].num[CALLED], version, &call[chan].provider, &call[chan].sondernummer[CALLED], &call[chan].intern[CALLED], &call[chan].local[CALLED], call[chan].dialin, CALLED);
strcpy(call[chan].vnum[CALLED], vnum(chan, CALLED));
if (dual > 1) {
auto char sx[BUFSIZ];
if (*call[chan].vorwahl[CALLED])
sprintf(sx, "DIALING %s [%s] %s %s/%s, %s",
s, call[chan].digits,
call[chan].areacode[CALLED],
call[chan].vorwahl[CALLED],
call[chan].rufnummer[CALLED],
call[chan].area[CALLED]);
else
sprintf(sx, "DIALING %s [%s]", s, call[chan].digits);
info(chan, PRT_SHOWNUMBERS, STATE_RING, sx);
} /* if */
}
else {
strcpy(call[chan].onum[CALLED], s);
buildnumber(s, oc3, -1, call[chan].num[CALLED], version, &call[chan].provider, &call[chan].sondernummer[CALLED], &call[chan].intern[CALLED], &call[chan].local[CALLED], call[chan].dialin, CALLED);
strcpy(call[chan].vnum[CALLED], vnum(chan, CALLED));
if (Q931dmp && (*call[chan].vnum[CALLED] != '?') && *call[chan].vorwahl[CALLED]
&& oc3 && ((oc3 & 0x70) != 0x40)) {
auto char s[BUFSIZ];
sprintf(s, "%s %s/%s, %s",
call[chan].areacode[CALLED],
call[chan].vorwahl[CALLED],
call[chan].rufnummer[CALLED],
call[chan].area[CALLED]);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
/* This message comes before bearer capability */
/* So dont show it here, show it at Bearer capability */
if (version != VERSION_1TR6) {
if (call[chan].knock)
info(chan, PRT_SHOWNUMBERS, STATE_RING, "********************");
sprintf(s, "RING (%s)", call[chan].service);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s);
if (call[chan].knock) {
info(chan, PRT_SHOWNUMBERS, STATE_RING, "NO FREE B-CHANNEL !!");
info(chan, PRT_SHOWNUMBERS, STATE_RING, "********************");
#ifdef Q931
if (!q931dmp) {
#endif
call[chan].connect = call[chan].disconnect = cur_time;
call[chan].cause = -2;
logger(chan);
#ifdef Q931
} /* if */
#endif
} /* if */
if (sound)
ringer(chan, RING_RING);
} /* if */
} /* else */
break;
case 0x74 : /* Redirecting number */
case 0x76 : /* Redirection number */
oc3 = strtol(p += 3, NIL, 16);
pd = s;
while (--l)
*pd++ = strtol(p += 3, NIL, 16);
*pd = 0;
strcpy(call[chan].onum[REDIR], s);
buildnumber(s, oc3, -1, call[chan].num[REDIR], version, &call[chan].provider, &call[chan].sondernummer[REDIR], &call[chan].intern[REDIR], &call[chan].local[REDIR], 0, 0);
strcpy(call[chan].vnum[REDIR], vnum(chan, REDIR));
if (Q931dmp && (*call[chan].vnum[REDIR] != '?') && *call[chan].vorwahl[REDIR]
&& oc3 && ((oc3 & 0x70) != 0x40)) {
auto char s[BUFSIZ];
sprintf(s, "%s %s/%s, %s",
call[chan].areacode[REDIR],
call[chan].vorwahl[REDIR],
call[chan].rufnummer[REDIR],
call[chan].area[REDIR]);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
break;
case 0x01 : /* Bearer capability 1TR6 */
if (l > 0)
call[chan].bearer = strtol(p + 3, NIL, 16);
else
call[chan].bearer = 1; /* Analog */
px = s;
if (!Q931dmp)
px += sprintf(px, "RING (");
px += sprintf(px, "%s", qmsg(TYPE_SERVICE, version, call[chan].bearer));
if (Q931dmp) {
Q931dump(TYPE_STRING, call[chan].bearer, s, version);
if (l > 1) {
c = strtol(p + 6, NIL, 16);
sprintf(s1, "octet 3a=%d", c);
Q931dump(TYPE_STRING, c, s1, version);
} /* if */
} /* if */
px += sprintf(px, ")");
info(chan, PRT_SHOWNUMBERS, STATE_RING, s);
if (sound)
ringer(chan, RING_RING);
p += (l * 3);
break;
case 0x04 : /* Bearer capability E-DSS1 */
clearchan(chan, 0);
pd = p + (l * 3);
l1 = l;
sxp = 0;
if (--l1 < 0) {
p = pd;
goto escape;
} /* if */
c = strtol(p += 3, NIL, 16); /* Octet 3 */
px = sx[sxp];
*px = 0;
sn[sxp] = c;
if (!Q931dmp)
px += sprintf(px, "BEARER: ");
/* Mapping from E-DSS1 Bearer capability to 1TR6 Service Indicator: */
switch (c & 0x1f) {
case 0x00 : px += sprintf(px, "Speech"); /* "CCITT Sprache" */
call[chan].si1 = 1;
call[chan].si11 = 1;
strcpy(call[chan].service, "Speech");
break;
case 0x08 : px += sprintf(px, "Unrestricted digital information"); /* "uneingeschr<68>nkte digitale Information" */
call[chan].si1 = 7;
call[chan].si11 = 0;
strcpy(call[chan].service, "Data");
break;
case 0x09 : px += sprintf(px, "Restricted digital information"); /* "eingeschr<68>nkte digitale Information" */
call[chan].si1 = 2;
call[chan].si11 = 0;
strcpy(call[chan].service, "Fax G3");
break;
case 0x10 : px += sprintf(px, "3.1 kHz audio"); /* "3,1 kHz audio" */
call[chan].si1 = 1;
call[chan].si11 = 0;
strcpy(call[chan].service, "3.1 kHz audio");
break;
case 0x11 : px += sprintf(px, "Unrestricted digital information with tones/announcements"); /* "uneingeschr<68>nkte digitale Ton-Inform." */
call[chan].si1 = 3;
call[chan].si11 = 0;
break;
case 0x18 : px += sprintf(px, "Video"); /* "Video" */
call[chan].si1 = 4;
call[chan].si11 = 0;
strcpy(call[chan].service, "Fax G4");
break;
default : px += sprintf(px, "Service %d", c & 0x1f);
sprintf(call[chan].service, "Service %d", c & 0x1f);
break;
} /* switch */
switch (c & 0x60) {
case 0x00 : px += sprintf(px, ", CCITT standardized coding"); break;
case 0x20 : px += sprintf(px, ", ISO/IEC"); break;
case 0x40 : px += sprintf(px, ", National standard"); break;
case 0x60 : px += sprintf(px, ", Standard defined for the network"); break;
} /* switch */
if (--l1 < 0) {
p = pd;
goto escape;
} /* if */
c = strtol(p += 3, NIL, 16); /* Octet 4 */
px = sx[++sxp];
*px = 0;
sn[sxp] = c;
switch (c & 0x1f) {
case 0x10 : px += sprintf(px, "64 kbit/s"); break;
case 0x11 : px += sprintf(px, "2 * 64 kbit/s"); break;
case 0x13 : px += sprintf(px, "384 kbit/s"); break;
case 0x15 : px += sprintf(px, "1536 kbit/s"); break;
case 0x17 : px += sprintf(px, "1920 kbit/s"); break;
case 0x18 : oc3 = strtol(p += 3, NIL, 16); /* Octet 4.1 */
px += sprintf(px, ", %d kbit/s", 64 * oc3 & 0x7f);
break;
} /* switch */
switch (c & 0x60) {
case 0x00 : px += sprintf(px, ", Circuit mode"); break;
case 0x40 : px += sprintf(px, ", Packet mode"); break;
} /* switch */
if (--l1 < 0) {
p = pd;
goto escape;
} /* if */
c = strtol(p += 3, NIL, 16);
if ((c & 0x60) == 0x20) { /* User information layer 1 */
int ch = ' ';
do {
switch (ch) {
case ' ' : px = sx[++sxp]; /* Octet 5 */
*px = 0;
sn[sxp] = c;
switch (c & 0x1f) {
case 0x01 : px += sprintf(px, "CCITT standardized rate adaption V.110/X.30"); break;
case 0x02 : px += sprintf(px, "G.711 u-law"); break;
case 0x03 : px += sprintf(px, "G.711 A-law"); break;
case 0x04 : px += sprintf(px, "G.721 32 kbit/s ADPCM (I.460)"); break;
case 0x05 : px += sprintf(px, "H.221/H.242"); break;
case 0x07 : px += sprintf(px, "Non-CCITT standardized rate adaption"); break;
case 0x08 : px += sprintf(px, "CCITT standardized rate adaption V.120"); break;
case 0x09 : px += sprintf(px, "CCITT standardized rate adaption X.31, HDLC flag stuffing"); break;
} /* switch */
break;
case 'a' : px = sx[++sxp]; /* Octet 5a */
*px = 0;
sn[sxp] = c;
switch (c & 0x1f) {
case 0x01 : px += sprintf(px, "0.6 kbit/s"); break;
case 0x02 : px += sprintf(px, "1.2 kbit/s"); break;
case 0x03 : px += sprintf(px, "2.4 kbit/s"); break;
case 0x04 : px += sprintf(px, "3.6 kbit/s"); break;
case 0x05 : px += sprintf(px, "4.8 kbit/s"); break;
case 0x06 : px += sprintf(px, "7.2 kbit/s"); break;
case 0x07 : px += sprintf(px, "8 kbit/s"); break;
case 0x08 : px += sprintf(px, "9.6 kbit/s"); break;
case 0x09 : px += sprintf(px, "14.4 kbit/s"); break;
case 0x0a : px += sprintf(px, "16 kbit/s"); break;
case 0x0b : px += sprintf(px, "19.2 kbit/s"); break;
case 0x0c : px += sprintf(px, "32 kbit/s"); break;
case 0x0e : px += sprintf(px, "48 kbit/s"); break;
case 0x0f : px += sprintf(px, "56 kbit/s"); break;
case 0x15 : px += sprintf(px, "0.1345 kbit/s"); break;
case 0x16 : px += sprintf(px, "0.100 kbit/s"); break;
case 0x17 : px += sprintf(px, "0.075/1.2 kbit/s"); break;
case 0x18 : px += sprintf(px, "1.2/0.075 kbit/s"); break;
case 0x19 : px += sprintf(px, "0.050 kbit/s"); break;
case 0x1a : px += sprintf(px, "0.075 kbit/s"); break;
case 0x1b : px += sprintf(px, "0.110 kbit/s"); break;
case 0x1c : px += sprintf(px, "0.150 kbit/s"); break;
case 0x1d : px += sprintf(px, "0.200 kbit/s"); break;
case 0x1e : px += sprintf(px, "0.300 kbit/s"); break;
case 0x1f : px += sprintf(px, "12 kbit/s"); break;
} /* switch */
switch (c & 0x40) {
case 0x00 : px += sprintf(px, ", Synchronous"); break;
case 0x40 : px += sprintf(px, ", Asynchronous"); break;
} /* switch */
switch (c & 0x20) {
case 0x00 : px += sprintf(px, ", In-band negotiation not possible"); break;
case 0x20 : px += sprintf(px, ", In-band negotiation possible"); break;
} /* switch */
break;
case 'b' : px = sx[++sxp]; /* Octet 5b */
*px = 0;
sn[sxp] = c;
switch (c & 0x60) {
case 0x20 : px += sprintf(px, "8 kbit/s"); break;
case 0x40 : px += sprintf(px, "16 kbit/s"); break;
case 0x60 : px += sprintf(px, "32 kbit/s"); break;
} /* switch */
break;
} /* switch */
ch = (ch == ' ') ? 'a' : ch + 1;
if (--l1 < 0) {
p = pd;
goto escape;
} /* if */
c = strtol(p += 3, NIL, 16);
} while (!(c & 0x80));
} /* if */
if ((c & 0x60) == 0x40) { /* User information layer 2 */
px = sx[++sxp];
*px = 0;
sn[sxp] = c;
switch (c & 0x1f) {
case 0x02 : px += sprintf(px, "Q.931/I.441"); break;
case 0x06 : px += sprintf(px, "X.25, packet layer"); break;
} /* switch */
if (--l1 < 0) {
p = pd;
goto escape;
} /* if */
c = strtol(p += 3, NIL, 16);
} /* if */
if ((c & 0x60) == 0x60) { /* User information layer 3 */
px = sx[++sxp];
*px = 0;
sn[sxp] = c;
switch (c & 0x1f) {
case 0x02 : px += sprintf(px, "Q.931/I.451"); break;
case 0x06 : px += sprintf(px, "X.25, packet layer"); break;
} /* switch */
} /* if */
escape: for (c = 0; c <= sxp; c++)
if (Q931dmp)
Q931dump(TYPE_STRING, sn[c], sx[c], version);
else
if (*sx[c])
info(chan, PRT_SHOWBEARER, STATE_RING, sx[c]);
p = pd;
break;
case 0x18 : /* Channel identification */
c = strtol(p + 3, NIL, 16);
sxp = 0;
px = sx[sxp];
*px = 0;
sn[sxp] = c;
if (!Q931dmp)
px += sprintf(px, "CHANNEL: ");
switch (c) {
case 0x80 : px += sprintf(px, "BRI, none requested");
call[chan].knock = 1; break;
case 0x81 : px += sprintf(px, "BRI, B1 requested"); break;
case 0x82 : px += sprintf(px, "BRI, B2 requested"); break;
case 0x83 : px += sprintf(px, "BRI, any channel"); break;
case 0x89 : px += sprintf(px, "BRI, B1 needed"); break;
case 0x8a : px += sprintf(px, "BRI, B2 needed"); break;
case 0x84 : px += sprintf(px, "BRI, D requested"); break;
case 0x8c : px += sprintf(px, "BRI, D needed"); break;
case 0xa0 : px += sprintf(px, "PRI, no channel"); break;
case 0xa1 : px += sprintf(px, "PRI, channel to be indicated later");
break;
case 0xa3 : px += sprintf(px, "PRI, indicated channel requested");
break;
case 0xa9 : px += sprintf(px, "PRI, indicated channel needed");
break;
case 0xac : px += sprintf(px, "PRI, D needed"); break;
case 0xe0 : px += sprintf(px, "no channel"); break;
case 0xe1 : px += sprintf(px, "channel to be indicated later");
break;
case 0xe3 : px += sprintf(px, "any channel"); break;
case 0xe9 : px += sprintf(px, "Nur der nachst. angegeb. Kanal ist akzeptabel"); break;
} /* switch */
if (Q931dmp)
Q931dump(TYPE_STRING, sn[0], sx[0], version);
else
info(chan, PRT_SHOWBEARER, STATE_RING, sx[0]);
if (c == 0x8a)
call[chan].channel = 2;
/* Jetzt eine 1 fuer Kanal 1 und 2 fuer die 2.
0 heisst unbekannt. chan muss dann spaeter
auf channel - 1 gesetzt werden.
Beim Parken bleibt der Kanal belegt (bei mir jedenfalls)
und neue Verbindungen kriegen vom Amt den anderen */
else if (c == 0x89)
call[chan].channel = 1;
else
call[chan].channel = 0;
p += (l * 3);
break;
case 0x1e : /* Progress indicator */
sxp = 0;
px = sx[sxp];
*px = 0;
c = strtol(p + 3, NIL, 16);
sn[sxp] = c;
if (Q931dmp)
px += sprintf(px, "%s", location(c & 0x0f));
else
px += sprintf(px, "PROGRESS: %s", location(c & 0x0f));
if (l > 1) {
px = sx[++sxp];
*px = 0;
if (!Q931dmp)
px += sprintf(px, "PROGRESS: ");
c = strtol(p + 6, NIL, 16);
sn[sxp] = c;
switch (c) {
case 0x81 : px += sprintf(px, "Der Ruf verlaeuft nicht vom Anfang bis zum Ende im ISDN"); break;
case 0x82 : px += sprintf(px, "Zieladresse ist kein ISDN-Anschluss"); break;
case 0x83 : px += sprintf(px, "(Ab)Sendeadresse ist kein ISDN-Anschluss"); break;
case 0x84 : px += sprintf(px, "Ruf ist zum ISDN zurueckgekehrt"); break;
case 0x88 : px += sprintf(px, "Inband Information available"); break;
} /* switch */
} /* if */
for (c = 0; c <= sxp; c++)
if (Q931dmp)
Q931dump(TYPE_STRING, sn[c], sx[c], version);
else if (*sx[c])
info(chan, PRT_SHOWBEARER, STATE_RING, sx[c]);
p += (l * 3);
break;
case 0x27 : /* Notification indicator */
sxp = 0;
px = sx[sxp];
*px = 0;
c = strtol(p + 3, NIL, 16);
sn[sxp] = c;
if (!Q931dmp)
px += sprintf(px, "NOTIFICATION: ");
switch (c) {
case 0x80 : px += sprintf(px, "Nutzer legt auf"); break;
case 0x81 : px += sprintf(px, "Nutzer nimmt wieder auf"); break;
case 0x82 : px += sprintf(px, "Wechsel des Uebermittlungsdienstes"); break;
case 0x83 : px += sprintf(px, "Discriminator for extension to ASN.1 encoded component"); break;
case 0x84 : px += sprintf(px, "Call completion delay"); break;
case 0xc2 : px += sprintf(px, "Conference established"); break;
case 0xc3 : px += sprintf(px, "Conference disconnected"); break;
case 0xc4 : px += sprintf(px, "Other party added"); break;
case 0xc5 : px += sprintf(px, "Isolated"); break;
case 0xc6 : px += sprintf(px, "Reattached"); break;
case 0xc7 : px += sprintf(px, "Other party isolated"); break;
case 0xc8 : px += sprintf(px, "Other party reattached"); break;
case 0xc9 : px += sprintf(px, "Other party split"); break;
case 0xca : px += sprintf(px, "Other party disconnected"); break;
case 0xcb : px += sprintf(px, "Conference floating"); break;
case 0xcf : px += sprintf(px, "Conference floating, served user preemted"); break;
case 0xcc : px += sprintf(px, "Conference disconnected, preemtion"); break;
case 0xf9 : px += sprintf(px, "Remote hold"); break;
case 0xfa : px += sprintf(px, "Remote retrieval"); break;
case 0xe0 : px += sprintf(px, "Call is a waiting call"); break;
case 0xfb : px += sprintf(px, "Call is diverting"); break;
case 0xe8 : px += sprintf(px, "Diversion activated"); break;
case 0xee : px += sprintf(px, "Reverse charging"); break;
} /* switch */
if (Q931dmp)
Q931dump(TYPE_STRING, sn[0], sx[0], version);
else
info(chan, PRT_SHOWNUMBERS, STATE_RING, sx[0]);
p += (l * 3);
break;
case 0x7d : /* High layer compatibility */
if (l > 1) {
sxp = 0;
px = sx[sxp];
*px = 0;
c = strtol(p + 3, NIL, 16);
sn[sxp] = c;
if (!Q931dmp)
px += sprintf(px, "HLC: ");
switch (c) {
case 0x91 : px += sprintf(px, "CCITT"); break;
case 0xb1 : px += sprintf(px, "Reserv."); break;
case 0xd1 : px += sprintf(px, "national"); break;
case 0xf1 : px += sprintf(px, "Eigendef"); break;
} /* switch */
if (Q931dmp) {
px = sx[++sxp];
*px = 0;
} /* if */
c = strtol(p + 6, NIL, 16);
sn[sxp] = c;
if (strlen(sx[sxp]))
px += sprintf(px, ", ");
switch (c) {
case 0x81 : px += sprintf(px, "Telefonie"); break;
case 0x84 : px += sprintf(px, "Fax Gr.2/3 (F.182)"); break;
case 0xa1 : px += sprintf(px, "Fax Gr.4 (F.184)"); break;
case 0xa4 : px += sprintf(px, "Teletex service,basic and mixed-mode"); break;
case 0xa8 : px += sprintf(px, "Teletex service,basic and processab.-mode of Op."); break;
case 0xb1 : px += sprintf(px, "Teletex service,basic mode of operation"); break;
case 0xb2 : px += sprintf(px, "Syntax based Videotex"); break;
case 0xb3 : px += sprintf(px, "International Videotex interworking via gateway"); break;
case 0xb5 : px += sprintf(px, "Telex service"); break;
case 0xb8 : px += sprintf(px, "Message Handling Systems (MHS)(X.400)"); break;
case 0xc1 : px += sprintf(px, "OSI application (X.200)"); break;
case 0xde :
case 0x5e : px += sprintf(px, "Reserviert fuer Wartung"); break;
case 0xdf :
case 0x5f : px += sprintf(px, "Reserviert fuer Management"); break;
case 0xe0 : px += sprintf(px, "Audio visual"); break;
default : px += sprintf(px, "unknown: %d", c); break;
} /* switch */
if ((c == 0x5e) || (c == 0x5f)) {
if (Q931dmp) {
px = sx[++sxp];
*px = 0;
} /* if */
c = strtol(p + 9, NIL, 16);
sn[sxp] = c;
if (strlen(sx[sxp]))
px += sprintf(px, ", ");
switch (c) {
case 0x81 : px += sprintf(px, "Telefonie G.711"); break;
case 0x84 : px += sprintf(px, "Fax Gr.4 (T.62)"); break;
case 0xa1 : px += sprintf(px, "Document Appl. Profile for Fax Gr4 (T.503)"); break;
case 0xa4 : px += sprintf(px, "Doc.Appl.Prof.for formatted Mixed-Mode(T501)"); break;
case 0xa8 : px += sprintf(px, "Doc.Appl.Prof.for Processable-form (T.502)"); break;
case 0xb1 : px += sprintf(px, "Teletex (T.62)"); break;
case 0xb2 : px += sprintf(px, "Doc.App.Prof. for Videotex interworking between Gateways (T.504)"); break;
case 0xb5 : px += sprintf(px, "Telex"); break;
case 0xb8 : px += sprintf(px, "Message Handling Systems (MHS)(X.400)"); break;
case 0xc1 : px += sprintf(px, "OSI application (X.200)"); break;
} /* case */
} /* if */
for (c = 0; c <= sxp; c++)
if (Q931dmp)
Q931dump(TYPE_STRING, sn[c], sx[c], version);
else if (*sx[c])
info(chan, PRT_SHOWNUMBERS, STATE_RING, sx[c]);
} /* if */
p += (l * 3);
break;
default : {
register char *p1, *p2;
register int i;
UNKNOWN_ELEMENT: p1 = p; p2 = s;
for (i = 0; i < l; i++)
p2 += sprintf(p2, "%02x ", (int)strtol(p1 += 3, NIL, 16));
p2 += sprintf(p2, "\"");
p1 = p;
for (i = 0; i < l; i++) {
c = (int)strtol(p1 += 3, NIL, 16);
p2 += sprintf(p2, "%c", isgraph(c) ? c : ' ');
} /* for */
p2 += sprintf(p2, "\"");
if (allflags & PRT_DEBUG_DECODE)
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s: ELEMENT=0x%02x :%s\n", st + 4, element, s);
if (Q931dmp)
Q931dump(TYPE_STRING, -4, s, version);
} /* if */
p += (l * 3);
break;
} /* switch */
}
else if (Q931dmp) {
if (version == VERSION_1TR6) {
switch ((element >> 4) & 7) {
case 1 : sprintf(s, "%02x ---> Shift %d (cs=%d, cs_fest=%d)", element, element & 0xf, element & 7, element & 8);
break;
case 3 : sprintf(s, "%02x ---> Congestion level %d", element, element & 0xf);
break;
case 2 : if (element == 0xa0)
sprintf(s, "%02x ---> More data", element);
else if (element == 0xa1)
sprintf(s, "%02x ---> Sending complete", element);
break;
default : sprintf(s, "%02x ---> Reserved %d", element, element);
break;
} /* switch */
Q931dump(TYPE_STRING, -3, s, version);
}
else if (version == VERSION_EDSS1) {
switch ((element >> 4) & 7) {
case 1 : sprintf(s, "%02x ---> Shift %d", element, element & 0xf);
break;
case 3 : sprintf(s, "%02x ---> Congestion level %d", element, element & 0xf);
break;
case 5 : sprintf(s, "%02x ---> Repeat indicator %d", element, element & 0xf);
break;
case 2 : if (element == 0x90)
sprintf(s, "%02x ---> Umschaltung in eine andere Codegruppe %d\n", element, element);
if (element == 0xa0)
sprintf(s, "%02x ---> More data", element);
else if (element == 0xa1)
sprintf(s, "%02x ---> Sending complete", element);
break;
default : sprintf(s, "%02x ---> Reserved %d\n", element, element);
break;
} /* switch */
Q931dump(TYPE_STRING, -3, s, version);
} /* else */
} /* else */
} /* while */
} /* decode */
/* --------------------------------------------------------------------------
call reference:
1 .. 63 DIALIN's - ist dabei 8. Bit gesetzt, meine Antwort an VSt
(cref=1 : VSt->User // cref=129 : User->VSt)
64 .. 127 DIALOUT's - ist dabei 8. Bit gesetzt, Antwort der VSt an mich
(cref=64 : User->VSt // cref=192 : VSt->User)
kommt ein SETUP ACKNOWLEDGE mit cref > 128, beginnt ein DIALOUT (!)
_nicht_ mit der Teles-Karte
kommt ein CALL PROCEEDING mit cref > 191, beginnt ein DIALOUT
mit der 2. Teles-Karte
folgt danach sofort ein SETUP, ist das ein Selbstanruf!
DIALOUT's erhalten vom Teles-Treiber staendig eine um jeweils 1
erhoehte call references
War die letzte cref also < 127, und die naechste = 64, bedeutet dies
einen Reload des Teles-Treibers!
-------------------------------------------------------------------------- */
void dotrace(void)
{
register int i;
auto char s[BUFSIZ];
print_msg(PRT_NORMAL, ">>>>>>> TRACE (CR=next, q=quit, d=dump, g=go):");
fgets(s, BUFSIZ, stdin);
if (*s == 'q')
exit(0);
else if (*s == 'g')
trace = 0;
else if (*s == 'd') {
print_msg(PRT_NORMAL, "chan=%d\n", chan);
for (i = 0; i < MAXCHAN; i++) {
if (call[i].state) {
print_msg(PRT_NORMAL, "call[%d]:", i);
print_msg(PRT_NORMAL, "state=%d, cref=%d, dialin=%d, cause=%d\n",
call[i].state, call[i].cref, call[i].dialin, call[i].cause);
print_msg(PRT_NORMAL, "\taoce=%d, channel=%d, dialog=%d, bearer=%d\n",
call[i].aoce, call[i].channel, call[i].dialog, call[i].bearer);
print_msg(PRT_NORMAL, "\tnum[0]=\"%s\", num[1]=\"%s\"\n",
call[i].num[0], call[i].num[1]);
print_msg(PRT_NORMAL, "\tvnum[0]=\"%s\", vnum[1]=\"%s\"\n",
call[i].vnum[0], call[i].vnum[1]);
print_msg(PRT_NORMAL, "\tconfentry[0]=%d, confentry[1]=%d\n",
call[i].confentry[0], call[i].confentry[1]);
print_msg(PRT_NORMAL, "\ttime=%d, connect=%d, disconnect=%d, duration=%d\n",
(int)call[i].time, (int)call[i].connect, (int)call[i].disconnect, (int)call[i].duration);
} /* if */
} /* for */
dotrace();
} /* if */
} /* dotrace */
static int b2c(register int b)
{
register int i;
for (i = 0; i < chans; i++)
if ((call[i].bchan == b) && call[i].dialog)
return(i);
return(-1);
} /* b2c */
/* NET_DV since 'chargeint' field exists */
#define NETDV_CHARGEINT 0x02
static void huptime(int chan, int setup)
{
register int c = call[chan].confentry[OTHER];
auto isdn_net_ioctl_cfg cfg;
auto int oldchargeint = 0, newchargeint = 0;
auto int oldhuptimeout, newhuptimeout;
auto char sx[BUFSIZ], why[BUFSIZ];
#if LCRtest
auto char n[1024], n1[1024];
auto union p {
isdn_net_ioctl_phone phone;
char n[1024];
} ph;
#endif
if (replay)
net_dv = 4;
if (hupctrl && (c != UNKNOWN) && (*known[c]->interface > '@') /* && expensive(call[chan].bchan) */) {
memset(&cfg, 0, sizeof(cfg)); /* clear in case of older kernel */
strcpy(cfg.name, known[c]->interface);
if (replay || (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETGCF, &cfg) >= 0)) {
#if NET_DV >= NETDV_CHARGEINT
if (net_dv >= NETDV_CHARGEINT)
call[chan].chargeint = oldchargeint = cfg.chargeint;
#endif
call[chan].huptimeout = oldhuptimeout = cfg.onhtime;
#if LCRtest
if (setup) {
strcpy(ph.phone.name, known[c]->interface);
ph.phone.outgoing = 1;
if (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETGNM, &ph.phone) >= 0) {
strcpy(n, ph.n);
sprintf(sx, "@LCR: SETUP to %s detected", n);
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
if (memcmp(n, vbn, strlen(vbn)) {
sprintf(sx, "@LCR: HANGUP %s", known[c]->interface);
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
if (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETHUP, known[c]->interface) >= 0) { /* HANGUP */
ph.phone.outgoing = 1;
strcpy(ph.phone.name, known[c]->interface);
strcpy(ph.phone.phone, n);
sprintf(sx, "@LCR: DELPHONE %s", n);
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
if (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETDNM, &ph.phone) >= 0) { /* DELPHONE */
sprintf(n1, "%s19%s", vbn, n);
ph.phone.outgoing = 1;
strcpy(ph.phone.name, known[c]->interface);
strcpy(ph.phone.phone, n1);
sprintf(sx, "@LCR: ADDPHONE %s", n1);
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
if (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETANM, &ph.phone) >= 0) { /* ADDPHONE */
sprintf(sx, "@LCR: DIAL");
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
if (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETDIL, known[c]->interface) >= 0) { /* DIAL */
sprintf(sx, "@LCR: DONE!");
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
} /* if */
} /* if */
} /* if */
} /* if */
} /* if */
} /* if */
} /* if */
#endif
if (!oldhuptimeout && !replay) {
sprintf(sx, "HUPTIMEOUT %s is *disabled* - unchanged", known[c]->interface);
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
return;
} /* if */
if (call[chan].tarifknown)
newchargeint = (int)(call[chan].Rate.Duration + 0.5);
else
newchargeint = UNKNOWN;
*why = 0;
#if NET_DV >= NETDV_CHARGEINT
if (net_dv >= NETDV_CHARGEINT) {
if (hup1 && hup2)
newhuptimeout = (newchargeint < 20) ? hup1 : hup2;
else
newhuptimeout = oldhuptimeout;
/* der erste Versuch, dem einmaligen Verbindungsentgelt
(DM 0,06/Anwahl) zu entkommen ... */
if (call[chan].Rate.Basic) /* wenn es eine Grundgebuehr gibt (z.b. T-Online eco) */
newhuptimeout = hup3;
}
else
#endif
/* for old kernels/kernel headers use old behaviour: hangup is charge
* time minus -h param */
if (hup1) {
newhuptimeout = newchargeint - hup1;
oldchargeint = newchargeint;
}
else
newhuptimeout = oldhuptimeout;
if (((oldchargeint != newchargeint) || (oldhuptimeout != newhuptimeout)) && (newchargeint != UNKNOWN)) {
#if NET_DV >= NETDV_CHARGEINT
if (net_dv >= NETDV_CHARGEINT)
call[chan].chargeint = cfg.chargeint = newchargeint;
#endif
call[chan].huptimeout = cfg.onhtime = newhuptimeout;
if (replay || (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETSCF, &cfg) >= 0)) {
sprintf(sx, "CHARGEINT %s %d (was %d)%s%s",
known[c]->interface, newchargeint, oldchargeint, (*why ? " - " : ""), why);
info(chan, PRT_INFO, STATE_HUPTIMEOUT, sx);
sprintf(sx, "HUPTIMEOUT %s %d (was %d)",
known[c]->interface, newhuptimeout, oldhuptimeout);
info(chan, PRT_INFO, STATE_HUPTIMEOUT, sx);
} /* if */
}
else {
sprintf(sx, "CHARGEINT %s still %d%s%s", known[c]->interface,
oldchargeint, (*why ? " - " : ""), why);
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
sprintf(sx, "HUPTIMEOUT %s still %d", known[c]->interface, oldhuptimeout);
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
} /* else */
} /* if */
} /* if */
} /* huptime */
static void oops(int where)
{
auto char s[BUFSIZ];
auto isdn_ioctl_struct ioctl_s;
auto int cmd;
static int loop = 0;
if (!replay) {
strcpy(ioctl_s.drvid, ifo[0].id);
ioctl_s.arg = 4;
cmd = 1;
if ((++loop == 2) || (ioctl(sockets[ISDNCTRL].descriptor, IIOCDRVCTL + cmd, &ioctl_s) < 0)) {
info(0, PRT_ERR, STATE_AOCD, "FATAL: Please enable D-Channel logging with:");
sprintf(s, "FATAL: \"hisaxctrl %s 1 4\"", ifo[0].id);
info(0, PRT_ERR, STATE_AOCD, s);
sprintf(s, "FATAL: and restart isdnlog! (#%d)\007", where);
info(0, PRT_ERR, STATE_AOCD, s);
Exit(34);
} /* if */
} /* if */
sprintf(s, "WARNING \"hisaxctrl %s 1 4\" called! (#%d)", ifo[0].id, where);
info(0, PRT_ERR, STATE_AOCD, s);
} /* if */
static void processbytes()
{
register int bchan, chan, change = 0;
auto char sx[BUFSIZ], sy[BUFSIZ], sz[BUFSIZ];
auto time_t DiffTime = (time_t)0;
auto int hup = 0, eh = 0, hx;
#if SHOWTICKS
auto double tack;
#endif
#if RATE_PER_SAMPLE
auto double DiffTime2;
#endif
for (bchan = 0; bchan < chans; bchan++)
if (((ifo[bchan].u & ISDN_USAGE_MASK) == ISDN_USAGE_NET) ||
((ifo[bchan].u & ISDN_USAGE_MASK) == ISDN_USAGE_MODEM)) {
#if FUTURE
if (!hexSeen)
oops(1);
#endif
if ((chan = b2c(bchan)) != -1) {
*sy = 0;
if (io[bchan].i > call[chan].ibytes) {
call[chan].libytes = call[chan].ibytes;
call[chan].ibytes = io[bchan].i;
change++;
} /* if */
if (io[bchan].o > call[chan].obytes) {
call[chan].lobytes = call[chan].obytes;
call[chan].obytes = io[bchan].o;
change++;
} /* if */
if (change) {
call[chan].traffic = call[chan].aoce;
if (!hexSeen)
oops(3);
} /* if */
#if 0 /* Fixme: why the hell should we call huptime() here? */
if (fullhour) /* zu jeder vollen Stunde HANGUP-Timer neu setzen (aendern sich um: 9:00, 12:00, 18:00, 21:00, 2:00, 5:00 Uhr) */
huptime(chan, bchan, 0);
#endif
DiffTime = cur_time - call[chan].connect;
if (call[chan].chargeint && DiffTime) {
hup = (int)(call[chan].chargeint - (DiffTime % call[chan].chargeint) - 2);
if (hup < 0)
hup = 0;
eh = (DiffTime / (time_t)call[chan].chargeint) + 1;
if (ifo[bchan].u & ISDN_USAGE_OUTGOING) {
sprintf(sy, " H#%d=%3ds", eh, hup);
hx = max(call[chan].chargeint, call[chan].huptimeout);
if (hx > call[chan].chargeint) {
hup = (int)(hx - (DiffTime % hx) - 2);
if (hup < 0)
hup = 0;
eh = (DiffTime / (time_t)hx) + 1;
sprintf(sz, " (#%d=%3ds)", eh, hup);
strcat(sy, sz);
} /* if */
} /* if */
} /* if */
if (DiffTime) {
call[chan].ibps = (double)(call[chan].ibytes / (double)(DiffTime));
call[chan].obps = (double)(call[chan].obytes / (double)(DiffTime));
}
else
call[chan].ibps = call[chan].obps = 0.0;
if (change && (call[chan].ibytes + call[chan].obytes)) {
sprintf(sx, "I=%s %s/s O=%s %s/s%s",
double2byte((double)call[chan].ibytes),
double2byte((double)call[chan].ibps),
double2byte((double)call[chan].obytes),
double2byte((double)call[chan].obps),
sy);
#if SHOWTICKS
if ((message & PRT_SHOWTICKS) && (tack = call[chan].tick - (double)(cur_time - call[chan].connect)) > 0.0)
sprintf(sy, " C=%s", double2clock(tack) + 4);
else
*sy = 0;
sprintf(sx, "I=%s %s/s O=%s %s/s%s",
double2byte((double)call[chan].ibytes),
double2byte((double)call[chan].ibps),
double2byte((double)call[chan].obytes),
double2byte((double)call[chan].obps),
sy);
#endif
info(chan, PRT_SHOWBYTE, STATE_BYTE, sx);
#if RATE_PER_SAMPLE
if ((DiffTime2 = ((double)(tt - tto) / (double)CLK_TCK))) {
auto long ibytes = call[chan].ibytes - call[chan].libytes;
auto long obytes = call[chan].obytes - call[chan].lobytes;
auto double ibps = (double)ibytes / (double)DiffTime2;
auto double obps = (double)obytes / (double)DiffTime2;
sprintf(sx, "I=%s %s/s O=%s %s/s (%4.4gs)",
double2byte(ibytes),
double2byte(ibps),
double2byte(obytes),
double2byte(obps),
(double)DiffTime2);
info(chan, PRT_SHOWBYTE, STATE_BYTE, sx);
} /* if */
#endif
}
else if (DiffTime) {
sprintf(sx, "I=%s %s/s O=%s %s/s%s",
double2byte((double)call[chan].ibytes),
double2byte((double)call[chan].ibps),
double2byte((double)call[chan].obytes),
double2byte((double)call[chan].obps),
sy);
info(chan, PRT_SHOWBYTE, STATE_BYTE, sx);
} /* else */
} /* if */
} /* if */
} /* processbytes */
static void processinfo(char *s)
{
register char *p;
register int j, k, chan, version;
auto char sx[BUFSIZ];
if (verbose & VERBOSE_INFO)
print_msg(PRT_LOG, "%s\n", s);
if (!memcmp(s, "idmap:", 6)) {
j = sscanf(s + 7, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
ifo[ 0].id, ifo[ 1].id, ifo[ 2].id, ifo[ 3].id,
ifo[ 4].id, ifo[ 5].id, ifo[ 6].id, ifo[ 7].id,
ifo[ 8].id, ifo[ 9].id, ifo[10].id, ifo[11].id,
ifo[12].id, ifo[13].id, ifo[14].id, ifo[15].id, ifo[16].id);
if (!newcps && (j == 17)) {
newcps = 1;
for (chans = 0; chans < 17; chans++)
if (!strcmp(ifo[chans].id, "-"))
break;
if (!Q931dmp) {
print_msg(PRT_NORMAL, "(ISDN subsystem with ISDN_MAX_CHANNELS > 16 detected - %d active channels, %d MSN/SI entries)\n", chans, mymsns);
if (dual) {
if (hfcdual)
print_msg(PRT_NORMAL, "(watching \"%s\" as HFC/echo mode)\n", isdnctrl);
else
print_msg(PRT_NORMAL, "(watching \"%s\" and \"%s\")\n", isdnctrl, isdnctrl2);
} /* if */
} /* if */
/*
* Ab "ISDN subsystem Rev: 1.21/1.20/1.14/1.10/1.6" gibt's den ioctl(IIOCGETDVR)
*
* Letzte Version davor war "ISDN subsystem Rev: 1.18/1.18/1.13/1.9/1.6"
*/
if (!replay)
if ((version = ioctl(sockets[ISDNINFO].descriptor, IIOCGETDVR)) != -EINVAL) {
#ifdef NET_DV
int my_net_dv = NET_DV;
#else
int my_net_dv = 0;
#endif
tty_dv = version & 0xff;
version = version >> 8;
net_dv = version & 0xff;
version = version >> 8;
inf_dv = version & 0xff;
print_msg(PRT_NORMAL, "(Data versions: iprofd=0x%02x net_cfg=0x%02x /dev/isdninfo=0x%02x)\n", tty_dv, net_dv, inf_dv);
if (/* Abort if kernel version is greater, since struct has probably
* become larger and would overwrite our stack */
net_dv > my_net_dv ||
/* version 0x03 is special, because it changed a field in the
* middle of the struct and thus is compatible only to itself */
((my_net_dv == 0x03 || net_dv == 0x03) && my_net_dv != net_dv)) {
print_msg(PRT_ERR, "isdn_net_ioctl_cfg version mismatch "
"(kernel 0x%02x, isdnlog 0x%02x)\n",
net_dv, my_net_dv);
Exit(99);
}
} /* if */
if (chans > 2) /* coming soon ;-) */
chans = 2;
} /* if */
}
else if (!memcmp(s, "chmap:", 6))
sscanf(s + 7, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
&ifo[ 0].ch, &ifo[ 1].ch, &ifo[ 2].ch, &ifo[ 3].ch,
&ifo[ 4].ch, &ifo[ 5].ch, &ifo[ 6].ch, &ifo[ 7].ch,
&ifo[ 8].ch, &ifo[ 9].ch, &ifo[10].ch, &ifo[11].ch,
&ifo[12].ch, &ifo[13].ch, &ifo[14].ch, &ifo[15].ch);
else if (!memcmp(s, "drmap:", 6))
sscanf(s + 7, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
&ifo[ 0].dr, &ifo[ 1].dr, &ifo[ 2].dr, &ifo[ 3].dr,
&ifo[ 4].dr, &ifo[ 5].dr, &ifo[ 6].dr, &ifo[ 7].dr,
&ifo[ 8].dr, &ifo[ 9].dr, &ifo[10].dr, &ifo[11].dr,
&ifo[12].dr, &ifo[13].dr, &ifo[14].dr, &ifo[15].dr);
else if (!memcmp(s, "usage:", 6))
sscanf(s + 7, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
&ifo[ 0].u, &ifo[ 1].u, &ifo[ 2].u, &ifo[ 3].u,
&ifo[ 4].u, &ifo[ 5].u, &ifo[ 6].u, &ifo[ 7].u,
&ifo[ 8].u, &ifo[ 9].u, &ifo[10].u, &ifo[11].u,
&ifo[12].u, &ifo[13].u, &ifo[14].u, &ifo[15].u);
else if (!memcmp(s, "flags:", 6))
sscanf(s + 7, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
&ifo[ 0].f, &ifo[ 1].f, &ifo[ 2].f, &ifo[ 3].f,
&ifo[ 4].f, &ifo[ 5].f, &ifo[ 6].f, &ifo[ 7].f,
&ifo[ 8].f, &ifo[ 9].f, &ifo[10].f, &ifo[11].f,
&ifo[12].f, &ifo[13].f, &ifo[14].f, &ifo[15].f);
else if (!memcmp(s, "phone:", 6)) {
sscanf(s + 7, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
ifo[ 0].n, ifo[ 1].n, ifo[ 2].n, ifo[ 3].n,
ifo[ 4].n, ifo[ 5].n, ifo[ 6].n, ifo[ 7].n,
ifo[ 8].n, ifo[ 9].n, ifo[10].n, ifo[11].n,
ifo[12].n, ifo[13].n, ifo[14].n, ifo[15].n);
for (j = 0; j < chans; j++)
if (ifo[j].u & ISDN_USAGE_MASK) {
#if FUTURE
if (!hexSeen)
oops(2);
#endif
for (chan = 0; chan < MAXCHAN; chan++)
if (memcmp(ifo[j].n, "???", 3) && !strcmp(ifo[j].n, call[chan].onum[OTHER])) {
call[chan].bchan = j;
strcpy(call[chan].id, ifo[j].id);
if (!(ifo[j].u & ISDN_USAGE_MASK)) /* no connection */
strcpy(call[chan].usage, (ifo[j].u & ISDN_USAGE_EXCLUSIVE) ? "Exclusive" : "Offline");
else {
switch (ifo[j].u & ISDN_USAGE_MASK) {
case ISDN_USAGE_RAW : sprintf(call[chan].usage, "%s %s", (ifo[j].u & ISDN_USAGE_OUTGOING) ? "Outgoing" : "Incoming", "Raw");
break;
case ISDN_USAGE_MODEM : sprintf(call[chan].usage, "%s %s", (ifo[j].u & ISDN_USAGE_OUTGOING) ? "Outgoing" : "Incoming", "Modem");
break;
case ISDN_USAGE_NET : sprintf(call[chan].usage, "%s %s", (ifo[j].u & ISDN_USAGE_OUTGOING) ? "Outgoing" : "Incoming", "Net");
break;
case ISDN_USAGE_VOICE : sprintf(call[chan].usage, "%s %s", (ifo[j].u & ISDN_USAGE_OUTGOING) ? "Outgoing" : "Incoming", "Voice");
break;
case ISDN_USAGE_FAX : sprintf(call[chan].usage, "%s %s", (ifo[j].u & ISDN_USAGE_OUTGOING) ? "Outgoing" : "Incoming", "Fax");
break;
} /* switch */
} /* else */
#if 0 /* Fixme: why the hell should we call huptime() here? */
huptime(chan, j, 1); /* bei Verbindungsbeginn HANGUP-Timer neu setzen */
#endif
} /* if */
} /* if */
if (imon) {
print_msg(PRT_SHOWIMON, "\n+ %s -----------------------------------------\n", st + 4);
for (j = 0; j < chans; j++) {
p = sx;
p += sprintf(p, "| %s#%d : ", ifo[j].id, j & 1);
if (!(ifo[j].u & ISDN_USAGE_MASK)) /* no connection */
p += sprintf(p, (ifo[j].u & ISDN_USAGE_EXCLUSIVE) ? "exclusive" : "free");
else {
p += sprintf(p, "%s\t", (ifo[j].u & ISDN_USAGE_OUTGOING) ? "outgoing" : "incoming");
switch (ifo[j].u & ISDN_USAGE_MASK) {
case ISDN_USAGE_RAW : p += sprintf(p, "raw device");
break;
case ISDN_USAGE_MODEM : p += sprintf(p, "tty emulation");
break;
case ISDN_USAGE_NET : p += sprintf(p, "IP interface");
break;
case ISDN_USAGE_VOICE : p += sprintf(p, "Voice");
break;
case ISDN_USAGE_FAX : p += sprintf(p, "Fax");
break;
} /* switch */
p += sprintf(p, "\t%s", ifo[j].n);
if ((chan = b2c(j)) != -1) {
k = call[chan].dialin ? CALLING : CALLED;
p += sprintf(p, " (%s/%s, %s)",
call[chan].vorwahl[k],
call[chan].rufnummer[k],
call[chan].area[k]);
} /* if */
} /* else */
print_msg(PRT_SHOWIMON, "%s\n", sx);
} /* for */
} /* if */
}
else if (!memcmp(s, "ibytes:", 7))
sscanf(s + 8, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
&io[ 0].i, &io[ 1].i, &io[ 2].i, &io[ 3].i,
&io[ 4].i, &io[ 5].i, &io[ 6].i, &io[ 7].i,
&io[ 8].i, &io[ 9].i, &io[10].i, &io[11].i,
&io[12].i, &io[13].i, &io[14].i, &io[15].i);
else if (!memcmp(s, "obytes:", 7)) {
sscanf(s + 8, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
&io[ 0].o, &io[ 1].o, &io[ 2].o, &io[ 3].o,
&io[ 4].o, &io[ 5].o, &io[ 6].o, &io[ 7].o,
&io[ 8].o, &io[ 9].o, &io[10].o, &io[11].o,
&io[12].o, &io[13].o, &io[14].o, &io[15].o);
processbytes();
} /* else */
} /* processinfo */
void clearchan(int chan, int total)
{
register int i;
if (total) {
memset((char *)&call[chan], 0, sizeof(CALL));
call[chan].tei = BROADCAST;
}
else
for (i = 0; i < MAXMSNS; i++)
*call[chan].onum[i] =
*call[chan].num[i] = 0;
call[chan].bchan = -1;
call[chan].cause = -1;
call[chan].loc = -1;
call[chan].aoce = -1;
call[chan].provider = -1;
call[chan].zone = -1;
for (i = 0; i < MAXMSNS; i++) {
strcpy(call[chan].vnum[i], "?");
call[chan].confentry[i] = UNKNOWN;
call[chan].sondernummer[i] = UNKNOWN;
call[chan].intern[i] = 0;
} /* for */
} /* clearchan */
static void addlist(int chan, int type, int mode) /* mode :: 0 = Add new entry, 1 = change existing entry, 2 = Terminate entry, 3 = dump */
{
#define MAXLIST 1000
typedef struct {
int state;
char *vnum[2];
int si;
time_t connect;
time_t disconnect;
int cause;
int uid;
} LIST;
static LIST list[MAXLIST];
static int lp = -1;
register int i;
register char *p;
auto struct tm *tm;
auto char s[BUFSIZ], s1[BUFSIZ];
if (((chan == -1) || call[chan].dialin)) {
if (mode == 0) {
if (++lp == MAXLIST)
lp = 0;
list[lp].state = SETUP;
list[lp].vnum[CALLING] = strdup(call[chan].vnum[CALLING]);
list[lp].vnum[CALLED] = strdup(call[chan].vnum[CALLED]);
list[lp].si = call[chan].si1;
list[lp].connect = call[chan].connect;
list[lp].uid = call[chan].uid;
}
else if ((mode == 1) || (mode == 2)) {
for (i = lp; i >= 0; i--) {
if (call[chan].uid == list[i].uid) {
switch (mode) {
case 1 : list[i].state = CONNECT;
break;
case 2 : list[i].cause = call[chan].cause;
list[i].state = RELEASE;
list[i].disconnect = call[chan].disconnect;
break;
} /* switch */
break;
} /* if */
} /* if */
}
else if (mode == 3) {
for (i = 0; i <= lp; i++) {
tm = localtime(&list[i].connect);
strftime(s1, 64, "%a %b %d %X", tm);
if (!list[i].disconnect)
list[i].disconnect = cur_time;
switch (list[i].si) {
case 1 : p = "Speech"; break;
case 2 : p = "Fax G3"; break;
case 3 : p = "Data"; break;
case 4 : p = "Fax G4"; break;
case 7 : p = "Data"; break;
default : p = ""; break;
} /* switch */
sprintf(s, "%s %s(%s) -> %s %ds %s",
s1,
list[i].vnum[0],
p,
list[i].vnum[1],
(int)(list[i].disconnect - list[i].connect),
qmsg(TYPE_CAUSE, VERSION_EDSS1, list[i].cause));
print_msg(PRT_SHOWNUMBERS, "%s\n", s);
} /* for */
} /* else */
} /* if */
} /* addlist */
void processRate(int chan)
{
call[chan].Rate.start = call[chan].connect;
call[chan].Rate.now = call[chan].disconnect = cur_time;
if (getRate(&call[chan].Rate, NULL) == UNKNOWN)
call[chan].tarifknown = 0;
else {
call[chan].tarifknown = 1;
call[chan].pay = call[chan].Rate.Charge;
} /* else */
} /* processRate */
static void processLCR(int chan, char *hint)
{
auto RATE bestRate, bookRate, pselRate, hintRate;
auto char buffer[BUFSIZ], *p;
auto double pselpreis = -1.0, hintpreis = -1.0, diff;
char prov[TN_MAX_PROVIDER_LEN];
*hint='\0';
*(p=buffer)='\0';
clearRate (&pselRate);
pselRate.prefix=preselect;
memcpy (pselRate.src, call[chan].Rate.src, sizeof (pselRate.src));
memcpy (pselRate.dst, call[chan].Rate.dst, sizeof (pselRate.dst));
pselRate.start = call[chan].Rate.start;
pselRate.now = call[chan].Rate.now;
hintRate = pselRate;
hintRate.prefix=call[chan].hint;
getLeastCost(&call[chan].Rate, &bestRate, 1, -1);
getLeastCost(&call[chan].Rate, &bookRate, 0, -1);
if (getRate(&pselRate, NULL) != UNKNOWN)
pselpreis = pselRate.Charge;
if (getRate(&hintRate, NULL) != UNKNOWN)
hintpreis = hintRate.Charge;
diff = call[chan].pay - bestRate.Charge;
if (diff > 0 && (bestRate.prefix != UNKNOWN) && (bestRate.prefix != call[chan].provider)) {
prefix2provider(bestRate.prefix, prov);
p+=sprintf(p, "\nHINT: Cheapest booked %s:%s %s (would save %s)",
prov, bestRate.Provider,
printRate (bestRate.Charge),
printRate(diff));
}
diff = call[chan].pay - bookRate.Charge;
if (diff > 0 && (bookRate.prefix != UNKNOWN) && (bookRate.prefix != bestRate.prefix)) {
prefix2provider(bookRate.prefix, prov);
p+=sprintf(p, "\nHINT: Overall cheapest %s:%s %s (would save %s)",
prov, bookRate.Provider,
printRate (bookRate.Charge),
printRate(diff));
}
diff = pselpreis - call[chan].pay;
if (diff > 0 && (call[chan].provider != preselect) && (pselpreis != -1.00) && (pselpreis != call[chan].pay)) {
prefix2provider(preselect, prov);
p+=sprintf(p, "\nHINT: Preselect %s:%s %s (you saved %s)",
prov, getProvider(preselect),
printRate (pselpreis),
printRate(diff));
}
diff = hintpreis - call[chan].pay;
if (diff > 0 && (call[chan].hint != UNKNOWN) && (call[chan].hint != bestRate.prefix)) {
prefix2provider(call[chan].hint, prov);
p+=sprintf(p, "\nHINT: Hinted %s:%s %s (saving %s)",
prov, getProvider(call[chan].hint),
printRate (hintpreis),
printRate(diff));
}
if (*buffer) {
p+=sprintf(p, "\nHINT: LCR:%s", (bestRate.prefix == call[chan].provider) ? "OK" : "FAILED");
sprintf (hint, "%s", buffer+1);
}
} /* processLCR */
static void showRates(RATE *Rate, char *message)
{
if (Rate->Basic > 0)
sprintf(message, "CHARGE: %s + %s/%ds = %s + %s/Min (%s)",
printRate(Rate->Basic),
printRate(Rate->Price),
(int)(Rate->Duration + 0.5),
printRate(Rate->Basic),
printRate(60 * Rate->Price / Rate->Duration),
explainRate(Rate));
else
sprintf(message, "CHARGE: %s/%ds = %s/Min (%s)",
printRate(Rate->Price),
(int)(Rate->Duration + 0.5),
printRate(60 * Rate->Price / Rate->Duration),
explainRate(Rate));
} /* showRates */
static void prepareRate(int chan, char **msg, char **tip, int viarep)
{
auto RATE lcRate, ckRate;
static char message[BUFSIZ];
static char lcrhint[BUFSIZ];
if (msg)
*(*msg = message) = '\0';
if (tip)
*(*tip = lcrhint) = '\0';
clearRate(&call[chan].Rate);
if (call[chan].intern[CALLED]) {
call[chan].Rate.zone = UNZONE;
call[chan].zone = INTERN;
call[chan].tarifknown = 0;
if (msg)
sprintf(message, "CHARGE: free of charge - internal call");
return;
} /* if */
call[chan].Rate.prefix = call[chan].provider;
if (call[chan].intern[CALLING]) {
call[chan].Rate.src[0] = mycountry;
call[chan].Rate.src[1] = myarea;
call[chan].Rate.src[2] = "";
}
else {
call[chan].Rate.src[0] = call[chan].areacode[CALLING];
call[chan].Rate.src[1] = call[chan].vorwahl[CALLING];
call[chan].Rate.src[2] = call[chan].rufnummer[CALLING];
} /* else */
if (call[chan].sondernummer[CALLED] != UNKNOWN) {
call[chan].Rate.dst[0] = "";
call[chan].Rate.dst[1] = call[chan].num[CALLED];
call[chan].Rate.dst[2] = "";
}
else {
call[chan].Rate.dst[0] = call[chan].areacode[CALLED];
call[chan].Rate.dst[1] = call[chan].vorwahl[CALLED];
call[chan].Rate.dst[2] = call[chan].rufnummer[CALLED];
} /* else */
if (getRate(&call[chan].Rate, msg) == UNKNOWN)
return;
if (call[chan].Rate.zone == FREECALL) { /* FreeCall */
call[chan].tarifknown = 0;
if (msg)
sprintf(message, "CHARGE: free of charge - FreeCall");
return;
} /* if */
if (call[chan].Rate.zone == UNKNOWN)
call[chan].tarifknown = 0;
else
processRate(chan);
if (viarep)
return;
if (msg && call[chan].tarifknown)
showRates(&call[chan].Rate, *msg=message);
if ((call[chan].hint = getLeastCost(&call[chan].Rate, &lcRate, 1, -1)) != UNKNOWN) {
if (tip) {
double diff;
char prov[TN_MAX_PROVIDER_LEN];
/* compute charge for LCR_DURATION seconds for used provider */
ckRate = call[chan].Rate;
ckRate.now = ckRate.start + LCR_DURATION;
getRate(&ckRate, NULL);
diff = ckRate.Charge - lcRate.Charge;
if(diff > 0) {
prefix2provider(lcRate.prefix, prov);
sprintf(lcrhint, "HINT: Better use %s:%s, %s/%ds = %s/Min, saving %s/Min",
prov, lcRate.Provider,
printRate(lcRate.Price),
(int)(lcRate.Duration + 0.5),
printRate(60 * lcRate.Price / lcRate.Duration),
printRate(60*(diff)/lcRate.Time));
}
} /* if */
} /* if */
} /* prepareRate */
#if 0
static void LCR(int chan, char *s)
{
auto char *why, *hint;
auto struct tms t1, t2;
auto long int tr1, tr2;
tr1 = times(&t1);
print_msg(PRT_NORMAL, ">> LCR: OUTGOING SETUP(%s)\n", s + 5);
print_msg(PRT_NORMAL, ">> LCR: from TEI %d, to number \"%s\", Provider=%s%d:%s, Sonderrufnummer=%d, InternalCall=%d, LocalCall=%d\n",
call[chan].tei, call[chan].num[CALLED], vbn, call[chan].provider, getProvider(call[chan].provider),
call[chan].sondernummer[CALLED], call[chan].intern[CALLED], call[chan].local[CALLED]);
if (!call[chan].intern[CALLED]) { /* keine Hausinternen Gespr<70>che */
if (!call[chan].local[CALLED]) { /* keine Ortsgespr<70>che */
if (call[chan].sondernummer[CALLED] == UNKNOWN) { /* keine Sonderrufnummern */
call[chan].disconnect = call[chan].connect = cur_time;
prepareRate(chan, &why, &hint, 0);
if (call[chan].hint == UNKNOWN)
print_msg(PRT_NORMAL, ">> LCR: NO ACTION: Better provider unknown :-(\n", why);
else if (call[chan].hint == call[chan].provider)
print_msg(PRT_NORMAL, ">> LCR: Best provider already used!", why);
else {
print_msg(PRT_NORMAL, ">> LCR: %s\n", why);
print_msg(PRT_NORMAL, ">> LCR: %s\n", hint);
tr2 = times(&t2);
print_msg(PRT_NORMAL, ">> LCR: FAKE! TRYING(%s%d0%s) - Time required: %8.6g s\n", vbn, call[chan].hint, call[chan].num[CALLED] + 3, (double)(tr2 - tr1) / (double)CLK_TCK);
} /* else */
}
else
print_msg(PRT_NORMAL, ">> LCR: NO ACTION: Sonderrufnummer\n");
}
else
print_msg(PRT_NORMAL, ">> LCR: NO ACTION: Local call\n");
}
else
print_msg(PRT_NORMAL, ">> LCR: NO ACTION: Internal call\n");
} /* LCR */
#endif
static void processctrl(int card, char *s)
{
register char *ps = s, *p;
register int i, c;
register int wegchan; /* fuer gemakelte */
auto int dialin, type = 0, cref = -1, creflen, version;
static int tei = BROADCAST, sapi = 0, net = 1, firsttime = 1;
auto char sx[BUFSIZ], s1[BUFSIZ], s2[BUFSIZ];
auto char *why, *hint;
auto char hints[BUFSIZ];
static char last[BUFSIZ];
auto int isAVMB1 = 0;
auto double tx;
hexSeen = 1;
if (Q931dmp) {
register int bcast = (strtol(ps + 8, NIL, 16) >> 1) == 0x7f;
register int sr = strtol(ps + (bcast ? 20 : 23), NIL, 16);
if (replaydev)
fprintf(stdout, "\n\n-----[ %d ]---[ %c ]---[ %d.card ]-------------------------------------------------------------------\n\n", ++lfd, (sr > 127 ? 'S' : 'R'), card + 1);
else
fprintf(stdout, "\n\n-----[ %d ]---[ %c ]---[ %d.card ]---[ %s ]------------------------------------------\n\n", ++lfd, (sr > 127 ? 'S' : 'R'), card + 1, st + 4);
if (bcast) {
s[13] = 0;
fprintf(stdout, "%s %s\n\n", s + 5, s + 14);
s[13] = ' ';
}
else
fprintf(stdout, "%s\n\n", s + 5);
} /* if */
if (verbose & VERBOSE_CTRL)
print_msg(PRT_LOG, "%s\n", s);
if (!memcmp(ps, "D2", 2)) { /* AVMB1 */
if (firsttime) {
firsttime = 0;
print_msg (PRT_NORMAL, "(AVM B1 driver detected (D2))\n");
} /* if */
memcpy(ps, "HEX: ", 5);
} /* if */
if (!memcmp(ps, "HEX: ", 5)) { /* new HiSax Driver */
if (((verbose & VERBOSE_HEX) && !(verbose & VERBOSE_CTRL)) || stdoutput)
print_msg(PRT_LOG, "%2d %s\n", card, s);
if (firsttime) {
firsttime = 0;
if (!Q931dmp)
print_msg(PRT_NORMAL, "(HiSax driver detected)\n");
HiSax = 1;
strcpy(last, s);
}
else {
if (!strcmp(last, s)) {
if (!Q931dmp)
return;
}
else
strcpy(last, s);
} /* else */
if (Q931dmp) {
register char *s1;
#if 0
register char *s2;
#endif
register int i = strtol(ps + 5, NIL, 16);
register int j = strtol(ps + 8, NIL, 16);
register int k = strtol(ps + 11, NIL, 16);
register int l = strtol(ps + 14, NIL, 16);
register int sapi = i >> 2;
register int cr = (i >> 1) & 1;
register int ea2 = i & 1;
register int tei = j >> 1;
register int bcast = 0;
register int ea3 = j & 1;
#if 0
switch (sapi) {
case 0 : s1 = "Signalisierungsblock"; break;
case 16 : s1 = "Paketdatenblock"; break;
case 63 : s1 = "TEI-Verwaltungsblock"; break;
default : s1 = "UNKNOWN sapi"; break;
} /* switch */
if (tei == BROADCAST) {
s2 = "Broadcast";
bcast = 1;
}
else if (tei < 64)
s2 = "feste TEI";
else
s2 = "zugeteilte TEI";
fprintf(stdout, "%02x SAPI=%d C/R=%d E/A=%d [%s]\n",
i, sapi, cr, ea2, s1);
fprintf(stdout, "%02x TEI=%d E/A=%d [%s]\n",
j, tei, ea3, s2);
#else
fprintf(stdout, "%02x SAPI=%d C/R=%d E/A=%d\n",
i, sapi, cr, ea2);
if (sapi == 63) {
fprintf(stdout, "%02x TEI Vergabe\n", j);
if (k == 3)
fprintf(stdout, "%02x UI\n", k);
switch (l = strtol(ps + 14, NIL, 16)) {
case 0x0f : fprintf(stdout, "%02x Management Entity Identifier\n", l); break;
} /* switch */
l = strtol(ps + 17, NIL, 16);
fprintf(stdout, "%02x Referenz Indikator\n", l);
l = strtol(ps + 20, NIL, 16);
fprintf(stdout, " %02x Referenz Indikator\n", l);
switch (l = strtol(ps + 23, NIL, 16)) {
case 1 : fprintf(stdout, " %02x TEI ANFORDERUNG\n", l); break;
case 2 : fprintf(stdout, " %02x TEI ZUWEISUNG\n", l); break;
case 4 : fprintf(stdout, " %02x TEI BITTE PRUEFEN\n", l); break;
} /* switch */
k = strtol(ps + 26, NIL, 16);
if (l == 2)
fprintf(stdout, " %02x ZUGEWIESENER TEI=%d\n", k, k >> 1);
else
fprintf(stdout, " %02x AKTIONS INDIKATOR\n", k);
}
else
fprintf(stdout, "%02x TEI=%d E/A=%d\n", j, tei, ea3);
#endif
if (sapi != 63) { /* keine TEI Vergabe */
if (!(k & 1)) { /* I-Block */
if (bcast)
fprintf(stdout, "%02x I-B N=%d\n", k, k >> 1);
else
fprintf(stdout, "%02x I-B N=%d %02x: N(R)=%d P=%d\n",
k, k >> 1, l, l >> 1, l & 1);
}
else if ((k & 3) == 1) { /* S-Block */
switch (k) {
case 01 : s1 = "RR"; break;
case 05 : s1 = "RNR"; break;
case 07 : s1 = "REJ"; break;
default : s1 = "UNKNOWN S-Block"; break;
} /* switch */
if (bcast)
fprintf(stdout, "%02x %s\n", k, s1);
else
fprintf(stdout, "%02x %s %02x: N(R)=%d P/F=%d\n",
k, s1, l, l >> 1, l & 1);
}
else { /* U-Format */
switch (k) {
case 0x7f : s1 = "SABME P=1"; break;
case 0x6f : s1 = "SABME P=0"; break;
case 0x0f : s1 = "DM F=0"; break;
case 0x1f : s1 = "DM F=1"; break;
case 0x53 : s1 = "DISC P=1"; break;
case 0x43 : s1 = "DISC P=0"; break;
case 0x73 : s1 = "UA F=1"; break;
case 0x63 : s1 = "UA F=0"; break;
case 0x93 : s1 = "FRMR F=1"; break;
case 0x83 : s1 = "FRMR F=0"; break;
case 0x13 : s1 = "UI P=1"; break;
case 0x03 : s1 = "UI P=0"; break;
default : s1 = "UNKNOWN U-Block"; break;
} /* switch */
fprintf(stdout, "%02x %s\n", k, s1);
} /* else */
} /* if */
} /* if */
#if 0 /* wird so ins syslog eingetragen :-( */
if (!replay)
if (strtol(ps + 11, NIL, 16) == 1)
print_msg(PRT_NORMAL, "%c\b", (strtol(ps + 5, NIL, 16) == 2) ? '>' : '<');
#endif
if (!*(ps + 13) || !*(ps + 16))
return;
i = strtol(ps += 5, NIL, 16) >> 1;
net = i & 1;
sapi = i >> 1;
if (sapi == 63) /* AK:07-Nov-98 -- future expansion */
return;
tei = strtol(ps += 3, NIL, 16) >> 1;
ps += (tei == BROADCAST) ? 1 : 4;
}
else if (!memcmp(ps, "D3", 2)) { /* AVMB1 */
if (firsttime) {
firsttime = 0;
print_msg(PRT_NORMAL, "(AVM B1 driver detected (D3))\n");
} /* if */
if (*(ps + 2) == '<') /* this is our "direction flag" */
net = 1;
else
net = 0;
tei = 65; /* we can't get a tei, so fake it */
isAVMB1 = 1;
ps[0] = 'h'; ps[1] = 'e'; ps[2] = 'x'; /* rewrite for the others */
}
else { /* Old Teles Driver */
/* Tei wird gelesen und bleibt bis zum Ende des naechsten hex: stehen.
Der naechste hex: -Durchlauf hat also die korrekte tei. */
if (!memcmp(ps, "Q.931 frame network->user tei ", 30)) {
tei = strtol(ps += 30, NIL, 10);
net = 1;
}
else if (!memcmp(ps, "Q.931 frame user->network tei ", 30)) {
tei = strtol(ps += 30, NIL, 10);
net = 0;
}
else if (!memcmp(ps, "Q.931 frame network->user with tei ", 35)) {
tei = strtol(ps += 35, NIL, 10);
net = 1;
}
else if (!memcmp(ps, "Q.931 frame network->user", 25)) {
net = 1;
tei = BROADCAST;
} /* else */
} /* else */
if (!memcmp(ps, "hex: ", 5) || !memcmp(s, "HEX: ", 5)) {
i = strtol(ps += 5, NIL, 16);
switch (i) {
case 0x40 :
case 0x41 : version = VERSION_1TR6;
break;
case 0x08 : version = VERSION_EDSS1;
break;
case 0xaa : version = VERSION_UNKNOWN; /* Euracom Frames */
return;
default : version = VERSION_UNKNOWN;
sprintf(sx, "Unexpected discriminator 0x%02x -- ignored!", i);
info(chan, PRT_SHOWNUMBERS, STATE_RING, sx);
return;
} /* switch */
if (Q931dmp) {
register int crl = strtol(ps + 3, NIL, 16);
register int crw = strtol(ps + 6, NIL, 16);
if (crl) {
#if 0
register int dir = crw >> 7;
register int cr = crw & 0x7f;
register char *s1, *s2;
if (cr < 64) {
s1 = "Dialin";
s2 = dir ? "User->VSt" : "VSt->User";
}
else {
s1 = "Dialout";
s2 = dir ? "VSt->User" : "User->VSt";
} /* else */
fprintf(stdout, "%02x %s, PD=%02x %02x: CRL=%d %02x: CRW=%d %s [%s, %s]\n",
i, (version == VERSION_EDSS1) ? "E-DSS1" : "1TR6", i, crl,
crl, crw, crw & 0x7f, (crw > 127) ? "Zielseite" : "Ursprungsseite", s1, s2);
#else
fprintf(stdout, "%02x %s, PD=%02x %02x: CRL=%d %02x: CRW=%d %s\n",
i, (version == VERSION_EDSS1) ? "E-DSS1" : "1TR6", i, crl,
crl, crw, crw & 0x7f, (crw > 127) ? "Zielseite" : "Ursprungsseite");
#endif
}
else
fprintf(stdout, "%02x %s, PD=%02x %02x: CRL=%d\n",
i, (version == VERSION_EDSS1) ? "E-DSS1" : "1TR6", i, crl,
crl);
} /* if */
if (bilingual && version == VERSION_1TR6) {
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: OOPS! 1TR6 Frame? Ignored!\n", st + 4);
goto endhex;
} /* if */
creflen = strtol(ps += 3, NIL, 16);
if (creflen)
cref = strtol(ps += 3, NIL, 16);
else
cref = -1;
type = strtol(ps += 3, NIL, 16);
if (!isAVMB1)
dialin = (tei == BROADCAST); /* dialin (Broadcast), alle anderen haben schon eine Tei! */
else
dialin = (cref & 0x80); /* first (SETUP) tells us who initiates the connection */
/* dialin = (cref & 0x7f) < 64; */
cref = (net) ? cref : cref ^ 0x80; /* cref immer aus Sicht des Amts */
if (Q931dmp)
Q931dump(TYPE_MESSAGE, type, NULL, version);
if (allflags & PRT_DEBUG_DIAG)
diag(cref, tei, sapi, dialin, net, type, version);
/* leider laesst sich kein switch nehmen, da decode
innerhalb von SETUP/A_ACK aufgerufen werden muss, sonst
aber erst nach feststellen von chan
Daher GOTO (urgs...) an das Ende vom if hex:.. */
if (type == SETUP) { /* neuen Kanal, ev. dummy, wenn keiner da ist */
chan = 5; /* den nehmen wir _nur_ dafuer! */
clearchan(chan, 1);
call[chan].dialin = dialin;
call[chan].tei = tei;
call[chan].card = card;
call[chan].uid = ++uid;
decode(chan, ps, type, version, tei);
#if 0
if (OUTGOING && *call[chan].num[CALLED])
LCR(chan, s);
#endif
if (call[chan].channel) { /* Aha, Kanal war dabei, dann nehmen wir den gleich */
chan = call[chan].channel - 1;
if (chanused[chan])
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: chan#%d already in use!\n", st + 4, chan);
chanused[chan] = 1;
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: Chan auf %d gesetzt\n", st + 4, chan);
/* nicht --channel, channel muss unveraendert bleiben! */
memcpy((char *)&call[chan], (char *)&call[5], sizeof(CALL));
Change_Channel(5, chan);
clearchan(5, 1);
} /* if */
call[chan].cref = (dialin) ? cref : (cref | 0x80); /* immer die cref, die _vom_ Amt kommt/kommen sollte */
call[chan].dialin = dialin;
call[chan].tei = tei;
call[chan].card = card;
call[chan].connect = cur_time;
call[chan].duration = tt;
call[chan].state = type;
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: START CHAN#%d tei %d cref %d %d %s %s->\n",
st + 4, chan, tei, cref, call[chan].cref,
call[chan].dialin ? " IN" : "OUT",
net ? "NET" : "USR");
addlist(chan, type, 0);
goto endhex;
} /* if SETUP */
/* AK:13-Feb-97 ::
Bei Rausrufen mit Creatix a/b kommt im
SETUP : Channel identification : BRI, beliebiger Kanal
und im
SETUP ACKNOWLEDGE : Channel identification : BRI, B1 gefordert
Bei Rausrufen mit Europa-10 dagegen:
SETUP : --
SETUP ACKNOWLEDGE : Channel identification : BRI, B1 gefordert
*/
if ((type == SETUP_ACKNOWLEDGE) || (type == CALL_PROCEEDING)) {
/* Kann sein, dass ein SETUP vorher kam, suchen wir mal, denkbar:
a) SETUP in 5 (eig. rausruf): decode auf 5, dann copy nach channel
b) nichts (rausruf fremd): decode auf 5, copy nach channel */
chan = 5;
if ((call[5].cref != cref) || (call[5].tei != tei)) {
/* bei C_PROC/S_ACK ist cref _immer_ > 128 */
/* keiner da, also leeren */
if (isAVMB1 && (call[chan].state == SETUP)) /* direction already set for AVMB1 */
dialin = call[chan].dialin;
clearchan(chan, 1);
call[chan].dialin = dialin;
call[chan].tei = tei;
call[chan].cref = cref;
call[chan].card = card;
} /* if */
decode(chan, ps, type, version, tei);
if (call[chan].channel) { /* jetzt muesste einer da sein */
chan = call[chan].channel - 1;
/* nicht --channel, channel muss unveraendert bleiben! */
memcpy((char *)&call[chan], (char *)&call[5], sizeof(CALL));
Change_Channel(5, chan);
addlist(chan, type, 1);
clearchan(5, 1);
}
else
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: OOPS, C_PROC/S_ACK ohne channel? tei %d\n",
st + 4, tei);
call[chan].connect = cur_time;
call[chan].duration = tt;
call[chan].state = type;
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: START CHAN#%d tei %d %s %s->\n",
st + 4, chan, tei,
call[chan].dialin ? " IN" : "OUT",
net ? "NET" : "USR");
goto endhex;
} /* if C_PROC || S_ACK */
if (type == AOCD_1TR6) {
decode(chan, ps, type, version, tei);
goto endhex;
} /* if AOCD_1TR6 */
/* Beim Makeln kommt Geb. Info nur mit Cref und Tei, die
cref muessen wir dann in chan 2/3 suchen */
/* Bei geparkten Gespr. kommen die waehrend des Parkens
aufgelaufenen Gebuehren beim Wiederholen. */
if ((cref != call[0].cref) && (cref != call[1].cref) &&
(cref != call[2].cref) && (cref != call[3].cref)) {
decode(6, ps, type, version, tei);
/* Mit falscher cref kommt hier keiner rein, koennte
ein RELEASE auf bereits freiem Kanal sein */
goto endhex;
} /* if */
/* So, wenn wir hier ankommen, haben wir auf jeden Fall einen
Kanal (0, 1, 2 oder 3) und eine cref. Die tei folgt evtl. erst beim
Connect (Reinruf). Suchen wir den Kanal: */
/* crefs absuchen. Gibt's die mehrmals, tei absuchen, dann haben wir
ihn.
Es kann aber sein, dass cref stimmt, aber noch keine tei da war
(Reinruf). Dann ist aber die cref eindeutig (hoffentlich)!
finden wir einen Kanal mit passender cref, der keine
tei hat, haben wir ihn. Hat er eine, und sie stimmt,
ebenso. Sonst weitersuchen. Geparkte Kanaele ignorieren
bis zum RESUME, oder sie werden bei neuem SETUP_ACK. ueber-
schrieben, wenn wir wen im Parken verhungen lassen haben */
chan = -1;
for (i = 0; ((i < 4) &&
((call[i].cref != cref) ||
((call[i].state == SUSPEND) && (type != RESUME_ACKNOWLEDGE)) ||
((call[i].tei != BROADCAST) && (call[i].tei != tei)))); i++);
chan = i;
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: Kanal %d\n", st + 4, chan);
/* auch wenn hier schon eine tei bei ist, erst beim connect hat
ein reingerufener Kanal eine gueltige tei */
decode(chan, ps, type, version, tei);
chanused[chan] = 2;
switch (type) {
case ALERTING :
case CALL_PROCEEDING :
if (!Q931dmp)
if (dual && *call[chan].digits) {
strcpy(call[chan].onum[CALLED], call[chan].digits);
buildnumber(call[chan].digits, call[chan].oc3, -1, call[chan].num[CALLED], version, &call[chan].provider, &call[chan].sondernummer[CALLED], &call[chan].intern[CALLED], &call[chan].local[CALLED], call[chan].dialin, CALLED);
strcpy(call[chan].vnum[CALLED], vnum(chan, CALLED));
} /* if */
break;
case CONNECT :
case CONNECT_ACKNOWLEDGE :
/* Bei Rufen an die Teles kommt CONNECT und CONN.ACKN., eins reicht uns */
if (call[chan].state == CONNECT)
goto doppelt;
call[chan].state = CONNECT;
call[chan].tei = tei;
call[chan].dialog++; /* es hat connect gegeben */
call[chan].connect = cur_time;
call[chan].duration = tt;
call[chan].card = card;
if (*call[chan].service) {
sprintf(sx, "CONNECT (%s)", call[chan].service);
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, sx);
}
else
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, "CONNECT");
if (OUTGOING && *call[chan].num[CALLED]) {
prepareRate(chan, &why, &hint, 0);
if (*why)
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, why);
if (*hint)
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, hint);
if (call[chan].tarifknown) {
call[chan].ctakt = call[chan].Rate.Units;
sprintf(sx, "%d.CI %s (now)", call[chan].ctakt, printRate(call[chan].pay));
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, sx);
call[chan].cint = call[chan].Rate.Duration;
snprintf(sx, BUFSIZ, "NEXT CI AFTER %s (%s)",
double2clock(call[chan].cint) + 3,
explainRate(&call[chan].Rate));
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, sx);
huptime(chan, 1);
if ((c = call[chan].confentry[OTHER]) > -1) {
if (!replay && (chargemax != 0.0)) {
if (day != known[c]->day) {
sprintf(s1, "CHARGEMAX resetting %s's charge (day %d->%d)",
known[c]->who, (known[c]->day == -1) ? 0 : known[c]->day, day);
info(chan, PRT_SHOWCHARGEMAX, STATE_AOCD, s1);
known[c]->scharge += known[c]->charge;
known[c]->charge = 0.0;
known[c]->day = day;
} /* if */
tx = cur_time - call[chan].connect;
sprintf(s1, "CHARGEMAX remaining=%s %s %s",
printRate((chargemax - known[c]->charge - call[chan].pay)),
(connectmax == 0.0) ? "" : double2clock(connectmax - known[c]->online - tx),
(bytemax == 0.0) ? "" : double2byte((double)(bytemax - known[c]->bytes)));
info(chan, PRT_SHOWCHARGEMAX, STATE_AOCD, s1);
if (((known[c]->charge + call[chan].pay) >= chargemax) && (*known[c]->interface > '@'))
chargemaxAction(chan, (known[c]->charge + call[chan].pay - chargemax));
} /* if */
if (!replay && (connectmax != 0.0)) {
if (month != known[c]->month) {
sprintf(s1, "CONNECTMAX resetting %s's online (month %d->%d)",
known[c]->who, (known[c]->month == -1) ? 0 : known[c]->month, month);
info(chan, PRT_SHOWCHARGEMAX, STATE_AOCD,s1);
known[c]->sonline += known[c]->online;
known[c]->online = 0.0;
known[c]->month = month;
known[c]->sbytes += known[c]->bytes;
known[c]->bytes = 0.0;
} /* if */
} /* if */
} /* if */
} /* if */
} /* if */
if (sound)
ringer(chan, RING_CONNECT);
doppelt:break;
case SUSPEND_ACKNOWLEDGE :
call[chan].state = SUSPEND;
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, "PARK");
break;
case RESUME_ACKNOWLEDGE :
call[chan].state = CONNECT;
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, "RESUME");
break;
case MAKEL_ACKNOWLEDGE :
wegchan = (call[2].state) ? 3 : 2;
memcpy((char *)&call[wegchan], (char *)&call[chan], sizeof(CALL));
Change_Channel(chan, wegchan);
addlist(wegchan, type, 1);
clearchan(chan, 1);
call[wegchan].state = MAKEL_ACKNOWLEDGE;
info(wegchan, PRT_SHOWHANGUP, STATE_HANGUP, "MAKEL");
break;
case MAKEL_RESUME_ACK :
if (call[chan].channel) { /* muesste einer da sein */
memcpy((char *)&call[call[chan].channel - 1], (char *)&call[chan], sizeof(CALL));
call[call[chan].channel - 1].channel = chan; /* den alten merken */
Change_Channel(chan, call[chan].channel - 1);
chan = call[chan].channel - 1; /* chan setzen */
addlist(chan, type, 1);
clearchan(call[chan].channel, 1);
call[chan].channel = chan + 1; /* in Ordnung bringen */
call[chan].state = CONNECT;
} /* if */
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, "MAKELRESUME");
break;
case DISCONNECT :
if (!call[chan].state) /* Keine Infos -> Weg damit */
break;
call[chan].disconnect = cur_time;
if (replay)
call[chan].duration = (tt - call[chan].duration) * 100;
else
call[chan].duration = tt - call[chan].duration;
call[chan].state = DISCONNECT;
break;
case RELEASE :
case RELEASE_COMPLETE :
if (!net) /* wir nehmen nur RELEASE vom Amt */
break;
if (!call[chan].state) /* Keine Infos -> Weg damit */
break;
/* Wenn's keinen CONNECT gab, hat's auch nichts gekostet.
Falls der RELEASE aber ein Rufablehnen war und der
CONNECT noch folgt, wird dafuer jetzt chan auf
4 gepackt, um die schoenen Daten in 0/1/ev.4 nicht
zu zerstoeren. Wir erkennen das an fehlender tei. */
if (call[chan].tei == BROADCAST) {
memcpy((char *)&call[4], (char *)&call[chan], sizeof(CALL));
Change_Channel(chan, 4);
chan = 4;
addlist(chan, type, 1);
call[chan].tei = tei;
call[chan].card = card;
} /* if */
if (!call[chan].disconnect) {
call[chan].disconnect = cur_time;
if (replay)
call[chan].duration = (tt - call[chan].duration) * 100;
else
call[chan].duration = tt - call[chan].duration;
} /* if */
if (!call[chan].dialog) {
call[chan].duration = 0;
call[chan].disconnect = call[chan].connect;
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: CHAN#%d genullt (dialin=%d, state=%d, tei=%d, cref=%d)\n",
st + 4, chan, call[chan].dialin, call[chan].state, call[chan].tei, call[chan].cref);
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: OOPS! DURATION=0\n", st + 4);
if (OUTGOING) {
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: OOPS! AOCE=0\n", st + 4);
} /* if */
} /* if kein connect */
if (allflags & PRT_DEBUG_BUGS) {
strcpy(sx, ctime(&call[chan].connect));
sx[19] = 0;
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: LOG CHAN#%d(%s : DIAL%s : %s -> %s : %d s (%d s) : %d EH):%s\n\n",
st + 4, chan,
sx + 4,
call[chan].dialin ? "IN" : "OUT",
call[chan].num[CALLING],
call[chan].num[CALLED],
(int)(call[chan].disconnect - call[chan].connect),
(int)call[chan].duration,
call[chan].aoce,
qmsg(TYPE_CAUSE, version, call[chan].cause));
} /* if */
if (OUTGOING && call[chan].duration) {
processRate(chan);
if (call[chan].tarifknown) {
char *h = hints;
processLCR(chan, h);
while (h && *h)
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, strsep(&h, "\n"));
} /* if */
} /* if */
if (!Q931dmp)
logger(chan);
chanused[chan] = 0;
addlist(chan, type, 2);
if (call[chan].dialog || any) {
if (call[chan].ibytes + call[chan].obytes) {
sprintf(s2, " I=%s O=%s",
double2byte((double)call[chan].ibytes),
double2byte((double)call[chan].obytes));
}
else
*s2 = 0;
if (call[chan].dialin)
sprintf(sx, "HANGUP (%s%s)",
double2clock((double)(call[chan].disconnect - call[chan].connect)), s2);
else {
auto int firsttime = 1;
register char *p = sx;
p += sprintf(p, "HANGUP");
if (call[chan].Rate.Units > 0) {
if (firsttime) {
p += sprintf(p, " (");
firsttime = 0;
} /* if */
p += sprintf(p, "%d CI %s",
call[chan].Rate.Units,
printRate(call[chan].pay));
} /* if */
if (call[chan].aocpay > 0) {
if (firsttime) {
p += sprintf(p, " (");
firsttime = 0;
}
else
p += sprintf(p, "; ");
p += sprintf(p, "%d EH %s %s",
call[chan].aoce,
currency,
double2str(call[chan].aocpay, 6, 3, DEB));
} /* if */
if (call[chan].disconnect - call[chan].connect) {
if (firsttime) {
p += sprintf(p, " (");
firsttime = 0;
}
else
p += sprintf(p, " ");
p += sprintf(p, "%s",
double2clock((double)(call[chan].disconnect - call[chan].connect)));
} /* if */
if (*s2) {
if (firsttime) {
p += sprintf(p, " (");
firsttime = 0;
} /* if */
p += sprintf(p, "%s", s2);
} /* if */
if (!firsttime)
p += sprintf(p, ")");
#if 0
if (call[chan].Rate.Units > 0)
sprintf(sx, "HANGUP (%d CI %s %s%s)",
call[chan].aoce,
printRate(call[chan].pay),
double2clock((double)(call[chan].disconnect - call[chan].connect)), s2);
else if (call[chan].pay)
sprintf(sx, "HANGUP (%s %s%s)",
((call[chan].pay == -1.0) ? "UNKNOWN" : printRate(call[chan].pay)),
double2clock((double)(call[chan].disconnect - call[chan].connect)), s2);
else if (call[chan].aocpay)
sprintf(sx, "HANGUP (%d EH %s %s %s%s)",
call[chan].aoce,
currency,
double2str(call[chan].aocpay, 6, 3, DEB),
double2clock((double)(call[chan].disconnect - call[chan].connect)), s2);
else
sprintf(sx, "HANGUP (%s%s)", double2clock((double)(call[chan].disconnect - call[chan].connect)), s2);
#endif
} /* else */
if (!memcmp(sx, "HANGUP ( )", 17))
sx[6] = 0;
if ((call[chan].cause != 0x10) && (call[chan].cause != 0x1f)) { /* "Normal call clearing", "Normal, unspecified" */
strcat(sx, " ");
strcat(sx, qmsg(TYPE_CAUSE, version, call[chan].cause));
if (((p = location(call[chan].loc)) != "")) {
strcat(sx, " (");
strcat(sx, p);
strcat(sx, ")");
} /* if */
} /* if */
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
if (((call[chan].cause == 0x22) || /* No circuit/channel available */
(call[chan].cause == 0x2a)) && /* Switching equipment congestion */
((call[chan].loc == 2) || /* Public network serving local user */
(call[chan].loc == 3))) { /* Transit network */
auto char s[BUFSIZ], s1[BUFSIZ];
RATE Other;
prepareRate(chan, NULL, NULL, 0);
if (getLeastCost(&call[chan].Rate, &Other, 1, call[chan].provider) != UNKNOWN) {
char prov[TN_MAX_PROVIDER_LEN];
prefix2provider(Other.prefix, prov);
showRates(&Other, s1);
sprintf(s, "OVERLOAD? Try %s:%s (%s)", prov, Other.Provider, s1);
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, s);
} /* if */
} /* if */
if (OUTGOING && ((c = call[chan].confentry[OTHER]) > -1)) {
if (chargemax != 0.0) {
known[c]->charge += call[chan].pay;
sprintf(sx, "CHARGEMAX total=%s today=%s remaining=%s",
printRate(known[c]->scharge + known[c]->charge),
printRate(known[c]->charge),
printRate((chargemax - known[c]->charge)));
info(chan, PRT_SHOWCHARGEMAX, STATE_HANGUP, sx);
} /* if */
if (connectmax != 0.0) {
if (connectmaxmode == 1)
known[c]->online += ((int)((call[chan].disconnect - call[chan].connect + 59) / 60.0)) * 60.0;
else
known[c]->online += call[chan].disconnect - call[chan].connect;
sprintf(sx, "CONNECTMAX total=%s month=%s remaining=%s",
double2clock(known[c]->sonline + known[c]->online),
double2clock(known[c]->online),
double2clock(connectmax - known[c]->online));
info(chan, PRT_SHOWCHARGEMAX, STATE_HANGUP, sx);
} /* if */
if (bytemax != 0.0) {
auto double byte;
switch (bytemaxmode & 25) {
case 8 : byte = call[chan].obytes;
break;
case 16 : byte = call[chan].ibytes + call[chan].obytes;
break;
default : byte = call[chan].ibytes;
break;
} /* switch */
switch (bytemaxmode & 3) {
case 0 : known[c]->bytes += byte;
break;
case 1 : known[c]->bytes += byte;
break;
case 2 : known[c]->bytes += byte;
break;
} /* switch */
sprintf(sx, "BYTEMAX total=%s month=%s remaining=%s",
double2byte((double)(known[c]->sbytes + known[c]->bytes)),
double2byte((double)(known[c]->bytes)),
double2byte((double)(bytemax - known[c]->bytes)));
info(chan, PRT_SHOWCHARGEMAX, STATE_HANGUP, sx);
} /* if */
} /* if */
if (sound)
ringer(chan, RING_HANGUP);
} /* if */
clearchan(chan, 1);
break;
} /* switch */
endhex:
tei = BROADCAST; /* Wenn nach einer tei-Zeile keine hex:-Zeile kommt, tei ungueltig machen! */
if ((type == SETUP) && !replay) { /* fetch additional info from "/dev/isdninfo" */
static void moreinfo(); /* soviel zu Objektorientiertem Denken ;-) */
moreinfo();
} /* if */
} /* if */
} /* processctrl */
void processflow()
{
register char *p;
register int j;
auto char sx[BUFSIZ];
auto double s;
if (!ioctl(sockets[ISDNINFO].descriptor, IIOCGETCPS, &io)) {
if (verbose & VERBOSE_FLOW) {
p = sx;
s = 0L;
for (j = 0; j < chans; j++) {
p += sprintf(p, "%ld ", io[j].i);
s += io[j].i;
} /* for */
if (s > 0L)
print_msg(PRT_LOG, "ibytes:\t%s\n", sx);
p = sx;
s = 0L;
for (j = 0; j < chans; j++) {
p += sprintf(p, "%ld ", io[j].o);
s += io[j].o;
} /* for */
if (s > 0L)
print_msg(PRT_LOG, "obytes:\t%s\n", sx);
} /* if */
processbytes();
} /* if */
} /* processflow */
int morectrl(int card)
{
register char *p, *p1, *p2, *p3;
register int go;
static char s[MAXCARDS][BIGBUFSIZ * 2];
static char *ps[MAXCARDS] = { s[0], s[1] };
auto int n = 0;
auto struct tm *tm;
if ((n = read(sockets[card ? ISDNCTRL2 : ISDNCTRL].descriptor, ps[card], BIGBUFSIZ)) > 0) {
now();
ps[card] += n;
*ps[card] = 0;
p1 = s[card];
while ((p = p2 = strchr(p1, '\n'))) {
*p = 0;
while (*--p == ' ')
*p = 0;
retry:
if (replay) {
if (replaydev)
p3 = p1;
else {
cur_time = tt = atom(p1 + 4);
if (cur_time == (time_t)-1) {
now();
replaydev++;
goto retry;
} /* if */
set_time_str();
tm = localtime(&cur_time);
p3 = p1 + 26;
} /* if */
processcint();
if (!memcmp(p3, "idmap:", 6) ||
!memcmp(p3, "chmap:", 6) ||
!memcmp(p3, "drmap:", 6) ||
!memcmp(p3, "usage:", 6) ||
!memcmp(p3, "flags:", 6) ||
!memcmp(p3, "phone:", 6) ||
!memcmp(p3, "ibytes:", 7) ||
!memcmp(p3, "obytes:", 7))
processinfo(p3);
else if (!memcmp(p3, "HEX: ", 5) ||
!memcmp(p3, "hex: ", 5) ||
/* !memcmp(p3, "D2<: ", 5) || Layer 2 not yet evaluated */
/* !memcmp(p3, "D2>: ", 5) || Layer 2 not yet evaluated */
!memcmp(p3, "D3<: ", 5) ||
!memcmp(p3, "D3>: ", 5))
processctrl(0, p3);
else if (!memcmp(p3 + 3, "HEX: ", 5))
processctrl(atoi(p3), p3 + 3);
}
else {
go = 1;
if (((ignoreRR & 1) == 1) && (strlen(p1) < 17))
go = 0;
if (((ignoreRR & 2) == 2) && !memcmp(p1 + 14, "AA", 2))
go = 0;
if (go) {
if (!memcmp(p1, "ECHO:", 5)) { /* Echo-channel from HFC card */
memcpy(p1 + 1, "HEX", 3);
processctrl(card + 1, p1 + 1);
}
else
processctrl(card, p1);
} /* if */
} /* else */
p1 = p2 + 1;
} /* while */
if (p1 < ps[card]) {
n = ps[card] - p1;
memmove(s, p1, n);
ps[card] = s[card] + n;
}
else
ps[card] = s[card];
return(1);
}
else {
alarm(0);
return(0);
} /* else */
} /* morectrl */
void moreinfo()
{
register char *p, *p1, *p2;
static char s[BIGBUFSIZ * 2];
static char *ps = s;
auto int n;
if ((n = read(sockets[ISDNINFO].descriptor, ps, BIGBUFSIZ)) > 0) {
now();
ps += n;
*ps = 0;
p1 = s;
while ((p = p2 = strchr(p1, '\n'))) {
*p = 0;
while (*--p == ' ')
*p = 0;
processinfo(p1);
p1 = p2 + 1;
} /* while */
if (p1 < ps) {
n = ps - p1;
memmove(s, p1, n);
ps = s + n;
}
else
ps = s;
} /* if */
} /* moreinfo */
/*****************************************************************************/
void morekbd()
{
auto char s[BIGBUFSIZ * 2];
auto char *ps = s;
auto int n, chan;
if ((n = read(sockets[STDIN].descriptor, ps, BIGBUFSIZ)) > 0) {
ps += n;
*ps = 0;
switch (*s) {
case 'l' : print_msg(PRT_SHOWNUMBERS, "Recent caller's:\n");
addlist(-1, SETUP, 3);
break;
case 'h' : print_msg(PRT_SHOWNUMBERS, "\n\t*** s)tatus, l)ist, u)p, d)own ***\n");
break;
case 'u' : /* huptime(0, 0); */
break;
case 'd' : /* huptime(0, 0); */
break;
case 's' : now();
print_msg(PRT_SHOWNUMBERS, "\n\t*** %s\n", stl);
for (chan = 0; chan < MAXCHAN; chan++) {
if (call[chan].bchan == -1)
sprintf(s, "\t*** BCHAN#%d : FREE ***\n", chan + 1);
else {
sprintf(s, "\t*** BCHAN#%d : %d %s %s %s ***\n",
chan + 1,
call[chan].bchan,
call[chan].vnum[0],
call[chan].dialin ? "<-" : "->",
call[chan].vnum[1]);
} /* else */
print_msg(PRT_SHOWNUMBERS, "%s", s);
} /* for */
break;
} /* switch */
} /* if */
} /* morekbd */
/*****************************************************************************/
static void teardown(int chan)
{
auto char sx[BUFSIZ];
if (!Q931dmp)
logger(chan);
chanused[chan] = 0;
call[chan].disconnect = call[chan].connect;
call[chan].cause = 0x66; /* Recovery on timer expiry */
addlist(chan, SETUP, 2);
sprintf(sx, "HANGUP (Timeout)" /*, qmsg(TYPE_CAUSE, VERSION_EDSS1, call[chan].cause) */);
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
if (sound)
ringer(chan, RING_HANGUP);
clearchan(chan, 1);
} /* teardown */
/*****************************************************************************/
void processcint()
{
auto int chan, c;
auto char sx[BUFSIZ], s1[BUFSIZ], hints[BUFSIZ];
auto double dur;
for (chan = 0; chan < chans; chan++) {
dur = cur_time - call[chan].connect;
/* more than 50 seconds after SETUP nothing happen? */
if ((chanused[chan] == 1) && (dur > 50))
teardown(chan);
if (OUTGOING && call[chan].tarifknown) {
processRate(chan);
if (call[chan].ctakt != call[chan].Rate.Units) { /* naechste Einheit */
call[chan].ctakt = call[chan].Rate.Units;
sprintf(sx, "%d.CI %s (after %s) ",
call[chan].ctakt,
printRate(call[chan].pay),
double2clock(call[chan].Rate.Time));
info(chan, PRT_SHOWCONNECT, (call[chan].Rate.Duration < 30) ? STATE_BYTE : STATE_CONNECT, sx);
if ((c = call[chan].confentry[OTHER]) > -1) {
if (!replay && (chargemax != 0.0)) {
sprintf(s1, "CHARGEMAX remaining=%s %s %s",
printRate((chargemax - known[c]->charge - call[chan].pay)),
(connectmax == 0.0) ? "" : double2clock(connectmax - known[c]->online - dur),
(bytemax == 0.0) ? "" : double2byte((double)(bytemax - known[c]->bytes)));
info(chan, PRT_SHOWCHARGEMAX, STATE_AOCD, s1);
if (((known[c]->charge + call[chan].pay) >= chargemax) && (*known[c]->interface > '@'))
chargemaxAction(chan, (known[c]->charge + call[chan].pay - chargemax));
} /* if */
} /* if */
} /* if */
if (call[chan].cint != call[chan].Rate.Duration) { /* Taktwechsel */
char *h=hints;
call[chan].cint = call[chan].Rate.Duration;
snprintf(sx, BUFSIZ, "NEXT CI AFTER %s (%s)",
double2clock(call[chan].cint) + 3,
explainRate(&call[chan].Rate));
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, sx);
processLCR(chan, h);
while (h && *h)
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, strsep(&h,"\n"));
huptime(chan, 0);
} /* if */
} /* if */
} /* for */
} /* processcint */
/*****************************************************************************/
void lcd4linux(void)
{
static FILE *lcd = NULL;
if (lcdfile == NULL)
return;
if (lcd == NULL) {
int fd;
if ((fd = open(lcdfile, O_WRONLY | O_NDELAY)) == -1) {
print_msg(PRT_ERR, "lcd4linux: open(%s) failed: %s\n", lcdfile, strerror(errno));
lcdfile = NULL;
return;
} /* if */
if ((lcd = fdopen(fd, "w")) == NULL) {
print_msg (PRT_ERR, "lcd4linux: fdopen(%s) failed: %s\n", lcdfile, strerror(errno));
lcdfile = NULL;
return;
} /* if */
} /* if */
/* Fixme: do something useful here... */
} /* lcd4linux */