isdn4k-utils/isdnlog/isdnlog/processor.c

5133 lines
189 KiB
C
Raw Blame History

/* $Id: processor.c,v 1.31 1998/11/06 14:28:31 calle Exp $
*
* ISDN accounting for isdn4linux. (log-module)
*
* Copyright 1995, 1998 by Andreas Kool (akool@Kool.f.UUnet.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.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"
extern double cheap96(time_t when, int zone, int *zeit);
extern double taktlaenge(int chan, char *description);
static int HiSax = 0, hexSeen = 0, uid = -1;
static char *asnp, *asnm;
#ifdef Q931
static int lfd = 0;
#endif
#ifdef Q931
static void Q931dump(int mode, int val, char *msg, int version)
{
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 */
} /* Q931dump */
#endif
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 */
static void info(int chan, int reason, int state, char *msg)
{
auto char s[BUFSIZ], *left = "", *right = "\n";
static int lstate = 0, lchan = -1;
if (!newline) {
if (state == STATE_BYTE) {
right = "";
if (lstate == STATE_BYTE)
left = "\r";
else
left = "";
}
else {
right = "\n";
if (lstate == STATE_BYTE)
left = "\n";
else
left = "";
} /* else */
if ((lchan != chan) && (lstate == STATE_BYTE))
left = "\r\n";
lstate = state;
lchan = chan;
} /* if */
if (allflags & PRT_DEBUG_GENERAL)
if (allflags & PRT_DEBUG_INFO)
print_msg(PRT_DEBUG_INFO, "%d INFO> ", chan);
(void)iprintf(s, chan, call[chan].dialin ? ilabel : olabel, left, msg, right);
print_msg(PRT_DEBUG_INFO, "%s", s);
print_msg(reason, "%s", s);
if (xinfo) {
strcpy(call[chan].msg, msg);
call[chan].stat = state;
message_from_server(&(call[chan]), chan);
print_msg(PRT_DEBUG_CS, "SOCKET> %s: MSG_CALL_INFO chan=%d\n", st + 4, chan);
} /* if */
} /* info */
static void buildnumber(char *num, int oc3, int oc3a, char *result, int version, int *provider, int *sondernummer)
{
auto char n[BUFSIZ];
#ifdef Q931
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 */
#endif
strcpy(n, num);
strcpy(result, "");
#ifdef ISDN_DE
if (!memcmp(num, "010", 3)) { /* Provider */
char c = num[5];
num[5] = 0;
*provider = atoi(num + 3);
num[5] = c;
num += 5;
#ifdef Q931
if (q931dmp) {
auto char s[BUFSIZ];
sprintf(s, "Via provider \"010%02d\", %s", *provider, Providername(*provider));
Q931dump(TYPE_STRING, -1, s, version);
} /* if */
#endif
} /* if */
#endif
if ((*sondernummer = is_sondernummer(num)) == -1)
switch (oc3 & 0x70) { /* Calling party number Information element, Octet 3 - Table 4-11/Q.931 */
case 0x00 : if (*num) { /* 000 Unknown */
char *amt = amtsholung;
while (amt && *amt) {
int len = strchr(amt, ':') ? strchr(amt, ':') - amt : strlen(amt);
if (len && !strncmp(num, amt, len)) {
num += len;
#ifdef Q931
if (q931dmp) {
auto char s[BUFSIZ], s1[BUFSIZ];
strncpy(s1, amt, len);
sprintf(s, "Amtsholung: %s", s1);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
#endif
break;
} /* if */
amt += len + (strchr(amt, ':') ? 1 : 0);
} /* while */
if (*num != '0')
sprintf(result, "%s%s", mycountry, myarea);
else {
if (num[1] != '0') /* Falls es doch Ausland ist -> nichts machen!!! */
strcpy(result, mycountry);
else
strcpy(result, countryprefix);
while (*num && (*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 */
if (interns0)
while (*num == '0')
num++;
} /* if */
break;
case 0x30 : break; /* 011 Network specific number */
case 0x40 : if (*num != '0') /* 100 Subscriber number */
sprintf(result, "%s%s", mycountry, myarea);
else {
strcpy(result, mycountry);
while (*num && (*num == '0'))
num++;
} /* else */
break;
case 0x60 : break; /* 110 Abbreviated number */
case 0x70 : break; /* 111 Reserved for extension */
} /* switch */
strcat(result, num);
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s: num=\"%s\", oc3=%s(%02x), result=\"%s\"\n",
st + 4, n, i2a(oc3, 8, 2), oc3 & 0x70, result);
} /* buildnumber */
static void aoc_debug(int val, char *s)
{
print_msg(PRT_DEBUG_DECODE, " DEBUG> %s: %s\n", st + 4, s);
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_STRING, val, s, VERSION_EDSS1);
#endif
} /* aoc_debug */
/*
currency_mode := AOC_UNITS | AOC_AMOUNT
currency_factor :=
currency := " DM" | "SCHILLING" | "NLG" | "FR."
*/
static int facility(int type, int l)
{
register int ls, i, ServedUserNr;
register char *px, *px1, *px2, *px3;
auto int c, result = 0, a1, a2, oc3 = 0;
static int ID = 0, OP = 0, EH = 0, MP = 0;
static char curr[64];
auto char s[BUFSIZ], s1[BUFSIZ], dst[BUFSIZ], src[BUFSIZ];
auto char vdst[BUFSIZ], vsrc[BUFSIZ];
switch(type) {
case AOC_INITIAL : ID = OP = EH = MP = 0;
if (asnp == NULL)
return(AOC_OTHER);
c = strtol(asnp += 3, NIL, 16); /* Ext/Spare/Profile */
switch (c) { /* Remote Operation Protocol */
case 0x91 : aoc_debug(c, "Remote Operation Protocol"); 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 */
c = strtol(asnp += 3, NIL, 16); /* Invoke Comp type */
switch (c) {
case 0xa1 : aoc_debug(c, "InvokeComponent"); break;
case 0xa2 : aoc_debug(c, "ReturnResultComponent"); break;
case 0xa3 : aoc_debug(c, "ReturnErrorComponent"); break;
case 0xa4 : aoc_debug(c, "RejectComponent"); break;
default : aoc_debug(c, "UNKNOWN Component");
return(AOC_OTHER);
} /* switch */
l = strtol(asnp += 3, NIL, 16); /* Invoke Comp length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
c = strtol(asnp += 3, NIL, 16); /* Invoke ID type */
sprintf(s, "InvokeIdentifier Type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* Invoke ID length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
while (l--) {
ID = ID << 8;
c = strtol(asnp += 3, NIL, 16); /* Invoke ID Contents */
sprintf(s, "InvokeIdentifier Contents=%d", c);
aoc_debug(c, s);
ID += c;
} /* while */
c = strtol(asnp += 3, NIL, 16); /* OPERATION type */
if (!c)
return(AOC_OTHER);
sprintf(s, "OperationType=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* OPERATION length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
while (l--) {
OP = OP << 8;
OP += strtol(asnp += 3, NIL, 16); /* OPERATION contents */
} /* while */
switch (OP) {
case 0x01 : asnm = "uUsa"; break;
case 0x02 : asnm = "cUGCall"; break;
case 0x03 : asnm = "mCIDRequest"; break;
case 0x04 : asnm = "beginTPY"; break;
case 0x05 : asnm = "endTPY"; break;
case 0x07 : asnm = "activationDiversion"; break;
case 0x08 : asnm = "deactivationDiversion"; break;
case 0x09 : asnm = "activationStatusNotificationDiv"; break;
case 0x0a : asnm = "deactivationStatusNotificationDiv"; break;
case 0x0b : asnm = "interrogationDiversion"; break;
case 0x0c : asnm = "diversionInformation"; break;
case 0x0d : asnm = "callDeflection"; break;
case 0x0e : asnm = "callRerouting"; break;
case 0x0f : asnm = "divertingLegInformation2"; break;
case 0x10 : asnm = "invokeStatus"; break;
case 0x11 : asnm = "interrogationDiversion1"; break;
case 0x12 : asnm = "divertingLegInformation1"; break;
case 0x13 : asnm = "divertingLegInformation3"; break;
case 0x14 : asnm = "explicitReservationCreationControl"; break;
case 0x15 : asnm = "explicitReservationManagement"; break;
case 0x16 : asnm = "explicitReservationCancel"; break;
case 0x18 : asnm = "mLPP lfb Query"; break;
case 0x19 : asnm = "mLPP Call Request"; break;
case 0x1a : asnm = "mLPP Call preemption"; break;
case 0x1e : asnm = "chargingRequest"; break;
case 0x1f : asnm = "aOCSCurrency"; break;
case 0x20 : asnm = "aOCSSpecialArrangement"; break;
case 0x21 : asnm = "aOCDCurrency"; break;
case 0x22 : asnm = "aOCDChargingUnit"; break;
case 0x23 : asnm = "aOCECurrency"; break;
case 0x24 : asnm = "aOCEChargingUnit"; break;
case 0x25 : asnm = "identificationOfChange"; break;
case 0x28 : asnm = "beginConf"; break;
case 0x29 : asnm = "addConf"; break;
case 0x2a : asnm = "splitConf"; break;
case 0x2b : asnm = "dropConf"; break;
case 0x2c : asnm = "IsolateConf"; break;
case 0x2d : asnm = "reattachConf"; break;
case 0x2e : asnm = "partyDISC"; break;
case 0x2f : asnm = "floatConf"; break;
case 0x30 : asnm = "endConf"; break;
case 0x31 : asnm = "identifyConferee"; break;
case 0x3c : asnm = "requestREV"; break;
} /* switch */
px = s + sprintf(s, "OperationContents : %s", asnm);
aoc_debug(OP, s);
switch (OP) {
case 0x09 : /* activationStatusNotificationDiv (Rufumleitung an) */
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "SEQUENCE=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "Enumeration type procedure=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
switch (c = strtol(asnp += 3, NIL, 16)) {
case 0x00 : px1 = "CFU"; break; /* Rufumleitung unbedingt */
case 0x01 : px1 = "CFB"; break; /* Rufumleitung bei Besetzt */
case 0x02 : px1 = "CFNR"; break; /* Rufumleitung wenn niemand h<>rt */
default : px1 = "CF?"; break; /* UNKNOWN Rufumleitung */
} /* switch */
aoc_debug(c, px1);
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "Enumeration type BasicService=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
switch (c = strtol(asnp += 3, NIL, 16)) {
case 0x00 : px2 = "all Services"; break;
case 0x01 : px2 = "Speech"; break;
case 0x02 : px2 = "unrestricted Digital Information"; break;
case 0x03 : px2 = "3.1 kHz audio"; break;
case 0x20 : px2 = "Telephony"; break;
case 0x21 : px2 = "Teletex"; break;
case 0x22 : px2 = "Telefax G4"; break;
case 0x23 : px2 = "Videotex Syntax Based"; break;
case 0x24 : px2 = "Videotelephony"; break;
default : px2 = "UNKNOWN BasicService"; break;
} /* switch */
aoc_debug(c, px2);
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "SEQUENCE, Address (Zieladresse)=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
switch (c = strtol(asnp += 3, NIL, 16)) {
case 0x80 : l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
px3 = "UNKNOWN PublicTypeOfNumber";
break;
case 0xa1 : l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "Aufzaehlungstyp, PublicTypeOfNumber=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
switch (oc3 = strtol(asnp += 3, NIL, 16)) {
case 0x00 : px3 = "Unknown Number"; break;
case 0x01 : px3 = "International Number"; break;
case 0x02 : px3 = "National Number"; break;
case 0x03 : px3 = "Network Spezific Number"; break;
case 0x04 : px3 = "Subscriber Number"; break;
case 0x05 : px3 = "abbreviated Number"; break;
default : px3 = "UNKNOWN PublicTypeOfNumber"; break;
} /* switch */
aoc_debug(oc3, px3);
break;
default : px3 = "UNKNOWN PublicTypeOfNumber";
break;
} /* switch */
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
ls = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", ls);
aoc_debug(ls, s);
l--;
px = dst;
while (ls--) {
*px++ = strtol(asnp += 3, NIL, 16);
l--;
} /* while */
*px = 0;
sprintf(s1, "\"%s\"", dst);
aoc_debug(-2, s1);
px = s;
c = strtol(asnp += 3, NIL, 16);
sprintf(px, "%02x ", c);
aoc_debug(-4, s);
for (i = 0; i < 5; i++) {
c = strtol(asnp += 3, NIL, 16);
sprintf(px, "%02x ", c);
aoc_debug(-4, s);
} /* for */
ls = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", ls);
aoc_debug(l, s);
l--;
px = src;
while (ls--) {
*px++ = strtol(asnp += 3, NIL, 16);
l--;
} /* while */
*px = 0;
sprintf(s1, "\"%s\"", src);
aoc_debug(-2, s1);
buildnumber(src, 0, 0, call[6].num[CLIP], VERSION_EDSS1, &a1, &a2);
strcpy(vsrc, vnum(6, CLIP));
buildnumber(dst, oc3 * 16, 0, call[6].num[CLIP], VERSION_EDSS1, &a1, &a2);
strcpy(vdst, vnum(6, CLIP));
/* sprintf(s, "%s %s/%s -> %s (%s)", px1, src, px2, dst, px3); */
sprintf(s, "%s %s/%s -> %s", px1, vsrc, px2, vdst);
aoc_debug(-2, s);
(void)iprintf(s1, -1, mlabel, "", s, "\n");
print_msg(PRT_SHOWNUMBERS, "%s", s1);
return(AOC_OTHER);
break;
case 0x08 : /* deactivationDiversion */
case 0x0a : /* deactivationStatusNotificationDiv (Rufumleitung aus) */
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "SEQUENCE=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "Enumeration type procedure=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
switch (c = strtol(asnp += 3, NIL, 16)) {
case 0x00 : px1 = "CFU"; break; /* Rufumleitung unbedingt */
case 0x01 : px1 = "CFB"; break; /* Rufumleitung bei Besetzt */
case 0x02 : px1 = "CFNR"; break; /* Rufumleitung wenn niemand h<>rt */
default : px1 = "CF?"; break; /* UNKNOWN Rufumleitung */
} /* switch */
aoc_debug(c, px1);
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "Enumeration type BasicService=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
switch (c = strtol(asnp += 3, NIL, 16)) {
case 0x00 : px2 = "all Services"; break;
case 0x01 : px2 = "Speech"; break;
case 0x02 : px2 = "unrestricted Digital Information"; break;
case 0x03 : px2 = "3.1 kHz audio"; break;
case 0x20 : px2 = "Telephony"; break;
case 0x21 : px2 = "Teletex"; break;
case 0x22 : px2 = "Telefax G4"; break;
case 0x23 : px2 = "Videotex Syntax Based"; break;
case 0x24 : px2 = "Videotelephony"; break;
default : px2 = "UNKNOWN BasicService"; break;
} /* switch */
aoc_debug(c, px2);
ServedUserNr = strtol(asnp += 3, NIL, 16);
sprintf(s, "ServedUserNr=%d", ServedUserNr);
aoc_debug(c, s);
if (ServedUserNr == 161)
for (i = 0; i < 5; i++) {
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "%02x ", l);
aoc_debug(-4, s);
} /* for */
l = strtol(asnp += 3, NIL, 16);
sprintf(s, "length=%d", l);
aoc_debug(l, s);
px = dst;
while (l--)
*px++ = strtol(asnp += 3, NIL, 16);
*px = 0;
sprintf(s1, "\"%s\"", dst);
aoc_debug(-2, s1);
buildnumber(dst, 0, 0, call[6].num[CLIP], VERSION_EDSS1, &a1, &a2);
strcpy(vdst, vnum(6, CLIP));
sprintf(s, "deactivate %s %s/%s", px1, vdst, px2);
(void)iprintf(s1, -1, mlabel, "", s, "\n");
print_msg(PRT_SHOWNUMBERS, "%s", s1);
return(AOC_OTHER);
break;
case 0x21 : (void)facility(AOCDCurrency, l);
result = -EH;
break;
case 0x22 : (void)facility(AOCDChargingUnit, l);
result = -EH;
break;
case 0x23 : (void)facility(AOCECurrency, l);
result = EH;
break;
case 0x24 : (void)facility(AOCEChargingUnit, l);
result = EH;
break;
default : sprintf(s, "UNKNOWN OperationContents=%d", OP);
aoc_debug(OP, s);
return(AOC_OTHER);
break;
} /* switch OP */
break;
case AOCDCurrency : (void)facility(AOCDCurrencyInfo, l);
break;
case AOCDChargingUnit : (void)facility(AOCDChargingUnitInfo, l);
break;
case AOCECurrency : (void)facility(AOCECurrencyInfo, l);
break;
case AOCEChargingUnit : (void)facility(AOCEChargingUnitInfo, l);
break;
case AOCDChargingUnitInfo : c = strtol(asnp += 3, NIL, 16); /* specificChargingUnits SEQUENCE type / NULL */
sprintf(s, "Sequence, specificChargingUnits type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* specificChargingUnits SEQUENCE length / NULL */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
if (!l) /* freeOfCharge */
break;
(void)facility(RecordedUnitsList, l);
(void)facility(TypeOfChargingInfo, l);
/*
(void)facility(AOCDBillingId, l);
*/
break;
case AOCEChargingUnitInfo : c = strtol(asnp += 3, NIL, 16); /* SEQUENCE type */
aoc_debug(c, "AOCEChargingUnitInfo");
sprintf(s, "SEQUENCE type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* SEQUENCE length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
c = strtol(asnp += 3, NIL, 16); /* specificChargingUnits SEQUENCE type / NULL */
sprintf(s, "specificChargingUnits SEQUENCE type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* specificChargingUnits SEQUENCE length / NULL */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
if (!l) /* freeOfCharge */
break;
(void)facility(RecordedUnitsList, l);
(void)facility(TypeOfChargingInfo, l);
/*
(void)facility(AOCDBillingId, l);
*/
break;
case AOCDCurrencyInfo : c = strtol(asnp += 3, NIL, 16); /* specificCurrency SEQUENCE type / NULL */
aoc_debug(c, "AOCDCurrencyInfo");
sprintf(s, "specificCurrency SEQUENCE type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* specificCurrency SEQUENCE length / NULL */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
if (!l) /* freeOfCharge */
break;
c = strtol(asnp += 3, NIL, 16); /* SEQUENCE type */
sprintf(s, "SEQUENCE type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* SEQUENCE length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
(void)facility(RecordedCurrency, l);
(void)facility(TypeOfChargingInfo, l);
/*
(void)facility(AOCDBillingId, l);
*/
break;
case AOCECurrencyInfo : c = strtol(asnp += 3, NIL, 16); /* SEQUENCE type */
aoc_debug(c, "AOCECurrencyInfo");
sprintf(s, "SEQUENCE type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* SEQUENCE length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
c = strtol(asnp += 3, NIL, 16); /* specificCurrency SEQUENCE type / NULL */
sprintf(s, "specificCurrency SEQUENCE type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* specificCurrency SEQUENCE length / NULL */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
if (!l) /* freeOfCharge */
break;
c = strtol(asnp += 3, NIL, 16); /* SEQUENCE type */
sprintf(s, "SEQUENCE type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* SEQUENCE length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
(void)facility(RecordedCurrency, l);
/*
(void)facility(AOCDBillingId, l);
(void)facility(ChargingAssociation, l);
*/
break;
case RecordedCurrency : c = strtol(asnp += 3, NIL, 16); /* IA5String type */
aoc_debug(c, "RecordedCurrency");
sprintf(s, "IA5String type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* IA5String length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
(void)facility(Currency, l);
c = strtol(asnp += 3, NIL, 16); /* SEQUENCE type */
sprintf(s, "SEQUENCE type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* SEQUENCE length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
(void)facility(Amount, l);
break;
case Currency : aoc_debug(-1, "Currency");
c = 0;
while (l--)
curr[c++] = strtol(asnp += 3, NIL, 16);
curr[c] = 0;
currency = curr;
sprintf(s, "\"%s\"", currency);
aoc_debug(-2, s);
break;
case Amount : c = strtol(asnp += 3, NIL, 16); /* INTEGER type */
aoc_debug(c, "Amount");
sprintf(s, "INTEGER type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* INTEGER length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
(void)facility(CurrencyAmount, l);
c = strtol(asnp += 3, NIL, 16); /* ENUMERATED type */
sprintf(s, "ENUMERATED type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* ENUMERATED length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
(void)facility(Multiplier, l);
break;
case CurrencyAmount : aoc_debug(-1, "CurrencyAmount");
while (l--) {
EH = EH << 8;
EH += strtol(asnp += 3, NIL, 16); /* Amount */
} /* while */
currency_mode = AOC_AMOUNT;
sprintf(s, "%d", EH);
aoc_debug(-2, s);
break;
case Multiplier : aoc_debug(-1, "Multiplier");
while (l--) {
MP = MP << 8;
MP += strtol(asnp += 3, NIL, 16); /* Multiplier */
} /* while */
switch (MP) {
case 0 : currency_factor = 0.001;
break;
case 1 : currency_factor = 0.01;
break;
case 2 : currency_factor = 0.1;
break;
case 3 : currency_factor = 1.0;
break;
case 4 : currency_factor = 10.0;
break;
case 5 : currency_factor = 100.0;
break;
case 6 : currency_factor = 1000.0;
break;
} /* switch */
sprintf(s, "%g", currency_factor);
aoc_debug(-2, s);
break;
case RecordedUnitsList : c = strtol(asnp += 3, NIL, 16); /* SEQUENCE SIZE type */
sprintf(s, "RecordedUnitsList=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* SEQUENCE SIZE length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
(void)facility(RecordedUnits, l);
break;
case RecordedUnits : c = strtol(asnp += 3, NIL, 16); /* SEQUENCE type */
sprintf(s, "Sequence Size(1..32) Of RecordedUnits=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* SEQUENCE length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
if (!l) /* notAvailable */
break;
(void)facility(NumberOfUnits, l);
break;
case NumberOfUnits : c = strtol(asnp += 3, NIL, 16); /* INTEGER type */
sprintf(s, "NumberOfUnits type=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* INTEGER length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
while (l--) {
EH = EH << 8;
EH += strtol(asnp += 3, NIL, 16); /* NumberOfUnits */
} /* while */
currency_mode = AOC_UNITS;
sprintf(s, "NumberOfUnits=%d", EH);
aoc_debug(EH, s);
break;
case TypeOfChargingInfo : c = strtol(asnp += 3, NIL, 16); /* typeOfChargingInfo type */
sprintf(s, "typeOfChargingInfo=%d", c);
aoc_debug(c, s);
l = strtol(asnp += 3, NIL, 16); /* typeOfChargingInfo length */
sprintf(s, "length=%d", l);
aoc_debug(l, s);
c = strtol(asnp += 3, NIL, 16); /* typeOfChargingInfo contents */
sprintf(s, "typeOfChargingInfo contents=%d", c);
aoc_debug(c, s);
break;
} /* switch */
return(result);
} /* facility */
/* gcc 2.7.2.1 Optimizer-Bug workaround from Stefan Gruendel <sgruendel@adulo.de> */
static int facility_start(char *p, int type, int l)
{
asnp = p;
return(facility(type, l));
} /* facility_start */
static int AOC_1TR6(int l, char *p)
{
auto int EH = 0;
auto int digit = 0;
#if 0
static char curr[64];
#endif
#ifdef ISDN_NL
/*
* 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)
/*
* "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, 2, DEB),
known[c]->who,
double2str(known[c]->scharge, 6, 2, 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)
{
register char *pd, *px, *py;
register int i, element, l, l1, c, oc3, oc3a, n, sxp = 0, warn;
auto int zeit, 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, pay = 0.0;
while (1) {
if (!*(p + 2))
break;
element = strtol(p += 3, NIL, 16);
if (element < 128) {
l = strtol(p += 3, NIL, 16);
#ifdef Q931
if (q931dmp) {
auto char s[BUFSIZ];
Q931dump(TYPE_ELEMENT, element, NULL, version);
sprintf(s, "length=%d", l);
Q931dump(TYPE_STRING, l, s, version);
} /* if */
#endif
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);
#ifdef Q931
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: ");
switch (c & 0x0f) {
case 0x00 : sprintf(ps, "Nutzer"); break;
case 0x01 : sprintf(ps, "Privates Netz des Nutzers"); break;
case 0x02 : sprintf(ps, "Oeffentliches Netz des Nutzers"); break;
case 0x03 : sprintf(ps, "Transitnetz"); break;
case 0x04 : sprintf(ps, "Oeffentliches Netz beim fernen Nutzer"); break;
case 0x05 : sprintf(ps, "Privates Netz beim fernen Nutzer"); break;
case 0x07 : sprintf(ps, "Internationales Netz"); break;
case 0x0a : sprintf(ps, "Netzwerk jenseits des interworking point"); break;
default : sprintf(ps, "UNKNOWN #%d", c & 0x0f); break;
} /* switch */
Q931dump(TYPE_STRING, -1, s, version);
} /* if */
#endif
switch ((loc = (c & 0x0f))) {
case 0x00 : py = "User"; break;
case 0x01 : py = "Private network serving local user"; break;
case 0x02 : py = "Public network serving local user"; break;
case 0x03 : py = "Transit network"; break;
case 0x04 : py = "Public network serving remote user"; break;
case 0x05 : py = "Private network serving remote user"; break;
case 0x07 : py = "International network"; break;
case 0x0a : py = "Network beyond inter-working point"; break;
default : py = ""; break;
} /* switch */
c = strtol(p + 6, NIL, 16);
cause = c & 0x7f;
/* 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" */
#if 0
auto char sx[200];
if ((call[chan].cause != -1) && (call[chan].cause != cause)) {
sprintf(sx, "USING cause %d:%s (%s),\nOVERWRITING cause %d:%s (%s)",
cause, qmsg(TYPE_CAUSE, version, cause), location(loc),
call[chan].cause, qmsg(TYPE_CAUSE, version, call[chan].cause), location(call[chan].loc));
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
} /* if */
#endif
call[chan].cause = cause;
call[chan].loc = loc;
}
#if 0
else {
auto char sx[200];
sprintf(sx, "IGNORING cause %d:%s (%s),\nLEAVING cause %d:%s (%s)",
cause, qmsg(TYPE_CAUSE, version, cause), location(loc),
call[chan].cause, qmsg(TYPE_CAUSE, version, call[chan].cause), location(call[chan].loc));
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
} /* else */
#endif
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_CAUSE, c, NULL, version);
#endif
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);
info(chan, PRT_SHOWCAUSE, STATE_CAUSE, s);
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;
#ifdef ISDN_DE
case 0x28 : /* DISPLAY ... z.b. Makelweg, AOC-E ... */
#ifdef Q931
if (q931dmp) {
auto char s[BUFSIZ];
register char *ps = s;
while (l--)
*ps++ = strtol(p += 3, NIL, 16);
*ps = 0;
Q931dump(TYPE_STRING, -2, s, version);
}
else
#endif
p += (l * 3);
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)
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)
n = AOC_1TR6(l, p);
#else
n = facility_start(p, AOC_INITIAL, 0);
#endif
if (n == AOC_OTHER)
; /* info(chan, PRT_SHOWAOCD, STATE_AOCD, asnm); */
#if 0
else if (!memcmp(call[chan].provider, "01019", 5) ||
!memcmp(call[chan].provider, "01070", 5)) {
if (type != FACILITY) { /* "AOC-E" Meldung */
if (!memcmp(call[chan].provider, "01019", 5)) { /* Mobilcom */
tx = cur_time - call[chan].connect;
call[chan].aoce = (int)((tx + 59) / 60);
call[chan].pay = call[chan].aoce * 0.19;
if (tx)
sprintf(s, "%s %s (%s)",
currency,
double2str(call[chan].pay, 6, 2, DEB),
double2clock(tx));
else
sprintf(s, "%s %s",
currency,
double2str(call[chan].pay, 6, 2, DEB));
info(chan, PRT_SHOWAOCD, STATE_AOCD, s);
} /* if */
} /* if */
}
#endif
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 (n) {
pay = abs(n) * currency_factor;
sprintf(s, "%d * %g = %g%s", abs(n), currency_factor, pay, currency);
aoc_debug(-2, s);
} /* if */
if (n < 0)
call[chan].aoce++;
call[chan].pay = pay;
call[chan].aoce = n; /* AK:08-May-98 */
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)
info(chan, PRT_SHOWAOCD, STATE_AOCD, "Free of charge");
else if (n < 0) {
tx = cur_time - call[chan].connect;
if ((c = call[chan].confentry[OTHER]) > -1) {
/* tack = cheap96(cur_time, known[c]->zone, &zeit); */
tack = taktlaenge (chan, NULL);
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].pay, 6, 2, 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].pay, 6, 2, DEB),
double2clock(tx));
else
sprintf(s, "%d.EH %s %s",
abs(call[chan].aoce),
currency,
double2str(call[chan].pay, 6, 2, DEB));
} /* else */
if (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 = known[c]->rcharge = 0.0;
known[c]->day = day;
} /* if */
known[c]->charge += (pay / call[chan].aoce);
known[c]->rcharge += (pay / call[chan].aoce);
sprintf(s1, "CHARGEMAX remaining=%s %s %s %s",
currency,
double2str((chargemax - known[c]->charge), 6, 2, DEB),
(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 >= chargemax) && (*known[c]->interface > '@'))
chargemaxAction(chan, (known[c]->charge - chargemax));
} /* if */
if (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 */
}
else if (-n > 1) { /* try to guess Gebuehrenzone */
#ifdef ISDN_AT
px="";
err=60*60*24*365; /* sehr gross */
for (c = 1; c < 31; c++) {
call[chan].zone=c;
tack = (-n-1) * taktlaenge (chan, NULL);
if ((tack > 0) && (abs(tack - tx)<err)) {
call[chan].tick = tack;
err = abs(tack) - tx;
px = z2s(c);
}
}
call[chan].zone=-1;
#else
tack = 0;
err = 0;
px = "";
for (c = 4; c > 0; c--) {
call[chan].tick = 0;
for (i = 0; i < -n - 1; i++) {
tack = cheap96(cur_time, c, &zeit);
call[chan].tick += tack;
} /* for */
err = call[chan].tick - tx;
if (err >= 0) {
switch (c) {
case 4 : px = "Fern"; break;
case 3 : px = "Regio 200"; break;
case 2 : px = "Regio 50"; break;
case 1 : px = "City"; break;
} /* switch */
break;
} /* if */
} /* for */
#endif
if (message & PRT_SHOWTICKS)
sprintf(s, "%d.EH %s %s (%s %d %s?) C=%s",
abs(call[chan].aoce),
currency,
double2str(call[chan].pay, 6, 2, 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].pay, 6, 2, DEB),
double2clock(tx));
else
sprintf(s, "%d.EH %s %s",
abs(call[chan].aoce),
currency,
double2str(call[chan].pay, 6, 2, DEB));
} /* else */
}
else {
sprintf(s, "%d.EH %s %s",
abs(call[chan].aoce),
currency,
double2str(call[chan].pay, 6, 2, DEB));
} /* else */
info(chan, PRT_SHOWAOCD, STATE_AOCD, s);
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 (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 */
}
else { /* AOC-E */
if ((c = call[chan].confentry[OTHER]) > -1) {
known[c]->charge -= known[c]->rcharge;
known[c]->charge += pay;
if (chargemax != 0.0) { /* only used here if no AOC-D */
if (day != known[c]->day) {
sprintf(s, "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, s);
known[c]->scharge += known[c]->charge;
known[c]->charge = 0.0;
known[c]->day = day;
} /* if */
} /* if */
if (connectmax != 0.0) { /* only used here if no AOC-D */
if (month != known[c]->month) {
sprintf(s, "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, s);
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 */
} /* else */
} /* 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;
#ifdef Q931
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 */
#endif
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 (dual && !*s)
strcpy(s, call[chan].onum[CALLED]);
else
strcpy(call[chan].onum[CALLED], s);
buildnumber(s, oc3, oc3a, call[chan].num[CALLED], version, &call[chan].provider, &call[chan].sondernummer);
if (!dual)
strcpy(call[chan].vnum[CALLED], vnum(chan, CALLED));
#ifdef Q931
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 */
#endif
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 ((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);
strcpy(call[chan].vnum[CLIP], vnum(6, CLIP));
#ifdef Q931
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 */
#endif
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 */
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);
strcpy(call[chan].vnum[CALLING], vnum(chan, CALLING));
#ifdef Q931
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 */
#endif
/* Fixme: what is short for 'Calling Party Number'? */
sprintf(s1, "CPN %s", call[chan].num[CALLING]);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s1);
if (callfile && call[chan].dialin) {
FILE *cl = fopen (callfile, "a");
if (cl != NULL) {
iprintf (s1, chan, callfmt);
fprintf (cl, "%s\n", s1);
fclose (cl);
}
}
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)) { /* Digit's beim waehlen mit ISDN-Telefon */
strcat(call[chan].digits, s);
call[chan].oc3 = oc3;
#ifdef Q931
if (q931dmp)
buildnumber(s, oc3, -1, call[chan].num[CALLED], version, &call[chan].provider, &call[chan].sondernummer);
#endif
buildnumber(call[chan].digits, oc3, -1, call[chan].num[CALLED], version, &call[chan].provider, &call[chan].sondernummer);
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);
strcpy(call[chan].vnum[CALLED], vnum(chan, CALLED));
#ifdef Q931
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 */
#endif
if ((c = call[chan].confentry[OTHER]) > -1)
known[c]->rcharge = 0.0;
/* 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, "********************");
} /* 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);
strcpy(call[chan].vnum[REDIR], vnum(chan, REDIR));
#ifdef Q931
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 */
#endif
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;
#ifdef Q931
if (!q931dmp)
#endif
px += sprintf(px, "RING (");
px += sprintf(px, "%s", qmsg(TYPE_SERVICE, version, call[chan].bearer));
#ifdef Q931
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 */
#endif
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;
#ifdef Q931
if (!q931dmp)
#endif
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++)
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_STRING, sn[c], sx[c], version);
else
#endif
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;
#ifdef Q931
if (!q931dmp)
#endif
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 */
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_STRING, sn[0], sx[0], version);
else
#endif
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;
#ifdef Q931
if (!q931dmp)
#endif
px += sprintf(px, "PROGRESS: ");
switch (c) {
case 0x80 : px += sprintf(px, "Location: User"); break;
case 0x81 : px += sprintf(px, "Location: Local:private net"); break;
case 0x82 : px += sprintf(px, "Location: Local:public net"); break;
case 0x84 : px += sprintf(px, "Location: Remote:public net"); break;
case 0x85 : px += sprintf(px, "Location: Remote:private net"); break;
case 0x8a : px += sprintf(px, "Location: Interworking"); break;
} /* switch */
if (l > 1) {
px = sx[++sxp];
*px = 0;
#ifdef Q931
if (!q931dmp)
#endif
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++)
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_STRING, sn[c], sx[c], version);
else
#endif
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;
#ifdef Q931
if (!q931dmp)
#endif
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 */
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_STRING, sn[0], sx[0], version);
else
#endif
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;
#ifdef Q931
if (!q931dmp)
#endif
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 */
px = sx[++sxp];
*px = 0;
#ifdef Q931
if (!q931dmp)
#endif
px += sprintf(px, "HLC: ");
c = strtol(p + 6, NIL, 16);
sn[sxp] = c;
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)) {
px = sx[++sxp];
*px = 0;
#ifdef Q931
if (!q931dmp)
#endif
px += sprintf(px, "HLC: ");
c = strtol(p + 9, NIL, 16);
sn[sxp] = c;
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++)
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_STRING, sn[c], sx[c], version);
else
#endif
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);
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_STRING, -4, s, version);
#endif
} /* if */
p += (l * 3);
break;
} /* switch */
}
#ifdef Q931
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 */
#endif
} /* 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 bchan, 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], n[1024], n1[1024];
auto union p {
isdn_net_ioctl_phone phone;
char n[1024];
} ph;
if (hupctrl && (c > -1) && (*known[c]->interface > '@') && expensive(bchan)) {
memset(&cfg, 0, sizeof(cfg)); /* clear in case of older kernel */
strcpy(cfg.name, known[c]->interface);
if (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 0 /* and now for the magic least-cost-routing part ... */
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, "010", 3) {
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, "01019%s", 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) {
sprintf(sx, "HUPTIMEOUT %s is *disabled* - unchanged", known[c]->interface);
info(chan, PRT_SHOWNUMBERS, STATE_HUPTIMEOUT, sx);
return;
} /* if */
newchargeint = taktlaenge(chan, why);
#ifdef ISDN_DE
if (call[chan].provider == 19) { /* Mobilcom 60/60 Takt */
newchargeint = 60;
sprintf(why, "via %s", Providername(call[chan].provider));
}
else if (call[chan].provider == 24) { /* TelePasswort 1s Takt */
newchargeint = 1;
sprintf(why, "via %s", Providername(call[chan].provider));
}
else if (call[chan].provider == 70) { /* Arcor 1s Takt */
newchargeint = 1;
sprintf(why, "via %s", Providername(call[chan].provider));
}
else if (call[chan].provider == 30) { /* TelDaFax 1s Takt */
newchargeint = 1;
sprintf(why, "via %s", Providername(call[chan].provider));
}
else if (call[chan].provider == 13) { /* Tele 2 1s Takt */
newchargeint = 1;
sprintf(why, "via %s", Providername(call[chan].provider));
}
else if (call[chan].provider == 24) { /* TelePassport 1/1 Takt */
newchargeint = 1;
sprintf(why, "via %s", Providername(call[chan].provider));
} /* else */
#endif
#if NET_DV >= NETDV_CHARGEINT
if (net_dv >= NETDV_CHARGEINT) {
if (hup1 && hup2)
newhuptimeout = (newchargeint < 20) ? hup1 : hup2;
else
newhuptimeout = oldhuptimeout;
}
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) {
#if NET_DV >= NETDV_CHARGEINT
if (net_dv >= NETDV_CHARGEINT)
call[chan].chargeint = cfg.chargeint = newchargeint;
#endif
call[chan].huptimeout = cfg.onhtime = newhuptimeout;
if (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETSCF, &cfg) >= 0) {
sprintf(sx, "CHARGEINT %s %d (was %d) - %s",
known[c]->interface, newchargeint, oldchargeint, 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", known[c]->interface,
oldchargeint, 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: \"telesctrl %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 \"telesctrl %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];
auto time_t DiffTime = (time_t)0;
auto int hup = 0, eh = 0;
#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 (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);
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);
} /* 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;
#ifdef Q931
if (!q931dmp) {
#endif
print_msg(PRT_NORMAL, "(ISDN subsystem with ISDN_MAX_CHANNELS > 16 detected - %d active channels, %d MSN/SI entries)\n", chans, mymsns);
if (dual)
print_msg(PRT_NORMAL, "(watching \"%s\" and \"%s\")\n", isdnctrl, isdnctrl2);
#ifdef Q931
} /* if */
#endif
/*
* 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 */
huptime(chan, j, 1); /* bei Verbindungsbeginn HANGUP-Timer neu setzen */
} /* 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)
{
if (total) {
memset((char *)&call[chan], 0, sizeof(CALL));
call[chan].tei = BROADCAST;
}
else
*call[chan].onum[0] =
*call[chan].onum[1] =
*call[chan].num[0] =
*call[chan].num[1] = 0;
strcpy(call[chan].vnum[0], "?");
strcpy(call[chan].vnum[1], "?");
call[chan].confentry[0] = call[chan].confentry[1] = -1;
call[chan].bchan = -1;
call[chan].cause = -1;
call[chan].loc = -1;
call[chan].aoce = -1;
call[chan].provider = -1;
call[chan].sondernummer = -1;
} /* clearchan */
static void how_expensive(int chan)
{
register int c, zone = -1, zone2 = -1, pro = -1, pro2 = -1;
auto int dur = (int)(call[chan].disconnect - call[chan].connect);
auto double pay2 = -1.0, pay3, onesec, cheap;
auto char sx[BUFSIZ];
extern double pay(time_t ts, int dauer, int tarifz, int pro);
auto struct tm *tm;
if (!call[chan].dialin && (dur > 0) && *call[chan].num[1]) {
tm = localtime(&call[chan].connect);
if (call[chan].sondernummer != -1) {
switch (SN[call[chan].sondernummer].tarif) {
case -1 :
#ifdef ISDN_DE
if (!strcmp(call[chan].num[1] + 3, "11833")) /* Sonderbedingung Auskunft Inland */
dur -= 30;
#endif
pay2 = SN[call[chan].sondernummer].grund1 * currency_factor;
pay2 += (dur / SN[call[chan].sondernummer].takt1) * currency_factor;
break;
case 0 : pay2 = 0.0;
break;
case 1 : zone = 1;
break;
} /* switch */
} /* if */
if (zone == -1) {
zone2 = area_diff(NULL, call[chan].num[1]);
if ((c = call[chan].confentry[OTHER]) > -1)
zone = known[c]->zone;
if ((zone == -1) && (zone2 > 0)) {
sprintf(sx, "WARNING: Assuming ZONE %d", zone2);
zone = zone2;
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
} /* if */
if ((zone != -1) && (zone2 != -1) && (zone != zone2)) {
sprintf(sx, "WARNING: Wrong ZONE (%d), assuming %d", zone, zone2);
zone = zone2;
if (call[chan].sondernummer == -1)
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
} /* if */
} /* if */
if (pay2 == -1.0) {
if (call[chan].aoce > 0) /* Gebuehrentakt AOC-E kam (Komfortanschluss, via Telekom */
call[chan].pay = call[chan].aoce * currency_factor;
else {
if (zone > 0) {
#ifdef ISDN_DE
if (zone == 1)
pro2 = 33; /* CityCall :: Telekom */
else if (zone == 2)
pro2 = 70; /* RegioCall :: Arcor */
else if (zone == 3) {
#if 0
if ((tm->tm_wday > 0) && (tm->tm_wday < 6))
wochentag;
else
wochenende;
#endif
if ((tm->tm_hour > 20) || (tm->tm_hour < 5))
pro2 = 30; /* zw. 21:00 Uhr und 5:00 Uhr TelDaFax */
else
pro2 = 19; /* Mobilcom */
} /* else */
switch (zone) { /* map "isdnlog" to "gebuehr.c" Zones */
case 2 : zone = 3;
break;
case 3 : zone = 4;
break;
} /* switch */
pro = call[chan].provider;
if (pro == -1)
pro = 33; /* Telekom */
if (pro) {
call[chan].pay = pay(call[chan].connect, dur, zone, pro);
if (call[chan].pay == -1.0) { /* Unknown Tarif */
if (pro == 23) { /* tesion )) -- quick hack for SL "Baden-W<>rttemberg Tarif" */
if ((tm->tm_hour > 20) || (tm->tm_hour < 9))
pay3 = 0.14;
else
pay3 = 0.21;
call[chan].pay = (pay3 / 60.0) * dur;
}
else
call[chan].pay = 0;
} /* if */
} /* if */
if (pro != pro2) {
pay3 = pay(call[chan].connect, dur, zone, pro2);
cheap = call[chan].pay - pay3;
if (cheap > 0) {
sprintf(sx, "WARNING: Provider %s DM %s cheaper!",
Providername(pro2),
double2str(cheap, 5, 2, DEB));
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
} /* if */
} /* if */
#endif
} /* if */
} /* else */
#ifdef ISDN_DE
if ((dur > 600) && (zone > 1) && ((call[chan].aoce > 0) || (pro == 33))) {
onesec = call[chan].pay / dur;
pay2 = (dur - 600) * onesec * 0.30;
sprintf(sx, "10plus DM %s - DM %s = DM %s",
double2str(call[chan].pay, 6, 2, DEB),
double2str(pay2, 6, 2, DEB),
double2str(call[chan].pay - pay2, 6, 2, DEB));
call[chan].pay -= pay2;
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
} /* if */
#endif
}
else
call[chan].pay = pay2;
} /* if */
} /* how_expensive */
static void dumpme()
{
register int chan;
auto char s[BUFSIZ];
for (chan = 0; chan < MAXCHAN; chan++) {
sprintf(s, "^CHAN[%d]: %s -> %s\n",
chan,
call[chan].vnum[0],
call[chan].vnum[1]);
print_msg(PRT_SHOWNUMBERS, "%s", s);
} /* for */
} /* dumpme */
/* mode :: 0 = Add new entry, 1 = change existing entry, 2 = Terminate entry, 3 = dump */
static void addlist(int chan, int type, int mode)
{
#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[0] = strdup(call[chan].vnum[CALLING]);
list[lp].vnum[1] = 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 */
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], s2[BUFSIZ];
static char last[BUFSIZ];
auto int isAVMB1 = 0;
hexSeen = 1;
#ifdef Q931
if (q931dmp) {
register int bcast = (strtol(ps + 8, NIL, 16) >> 1) == 0x7f;
if (replaydev)
fprintf(stdout, "\n\n-----[ %d ]-------------------------------------------------------------------\n\n", ++lfd);
else
fprintf(stdout, "\n\n-----[ %d ]------[ %s ]------------------------------------------\n\n", ++lfd, st + 4);
if (bcast) {
s[13] = 0;
if (replaydev)
fprintf(stdout, "r[%d]: %s %s\n\n", card, s + 5, s + 14);
else
fprintf(stdout, "[%s] r[%d]: %s %s\n\n", st + 4, card, s + 5, s + 14);
s[13] = ' ';
}
else {
if (replaydev)
fprintf(stdout, "r[%d]: %s\n\n", card, s + 5);
else
fprintf(stdout, "[%s] r[%d]: %s\n\n", st + 4, card, s + 5);
} /* else */
} /* if */
#endif
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");
}
memcpy(ps, "HEX: ", 5);
}
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;
#ifdef Q931
if (!q931dmp)
#endif
print_msg(PRT_NORMAL, "(HiSax driver detected)\n");
HiSax = 1;
strcpy(last, s);
}
else {
if (!strcmp(last, s)) {
#ifdef Q931
if (!q931dmp)
#endif
return;
}
else
strcpy(last, s);
} /* else */
#ifdef Q931
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);
fprintf(stdout, "%02x TEI=%d E/A=%d\n",
j, tei, ea3);
#endif
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 */
#endif
if (!*(ps + 13) || !*(ps + 16))
return;
i = strtol(ps += 5, NIL, 16) >> 1;
net = i & 1;
sapi = i >> 1;
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 (*(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 */
} /* AVM B1 */
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;
default : version = VERSION_UNKNOWN; break;
} /* switch */
#ifdef Q931
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 */
#endif
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 */
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_MESSAGE, type, NULL, version);
#endif
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);
if (call[chan].channel) { /* Aha, Kanal war dabei, dann nehmen wir den gleich */
chan = call[chan].channel - 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);
/* dumpme(); */
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);
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);
/* 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);
switch (type) {
case ALERTING :
case CALL_PROCEEDING :
#ifdef Q931
if (!q931dmp)
#endif
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);
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 (message & PRT_SHOWNUMBERS)
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, "CONNECT");
else {
sprintf(sx, "CONNECT (%s)", call[chan].service);
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, sx);
} /* else */
if (!call[chan].dialin) {
auto char s[BUFSIZ], sx[BUFSIZ];
if ((call[chan].cint = taktlaenge(chan, s)) > 1) {
call[chan].cinth = hour;
call[chan].nextcint = call[chan].connect + (int)call[chan].cint;
call[chan].ctakt = 1;
sprintf(sx, "NEXT CHARGEINT IN %s (%s)", double2clock(call[chan].cint), s);
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, sx);
} /* 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 (!call[chan].dialin) {
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 */
how_expensive(chan);
#ifdef Q931
if (!q931dmp)
#endif
logger(chan);
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 {
if (call[chan].aoce > 0)
sprintf(sx, "HANGUP (%d EH %s %s %s%s)",
call[chan].aoce,
currency,
double2str(call[chan].pay, 6, 2, DEB),
double2clock((double)(call[chan].disconnect - call[chan].connect)), s2);
else if (call[chan].pay)
sprintf(sx, "HANGUP (%s %s %s%s)",
currency,
double2str(call[chan].pay, 6, 2, DEB),
double2clock((double)(call[chan].disconnect - call[chan].connect)), s2);
else
sprintf(sx, "HANGUP (%s%s) %s (%s)",
double2clock((double)(call[chan].disconnect - call[chan].connect)), s2,
qmsg(TYPE_CAUSE, version, call[chan].cause),
location(call[chan].loc));
} /* 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, location(call[chan].loc));
strcat(sx, ")");
} /* if */
} /* if */
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
if (!call[chan].dialin && ((c = call[chan].confentry[OTHER]) > -1)) {
if (chargemax != 0.0) {
sprintf(sx, "CHARGEMAX total=%s %s today=%s %s remaining=%s %s",
currency,
double2str(known[c]->scharge + known[c]->charge, 7, 2, DEB),
currency,
double2str(known[c]->charge, 6, 2, DEB),
currency,
double2str((chargemax - known[c]->charge), 6, 2, DEB));
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 processrate()
{
register char *p;
register int j;
auto char sx[BUFSIZ];
auto double s;
if (!ioctl(sockets[ISDNINFO].descriptor, IIOCGETCPS, &io)) {
if (verbose & VERBOSE_RATE) {
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 */
} /* processrate */
int morectrl(int card)
{
register char *p, *p1, *p2, *p3;
static char s[MAXCARDS][BIGBUFSIZ];
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], BUFSIZ)) > 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 */
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
processctrl(card, p1);
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 */
/*****************************************************************************/
void processcint()
{
register int chan;
auto char s[BUFSIZ], sx[BUFSIZ];
auto double newcint;
auto double exp;
auto int dur;
extern double pay(time_t ts, int dauer, int tarifz, int pro);
for (chan = 0; chan < 2; chan++) {
if (!call[chan].dialin && (call[chan].cint > 1)) {
if (call[chan].nextcint == cur_time) {
dur = cur_time - call[chan].connect;
if (call[chan].cinth != hour) { /* Moeglicherweise Taktwechsel */
newcint = taktlaenge(chan, s);
if (newcint != call[chan].cint) {
call[chan].cint = newcint;
sprintf(sx, "NEXT CHARGEINT IN %s (%s)", double2clock((double)call[chan].cint), s);
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, sx);
}
} /* if */
call[chan].cinth = hour;
call[chan].ctakt++;
if (1 /* message & PRT_SHOWTICKS */) {
#ifdef ISDN_DE
if ((call[chan].provider == -1) || (call[chan].provider == 33))
exp = call[chan].ctakt * currency_factor;
else
/* call pay() with duration + 1 to get the charge for the _next_ chargeint! */
exp = pay(call[chan].connect, dur + 1, call[chan].zone, call[chan].provider);
#else
exp = call[chan].ctakt * currency_factor;
#endif
sprintf(sx, "START %d.CHARGEINT %s %s (%s)",
call[chan].ctakt,
currency,
double2str(exp, 6, 2, DEB),
double2clock((double)dur));
info(chan, PRT_SHOWCONNECT, STATE_CONNECT, sx);
} /* if */
call[chan].nextcint += (int)call[chan].cint;
} /* if */
} /* if */
} /* for */
} /* processcint */