isdn4k-utils/isdnlog/isdnlog/processor.c

4050 lines
152 KiB
C
Raw Blame History

/* $Id: processor.c,v 1.1 1997/03/16 20:58:47 luethje Exp $
*
* ISDN accounting for isdn4linux. (log-module)
*
* Copyright 1995, 1997 by Andreas Kool (akool@Kool.f.EUnet.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.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);
static int HiSax = 0, hexSeen = 0;
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 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);
else
return;
(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 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;
register char *px, *px1, *px2, *px3;
auto int c, result = 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];
switch(type) {
case AOC_INITIAL : ID = OP = EH = MP = 0;
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;
} /* 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;
} /* 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, "Aufz<EFBFBD>hlungstyp, PublicTypeOfNumber=%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 : 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(c, 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);
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);
sprintf(s, "%s %s/%s -> %s (%s)", px1, src, px2, dst, px3);
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);
c = strtol(asnp += 3, NIL, 16);
sprintf(s, "ServedUserNr=%d", c);
aoc_debug(c, s);
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);
sprintf(s, "deactivate %s %s/%s", px1, dst, 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 */
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 void buildnumber(char *num, int oc3, int oc3a, char *result, int version)
{
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, "");
switch (oc3 & 0x70) { /* Calling party number Information element, Octet 3 - Table 4-11/Q.931 */
case 0x00 : if (*num) { /* 000 Unknown */
if (*amtsholung && !strncmp(num, amtsholung, strlen(amtsholung))) {
num += strlen(amtsholung);
#ifdef Q931
if (q931dmp) {
auto char s[BUFSIZ];
sprintf(s, "Amtsholung: %s", amtsholung);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
#endif
} /* if */
if (*num != '0')
sprintf(result, "%s%s", mycountry, myarea);
else {
strcpy(result, mycountry);
while (*num && (*num == '0'))
num++;
} /* else */
} /* if */
break;
case 0x10 : if (version != VERSION_1TR6)
strcpy(result, "00"); /* 001 International */
break;
case 0x20 : if (version != VERSION_1TR6)
strcpy(result, mycountry); /* 010 National */
break;
case 0x30 : break; /* 011 Network specific number */
case 0x40 : sprintf(result, "%s%s", mycountry, myarea); /* 100 Subscriber number */
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 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/%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 */
} /* 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;
auto char s[BUFSIZ], s1[BUFSIZ];
auto char sx[10][BUFSIZ];
auto int sn[10];
auto struct tm tm;
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 (*pd == 'U') {
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 standartisierte Codierung"); break;
case 0x20 :
case 0xa0 : sprintf(ps, "Reserve"); break;
case 0x40 :
case 0xc0 : sprintf(ps, "reserviert f<>r 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 (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);
call[chan].cause = c & 0x7f;
#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;
#if !defined(ISDN_NL) && !defined(ISDN_CH)
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
asnp = p;
n = facility(AOC_INITIAL, 0);
#endif
if (n == AOC_OTHER)
; /* info(chan, PRT_SHOWAOCD, STATE_AOCD, asnm); */
else {
call[chan].aoc = 1;
/* 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;
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);
err = call[chan].tick - tx;
call[chan].tick += tack;
if (message & PRT_SHOWTICKS)
sprintf(s, "%d.EH %s %s (%s %d) C=%s",
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)",
call[chan].aoce,
currency,
double2str(call[chan].pay, 6, 2, DEB),
double2clock(tx));
else
sprintf(s, "%d.EH %s %s",
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_SHOWAOCD, 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_SHOWAOCD, 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_SHOWAOCD, 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 */
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 */
if (message & PRT_SHOWTICKS)
sprintf(s, "%d.EH %s %s (%s %d %s?) C=%s",
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)",
call[chan].aoce,
currency,
double2str(call[chan].pay, 6, 2, DEB),
double2clock(tx));
else
sprintf(s, "%d.EH %s %s",
call[chan].aoce,
currency,
double2str(call[chan].pay, 6, 2, DEB));
} /* else */
}
else {
sprintf(s, "%d.EH %s %s",
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 */
} /* else */
} /* if */
p += (l * 3);
break;
case 0x29 : /* Date/Time */
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);
tm.tm_sec = 0;
tm.tm_wday = tm.tm_yday = 0;
tm.tm_isdst = -1;
call[chan].time = mktime(&tm);
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 */
sprintf(s, "Time:%s", ctime(&call[chan].time));
if ((px = strchr(s, '\n')))
*px = 0;
#ifdef Q931
if (q931dmp)
Q931dump(TYPE_STRING, -2, s + 5, version);
#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;
strcpy(call[chan].onum[CALLED], s);
buildnumber(s, oc3, oc3a, call[chan].num[CALLED], version);
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[6].onum[CALLING], s);
buildnumber(s, oc3, oc3a, call[6].num[CALLING], version);
strcpy(call[6].vnum[CALLING], vnum(6, 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[6].areacode[CALLING],
call[6].vorwahl[CALLING],
call[6].rufnummer[CALLING],
call[6].area[CALLING]);
Q931dump(TYPE_STRING, -2, s, version);
} /* if */
#endif
sprintf(s1, "CLIP %s", call[6].vnum[CALLING]);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s1);
break;
}
else {
warn = 1;
strcpy(call[6].vnum[CALLING], call[chan].vnum[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);
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
if (warn) {
sprintf(s1, "CLIP %s", call[6].vnum[CALLING]);
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);
#endif
if (dual > 1) {
auto char sx[BUFSIZ];
buildnumber(call[chan].digits, oc3, -1, call[chan].num[CALLED], version);
strcpy(call[chan].vnum[CALLED], vnum(chan, CALLED));
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);
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) {
sprintf(s, "RING (%s)", call[chan].service);
info(chan, PRT_SHOWNUMBERS, STATE_RING, s);
if (sound)
ringer(chan, RING_RING);
} /* if */
} /* else */
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, kein Kanal"); break;
case 0x81 : px += sprintf(px, "BRI, B1 bevorzugt"); break;
case 0x82 : px += sprintf(px, "BRI, B2 bevorzugt"); break;
case 0x83 : px += sprintf(px, "BRI, beliebiger Kanal"); break;
case 0x89 : px += sprintf(px, "BRI, B1 gefordert"); break;
case 0x8a : px += sprintf(px, "BRI, B2 gefordert"); break;
case 0x84 : px += sprintf(px, "BRI, D-Kanal gewuenscht"); break;
case 0x8c : px += sprintf(px, "BRI, D-Kanal gefordert"); break;
case 0xa0 : px += sprintf(px, "PRI, kein Kanal"); break;
case 0xa1 : px += sprintf(px, "PRI, Kanal nachstehend spezifiziert"); break;
case 0xa3 : px += sprintf(px, "PRI, angegebener Kanal bevorzugt"); break;
case 0xa9 : px += sprintf(px, "PRI, Nur der angeg. Kanal akzeptabel"); break;
case 0xac : px += sprintf(px, "PRI, D-Kanal gefordert"); break;
case 0xe0 : px += sprintf(px, "Kein Kanal"); break;
case 0xe1 : px += sprintf(px, "Kanal wie nachfolgend angegeben"); break;
case 0xe3 : px += sprintf(px, "Kanal beliebig"); 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_SHOWNUMBERS, 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_SHOWNUMBERS, 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 = p, *p2 = s;
register int i;
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):");
gets(s);
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 */
static void huptime(int chan, int bchan)
{
register int c = call[chan].confentry[OTHER];
auto isdn_net_ioctl_cfg cfg;
auto int oldchargeint = 0, newchargeint = 0;
auto int oldhuptimeout, newhuptimeout, zeit;
auto char sx[BUFSIZ];
if (hupctrl && (c > -1) && (*known[c]->interface > '@') && expensive(bchan)) {
strcpy(cfg.name, known[c]->interface);
if (ioctl(sockets[ISDNCTRL].descriptor, IIOCNETGCF, &cfg) >= 0) {
#ifndef OLD_I4L
call[chan].chargeint = oldchargeint = cfg.chargeint;
#endif
call[chan].huptimeout = oldhuptimeout = cfg.onhtime;
newchargeint = (int)cheap96(cur_time, known[c]->zone, &zeit);
if (hup1 && hup2)
newhuptimeout = (newchargeint < 20) ? hup1 : hup2;
else
newhuptimeout = oldhuptimeout;
if (oldchargeint != newchargeint) {
#ifndef OLD_I4L
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, %s",
known[c]->interface, newchargeint, oldchargeint,
z2s(known[c]->zone), t2tz(zeit));
info(chan, PRT_INFO, STATE_HUPTIMEOUT, sx);
if (oldhuptimeout != newhuptimeout) {
sprintf(sx, "HUPTIMEOUT %s %d (was %d)",
known[c]->interface, newhuptimeout, oldhuptimeout);
info(chan, PRT_INFO, STATE_HUPTIMEOUT, sx);
} /* if */
} /* if */
}
else {
sprintf(sx, "CHARGEINT %s still %d - %s, %s", known[c]->interface,
oldchargeint, z2s(known[c]->zone), t2tz(zeit));
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);
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) {
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 */
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); /* 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;
} /* clearchan */
static void processctrl(int card, char *s)
{
register char *ps = s;
register int i, c;
register int wegchan; /* fuer gemakelte */
auto int dialin, type, cref = -1, creflen, version;
static int tei = BROADCAST, sapi = 0, net = 1, firsttime = 1;
auto char sx[BUFSIZ], s2[BUFSIZ];
static char last[BUFSIZ];
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, "HEX: ", 5)) { /* new HiSax Driver */
if ((verbose & VERBOSE_HEX) && !(verbose & VERBOSE_CTRL))
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
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 { /* 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
#ifdef SL
if (version == VERSION_1TR6) {
print_msg(PRT_DEBUG_BUGS, " DEBUG> %s: OOPS! 1TR6 Frame? Ignored!\n", st + 4);
goto endhex;
} /* if */
#endif
creflen = strtol(ps += 3, NIL, 16);
if (creflen)
cref = strtol(ps += 3, NIL, 16);
else
cref = -1;
type = strtol(ps += 3, NIL, 16);
dialin = (tei == BROADCAST); /* dialin (Broadcast), alle anderen haben schon eine Tei! */
/* 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;
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");
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 */
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);
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);
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);
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 (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);
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 */
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;
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 (was %d)\n", st + 4, call[chan].aoc);
call[chan].aoc = 0;
} /* 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 */
#ifdef Q931
if (!q931dmp)
#endif
logger(chan);
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].aoc)
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
sprintf(sx, "HANGUP (%s %s) %s",
double2clock((double)(call[chan].disconnect - call[chan].connect)), s2,
qmsg(TYPE_CAUSE, version, call[chan].cause));
} /* else */
if (!memcmp(sx, "HANGUP ( )", 18))
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 */
info(chan, PRT_SHOWHANGUP, STATE_HANGUP, sx);
if (!call[chan].dialin && ((c = call[chan].confentry[OTHER]) > -1)) {
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_SHOWHANGUP, STATE_HANGUP, sx);
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_SHOWHANGUP, 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_SHOWHANGUP, 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))
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 */