diff --git a/isdnlog/Makefile b/isdnlog/Makefile index 27f0624b..715cc4b4 100644 --- a/isdnlog/Makefile +++ b/isdnlog/Makefile @@ -1,4 +1,4 @@ -## $Id: Makefile,v 1.1 1997/03/03 04:37:33 fritz Exp $ +## $Id: Makefile,v 1.2 1997/03/16 20:58:07 luethje Exp $ ## ## ISDN accounting for isdn4linux. ## @@ -19,6 +19,11 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ## ## $Log: Makefile,v $ +## Revision 1.2 1997/03/16 20:58:07 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 1.1 1997/03/03 04:37:33 fritz ## Added files in isdnlog ## @@ -32,6 +37,9 @@ else PREFIXDIR=$(ROOTDIR) endif +PREFIXDIR=.. +LIBAREA=1 + LIBISDNDIR = $(PREFIXDIR)/lib ifdef MAKELIB SUBDIRS = $(LIBISDNDIR) @@ -83,7 +91,7 @@ SERVICEFILE = /etc/services # DON'T EDIT BELOW THIS LINE ###################################################################### -#I4LVERSION = 2.60 +VERSION = 2.99.1 ifdef POSTGRES CFLAGS += -DPOSTGRES @@ -109,7 +117,7 @@ CFLAGS += -DOLDCONFFILE=\"$(OLDCONFFILE)\" \ -DLOGFILE=\"$(LOGFILE)\" \ -DRELOADCMD=\"$(RELOADCMD)\" \ -DSTOPCMD=\"$(STOPCMD)\" \ - -DI4LVERSION=\"$(I4LVERSION)\" \ + -DVERSION=\"$(VERSION)\" \ -DCHARGEFILE=\"$(CHARGEFILE)\" \ -DSERV_PORT=$(SERV_PORT) \ -DREBOOTCMD=\"$(REBOOTCMD)\" \ @@ -215,7 +223,7 @@ xinstall: xall install # @echo "" distrib: xdistclean - cd .. && tar cf /tmp/isdnlog-$(I4LVERSION).tar \ + cd .. && tar cf /tmp/isdnlog-$(VERSION).tar \ isdnlog-$(I4LVERSION)/Makefile \ isdnlog-$(I4LVERSION)/Isdn \ isdnlog-$(I4LVERSION)/README \ diff --git a/isdnlog/README b/isdnlog/README index fe00fecc..bdea2a27 100644 --- a/isdnlog/README +++ b/isdnlog/README @@ -2364,6 +2364,11 @@ Dies wird in 4 Stufen versucht: 4. Stufe: Der Rechner wird rebootet ("/sbin/reboot") +In der Parameterdatei wird dieses Feature mit + +watchdog="value" + +aufgerufen. 14.2 CHARGEMAX -------------- diff --git a/isdnlog/connect/connect.c b/isdnlog/connect/connect.c new file mode 100644 index 00000000..e91069db --- /dev/null +++ b/isdnlog/connect/connect.c @@ -0,0 +1,92 @@ +/* + * ISDN accounting for isdn4linux. + * + * Copyright 1996 by Stefan Luethje (luethje@sl-gw.lake.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/****************************************************************************/ + +#define _CONNECT_C_ + +/****************************************************************************/ + +#include "socket.h" + +/****************************************************************************/ + +int server_connect(struct servent **sp, int port) +{ + int sock; + struct sockaddr_in server; + + + if (!port) + if ((*sp = getservbyname(SERV_ISDNLOG,"tcp")) != NULL) + port = (*sp)->s_port; + else + port = htons(SERV_PORT); + else + port = htons (port); + + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = port; + + if ((sock = socket(AF_INET,SOCK_STREAM,0)) < 0) + return NO_SOCKET; + + if (bind(sock,(struct sockaddr*) &server,sizeof(server)) < 0) + return NO_BIND; + + if (listen(sock,MAX_CLIENTS_LISTEN)) + return NO_LISTEN; + + return sock; +} + +/****************************************************************************/ + +int client_connect(char *name, int port) +{ + int sock; + struct sockaddr_in server; + struct servent *sp; + struct hostent *hp = gethostbyname (name); + + if((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) + return NO_SOCKET; + + if (!port) + if ((sp = getservbyname(SERV_ISDNLOG,"tcp")) != NULL) + port = sp->s_port; + else + port = htons(SERV_PORT); + else + port = htons (port); + + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = port; + + memcpy ((char *) &server.sin_addr, (char *) hp->h_addr, hp->h_length); + + if (connect (sock, (struct sockaddr *) &server, sizeof (server)) < 0) + return NO_CONNECT; + + return sock; +} diff --git a/isdnlog/connect/conv_address.c b/isdnlog/connect/conv_address.c new file mode 100644 index 00000000..45cbf64f --- /dev/null +++ b/isdnlog/connect/conv_address.c @@ -0,0 +1,526 @@ +/* + * ISDN accounting for isdn4linux. + * + * Copyright 1996 by Stefan Luethje (luethje@sl-gw.lake.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/*****************************************************************************/ + +#define _CONV_ADDRESS_C_ + +/*****************************************************************************/ + +#include "socket.h" + +/*****************************************************************************/ + +#define ADR_DELIMITER ':' + +/*****************************************************************************/ + +int Set_String(char **Target, char*Source); +int Set_Address(Addresses **Adr, int Anz, char **Array, int *Cnt2); +int Set_String_Field(char ***String, int Anz,char **Array, int *Cnt2); +int Set_PhoneNumber(PhoneNumber **String, int Anz,char **Array, int *Cnt2); +int Set_Date(time_t *NewTime, char *Ptr1); +int Append_Date(char** String, time_t NewTime); +int Append_Integer(char** String, int Append); +int Append_String(char** String, char *Append); + +/*****************************************************************************/ + +#ifdef STANDALONE +int main (int argc, char* argv[]) +{ + int len = 5000; + char buf[5000]; + Address *Ptr; + + while(!feof(stdin)) + { + fgets(buf,len,stdin); + + if ((Ptr = read_address(buf)) != NULL) + { + printf("%s\n",write_address(Ptr)); + free_Address(Ptr); + } + } + + return 0; +} +#endif + +/*****************************************************************************/ + +Address* read_address(char* Ptr1) +{ + Address *APtr; + char **Array; + int Cnt = 0; + + + Array = String_to_Array(Ptr1, ADR_DELIMITER); + + if (Array == NULL) + { + del_Array(Array); + return NULL; + } + + if ((APtr = (Address*) calloc(1,sizeof(Address))) == NULL) + { + free_Address(APtr); + del_Array(Array); + return NULL; + } + + if (Set_String(&(APtr->NName),Array[Cnt++])) + { + free_Address(APtr); + del_Array(Array); + return NULL; + } + + if (Set_String(&(APtr->FName),Array[Cnt++])) + { + free_Address(APtr); + del_Array(Array); + return NULL; + } + + if (Array[Cnt]) + APtr->NumAdr = atoi(Array[Cnt++]); + else + { + free_Address(APtr); + del_Array(Array); + return NULL; + } + + if (Set_Address(&(APtr->Adr),APtr->NumAdr,Array,&Cnt)) + { + free_Address(APtr); + del_Array(Array); + return NULL; + } + + /* + if (Set_Date(&(APtr->Birthday),Ptr1)) + */ + if (Set_String(&(APtr->Birthday),Array[Cnt++])) + { + free_Address(APtr); + del_Array(Array); + return NULL; + } + + del_Array(Array); + return APtr; +} + +/*****************************************************************************/ + +char* write_address(Address* Ptr) +{ + int Cnt1, Cnt2; + int len; + char *RetCode = NULL; + + + if (Append_String(&RetCode,Ptr->NName)) + return NULL; + + if (Append_String(&RetCode,Ptr->FName)) + return NULL; + + if (Append_Integer(&RetCode,Ptr->NumAdr)) + return NULL; + + for (Cnt1 = 0; Cnt1 < Ptr->NumAdr; Cnt1++) + { + if (Append_String(&RetCode,Ptr->Adr[Cnt1].Company)) + return NULL; + + if (Append_String(&RetCode,Ptr->Adr[Cnt1].Street)) + return NULL; + + if (Append_String(&RetCode,Ptr->Adr[Cnt1].Country)) + return NULL; + + if (Append_String(&RetCode,Ptr->Adr[Cnt1].PLZ)) + return NULL; + + if (Append_String(&RetCode,Ptr->Adr[Cnt1].City)) + return NULL; + + if (Append_Integer(&RetCode,Ptr->Adr[Cnt1].NumTel)) + return NULL; + + for (Cnt2 = 0; Cnt2 < Ptr->Adr[Cnt1].NumTel; Cnt2++) + { + if (Append_String(&RetCode,Ptr->Adr[Cnt1].Tel[Cnt2].Number)) + return NULL; + + if (Append_String(&RetCode,Ptr->Adr[Cnt1].Tel[Cnt2].Alias)) + return NULL; + } + + if (Append_Integer(&RetCode,Ptr->Adr[Cnt1].NumFax)) + return NULL; + + for (Cnt2 = 0; Cnt2 < Ptr->Adr[Cnt1].NumFax; Cnt2++) + { + if (Append_String(&RetCode,Ptr->Adr[Cnt1].Fax[Cnt2].Number)) + return NULL; + + if (Append_String(&RetCode,Ptr->Adr[Cnt1].Fax[Cnt2].Alias)) + return NULL; + } + + if (Append_Integer(&RetCode,Ptr->Adr[Cnt1].NumEmail)) + return NULL; + + for (Cnt2 = 0; Cnt2 < Ptr->Adr[Cnt1].NumEmail; Cnt2++) + if (Append_String(&RetCode,Ptr->Adr[Cnt1].Email[Cnt2])) + return NULL; + } + + /* + if (Append_Date(&RetCode,Ptr->Birthday)) + */ + if (Append_String(&RetCode,Ptr->Birthday)) + return NULL; + + len = strlen(RetCode); + if (len > 0) + RetCode[len-1] = '\0'; + + return RetCode; +} + +/*****************************************************************************/ + +int Append_Integer(char** String, int Append) +{ + static char NewString[30]; + + sprintf(NewString,"%d",Append); + + return Append_String(String,NewString); +} + +/*****************************************************************************/ + +int Append_String(char** String, char *Append) +{ + int len1 = 0; + int len2 = 0; + + + if (Append == NULL) + Append = ""; + else + len2 = strlen(Append); + + if (*String) + { + len1 = strlen(*String); + *String = (char*) realloc(*String,(len1+len2+2)*sizeof(char)); + } + else + *String = (char*) calloc(len2+2,sizeof(char)); + + if (*String == NULL) + return -1; + + /* + strcat(*String,Append); + */ + memcpy(*String+len1,Append,len2); + (*String)[len1+len2] = ADR_DELIMITER; + (*String)[len1+len2+1] = '\0'; + + return 0; +} + +/*****************************************************************************/ + +int Append_Date(char** String, time_t NewTime) +{ + static char RetString[20]; + struct tm *Time; + + Time = localtime(&NewTime); + sprintf(RetString,"%d.%d.%d",Time->tm_mday,Time->tm_mon+1,Time->tm_year+1900); + + return Append_String(String,RetString); +} + +/*****************************************************************************/ + +int Set_Date(time_t *NewTime, char *Ptr) +{ + int Day, Month, Year; + time_t t_Time; + struct tm Time; + static struct tm *CurTime = NULL; + + + if (*Ptr == '\0') + return 0; + + if (sscanf(Ptr,"%d.%d.%d",&Day,&Month,&Year) == 3); + else + if (sscanf(Ptr,"%d/%d/%d",&Month,&Day,&Year) == 3); + else + return -1; + + Time.tm_sec = 0; + Time.tm_min = 0; + Time.tm_hour = 0; + Time.tm_wday = 0; + Time.tm_yday = 0; + Time.tm_isdst = 0; + Time.tm_mday = Day; + Time.tm_mon = Month - 1; + + if (Year < 100) + { + if (CurTime == NULL) + { + time(&t_Time); + CurTime = localtime(&t_Time); + } + + Time.tm_year = (CurTime->tm_year/100) * 100 + Year; + } + else + Time.tm_year = Year - 1900; + + (*NewTime) = mktime(&Time); + + return 0; +} + +/*****************************************************************************/ + +int Set_PhoneNumber(PhoneNumber **String, int Anz,char **Array, int *Cnt2) +{ + int Cnt = 0; + + if (!Anz) + return 0; + + if((*String = (PhoneNumber*) calloc(Anz,sizeof(PhoneNumber))) == NULL) + return -1; + + while (Cnt < Anz) + { + if (Set_String(&((*String)[Cnt].Number),Array[(*Cnt2)++])) + return -1; + + if (Set_String(&((*String)[Cnt].Alias),Array[(*Cnt2)++])) + return -1; + + Cnt++; + } + + return 0; +} + +/*****************************************************************************/ + +int Set_String_Field(char ***String, int Anz,char **Array, int *Cnt2) +{ + int Cnt = 0; + + if (!Anz) + return 0; + + if((*String = (char**) calloc(Anz,sizeof(char*))) == NULL) + return -1; + + while (Cnt < Anz) + { + if (Set_String(&((*String)[Cnt]),Array[(*Cnt2)++])) + return -1; + + Cnt++; + } + + return 0; +} + +/*****************************************************************************/ + +int Set_Address(Addresses **Adr, int Anz, char **Array, int *Cnt2) +{ + int Cnt = 0; + + + if (!Anz) + return 0; + + if((*Adr = (Addresses*) calloc(Anz,sizeof(Addresses))) == NULL) + return -1; + + while (Cnt < Anz) + { + if (Set_String(&((*Adr)[Cnt].Company),Array[(*Cnt2)++])) + return -1; + + if (Set_String(&((*Adr)[Cnt].Street),Array[(*Cnt2)++])) + return -1; + + if (Set_String(&((*Adr)[Cnt].Country),Array[(*Cnt2)++])) + return -1; + + if (Set_String(&((*Adr)[Cnt].PLZ),Array[(*Cnt2)++])) + return -1; + + if (Set_String(&((*Adr)[Cnt].City),Array[(*Cnt2)++])) + return -1; + + if (Array[*Cnt2]) + (*Adr)[Cnt].NumTel = atoi(Array[(*Cnt2)++]); + else + return -1; + + if (Set_PhoneNumber(&((*Adr)[Cnt].Tel),(*Adr)[Cnt].NumTel,Array,Cnt2)) + return -1; + + if (Array[*Cnt2]) + (*Adr)[Cnt].NumFax = atoi(Array[(*Cnt2)++]); + else + return -1; + + if (Set_PhoneNumber(&((*Adr)[Cnt].Fax),(*Adr)[Cnt].NumFax,Array,Cnt2)) + return -1; + + if (Array[*Cnt2]) + (*Adr)[Cnt].NumEmail = atoi(Array[(*Cnt2)++]); + else + return -1; + + if (Set_String_Field(&((*Adr)[Cnt].Email),(*Adr)[Cnt].NumEmail,Array,Cnt2)) + return -1; + + Cnt++; + } + + return 0; +} + +/*****************************************************************************/ + +int Set_String(char **Target, char*Source) +{ + int len = strlen(Source); + + if (len && Source) + { + if ((*Target = (char*) calloc(len+1,sizeof(char))) == NULL) + return -1; + + strcpy(*Target,Source); + + if ((*Target)[len-1] == '\n') + (*Target)[len-1] = '\0'; + } + + return 0; +} + +/*****************************************************************************/ + +void free_Address(Address *APtr) +{ + int Cnt1, Cnt2; + + + if (APtr->Adr) + { + for(Cnt1 = 0; Cnt1 < APtr->NumAdr; Cnt1++) + { + if (APtr->Adr[Cnt1].Tel) + { + for(Cnt2 = 0; Cnt2 < APtr->Adr[Cnt1].NumTel; Cnt2++) + { + if (APtr->Adr[Cnt1].Tel[Cnt2].Number) + free(APtr->Adr[Cnt1].Tel[Cnt2].Number); + + if (APtr->Adr[Cnt1].Tel[Cnt2].Alias) + free(APtr->Adr[Cnt1].Tel[Cnt2].Alias); + } + + free(APtr->Adr[Cnt1].Tel); + } + + if (APtr->Adr[Cnt1].Fax) + { + for(Cnt2 = 0; Cnt2 < APtr->Adr[Cnt1].NumFax; Cnt2++) + { + if (APtr->Adr[Cnt1].Fax[Cnt2].Number) + free(APtr->Adr[Cnt1].Fax[Cnt2].Number); + + if (APtr->Adr[Cnt1].Fax[Cnt2].Alias) + free(APtr->Adr[Cnt1].Fax[Cnt2].Alias); + } + + free(APtr->Adr[Cnt1].Fax); + } + + if (APtr->Adr[Cnt1].Email) + { + for(Cnt2 = 0; Cnt2 < APtr->Adr[Cnt1].NumEmail; Cnt2++) + if (APtr->Adr[Cnt1].Email[Cnt2]) + free(APtr->Adr[Cnt1].Email[Cnt2]); + } + + if (APtr->Adr[Cnt1].Company) + free(APtr->Adr[Cnt1].Company); + + if (APtr->Adr[Cnt1].Street) + free(APtr->Adr[Cnt1].Street); + + if (APtr->Adr[Cnt1].Country) + free(APtr->Adr[Cnt1].Country); + + if (APtr->Adr[Cnt1].PLZ) + free(APtr->Adr[Cnt1].PLZ); + + if (APtr->Adr[Cnt1].City) + free(APtr->Adr[Cnt1].City); + } + + free(APtr->Adr); + } + + if (APtr->FName) + free(APtr->FName); + + if (APtr->NName) + free(APtr->NName); + + if (APtr->Birthday) + free(APtr->Birthday); +} + +/*****************************************************************************/ + diff --git a/isdnlog/connect/socket.c b/isdnlog/connect/socket.c new file mode 100644 index 00000000..03d4fb1a --- /dev/null +++ b/isdnlog/connect/socket.c @@ -0,0 +1,495 @@ + +/* + * ISDN accounting for isdn4linux. + * + * Copyright 1996 by Stefan Luethje (luethje@sl-gw.lake.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/****************************************************************************/ + +#define _SOCKET_C_ + +/****************************************************************************/ + +#include "socket.h" + +/****************************************************************************/ + +int get_msg(socket_queue *sock, buffer *buf); +int bufcat(buffer *s1,buffer *s2, int first, int len); +int initbuf(buffer *buf); + +/****************************************************************************/ + +int Write(socket_queue* sock) +{ + /* ACHTUNG IN DIESER FKT DARF KEIN print_msg() AUFGERUFEN WERDEN !!!!! */ + int RetCode; + static buffer *buf = NULL; + char *Ptr; + + if (sock->descriptor < 0) + { +#ifdef DEBUG + syslog(LOG_DEBUG,"Write: Invalid Descriptor %d",sock->descriptor); +#endif + return 1; + } + + if (!buf) + { + buf = (buffer*) calloc(1,sizeof(buffer)); + + if (!buf) + return NO_MEMORY; + + if ((RetCode = initbuf(buf)) != 0) + return RetCode; + } + + if ((Ptr = itos(sock->msgbuf.used+_MSG_LEN+_MSG_MSG,_MSG_LEN)) == NULL) + return -1; + + memcpy(buf->buf,Ptr,_MSG_LEN); + buf->used = _MSG_LEN; + + if ((Ptr = itos(sock->msg,_MSG_MSG)) == NULL) + return -1; + +#ifdef DEBUG + syslog(LOG_DEBUG,"Write: Message %d:*%s*",sock->msg,sock->msgbuf.buf); +#endif + sock->msg = NO_MSG; + + memcpy(buf->buf+_MSG_LEN,Ptr,_MSG_MSG); + buf->used += _MSG_MSG; + + if ((RetCode = bufcat(buf,&(sock->msgbuf),0,sock->msgbuf.used)) != 0) + return RetCode; + + return write(sock->descriptor,buf->buf,buf->used); +} + +/****************************************************************************/ + +int Read(socket_queue* sock) +{ + int RetCode; + int SelRet; + fd_set readmask; + struct timeval timeout = {0,0}; + static buffer *buf = NULL; + + + if (sock->descriptor < 0) + { +#ifdef DEBUG + syslog(LOG_DEBUG,"Write: Invalid Descriptor %d",sock->descriptor); +#endif + return 1; + } + + if (sock->restbuf.len > BUF_SIZE && sock->restbuf.used == 0) + { + free(sock->restbuf.buf); + sock->restbuf.buf = NULL; + initbuf(&(sock->restbuf)); + } + + if (sock->msgbuf.len > BUF_SIZE && sock->msgbuf.used == 0) + { + free(sock->msgbuf.buf); + sock->msgbuf.buf = NULL; + initbuf(&(sock->msgbuf)); + } + else + sock->msgbuf.used = 0; + + if (!buf) + { + if ((buf = (buffer*) calloc(1,sizeof(buffer))) == NULL) + return NO_MEMORY; + + if ((RetCode = initbuf(buf)) != 0) + return RetCode; + } + else + if (buf->len > BUF_SIZE) + { + free(buf->buf); + buf->buf = NULL; + initbuf(buf); + } + + FD_ZERO(&readmask); + FD_SET(sock->descriptor,&readmask); + + while ((SelRet = select(sock->descriptor+1,&readmask,NULL,NULL,&timeout)) > 0 && + FD_ISSET(sock->descriptor,&readmask)) + if ((RetCode = buf->used = read(sock->descriptor,buf->buf,buf->len)) > 0) + { + if ((RetCode = bufcat(&(sock->restbuf),buf,0,buf->used)) != 0) + return RetCode; + } + else + return -1; + + if (SelRet < 0) + return -1; + + if (sock->restbuf.used) + if ((RetCode = get_msg(sock,buf)) != 0) + return RetCode; + + return -1; /* Sollte nur ein Wert > 0 zurueckliefern */ +} + +/****************************************************************************/ + +int init_socket(socket_queue *sock) +{ + int RetCode; + + + if (!sock) + return -1; + + if ((RetCode = initbuf(&(sock->msgbuf))) != 0) + return RetCode; + + if ((RetCode = initbuf(&(sock->restbuf))) != 0) + return RetCode; + + return 0; +} + +/****************************************************************************/ + +int get_msg(socket_queue *sock, buffer *buf) +{ + int len; + int RetCode; + + buf->used = 0; + sock->msgbuf.used = 0; + + if (sock->restbuf.used < _MSG_LEN + _MSG_MSG) + { + sock->status = NO_NEXT_MSG; + sock->msg = NO_MSG; + return 0; + } + + len = (int) stoi(sock->restbuf.buf,_MSG_LEN); + + /* printf("stoi %d,%d\n",len,sock->restbuf.used); */ + + if (len > sock->restbuf.used) + { + sock->status = NO_NEXT_MSG; + sock->msg = NO_MSG; + return 0; + } + + sock->msg = (int) stoi(sock->restbuf.buf+_MSG_LEN,_MSG_MSG); + + if ((RetCode = bufcat(buf,&(sock->restbuf),0,sock->restbuf.used)) != 0) + return RetCode; + + if ((RetCode = bufcat(&(sock->msgbuf),buf,_MSG_LEN+_MSG_MSG,len - _MSG_LEN - _MSG_MSG)) != 0) + return RetCode; + + sock->restbuf.used = 0; + if ((RetCode = bufcat(&(sock->restbuf),buf,len,buf->used - len)) != 0) + return RetCode; + + if (sock->restbuf.used >= _MSG_LEN + _MSG_MSG && + stoi(sock->restbuf.buf,_MSG_LEN) <= sock->restbuf.used) + sock->status = NEXT_MSG; + else + sock->status = NO_NEXT_MSG; + + return buf->used; +} + +/****************************************************************************/ + +int msgcpy(socket_queue *sock, char *String, int len) +{ + if (sock->msgbuf.len < len) + { + sock->msgbuf.len = len; + if ((sock->msgbuf.buf = (char*) realloc(sock->msgbuf.buf, len * sizeof(char))) == NULL) + return NO_MEMORY; + } + + memcpy(sock->msgbuf.buf,String,len); + sock->msgbuf.used = len; + + return 0; +} + +/****************************************************************************/ + +int bufcat(buffer *s1, buffer *s2, int first, int len) +{ + if (s1->used + len - first > s1->len) + { + s1->len = s1->used + len - first; + s1->buf = (char*) realloc(s1->buf, (s1->used + len - first) * sizeof(char)); + + if (s1->buf == NULL) + return NO_MEMORY; + } + + memcpy((void*) (s1->buf + s1->used),(void*) (s2->buf + first), len); + s1->used += len; + + return 0; +} + +/****************************************************************************/ + +int initbuf(buffer *buf) +{ + if (buf && buf->buf == NULL) + { + buf->buf = (char*) calloc(BUF_SIZE,sizeof(char)); + buf->len = BUF_SIZE; + buf->used = 0; + } + + return buf->buf?0:NO_MEMORY; +} + +/****************************************************************************/ + +unsigned long stoi (unsigned char* s, int len) +{ + unsigned long val = 0; + unsigned long Cnt = 0; + + + if (len > 4) + return 0; + + while (Cnt < len) + val = (val << 8) + s[Cnt++]; + + return val; +} + +/****************************************************************************/ + +char *itos (unsigned long val, int len) +{ + static char s[16]; + + + if (len > 4) + return NULL; + + while(len-- > 0) + { + s[len] = (char) val % 256; + val = val >> 8; + } + + return s; +} + +/****************************************************************************/ + +int add_socket(socket_queue **sock, int new_socket) +{ + int Cnt = 0; + + + if ((*sock) == NULL) + { + if (!((*sock) = (socket_queue*) calloc(2,sizeof(socket_queue)))) + return NO_MEMORY; + + (*sock)[0].descriptor = new_socket; + (*sock)[1].descriptor = NO_SOCKET; + } + else + { + Cnt = socket_size((*sock)); + (*sock) = (socket_queue*) realloc((*sock),sizeof(socket_queue)*(Cnt+2)); + memset(&((*sock)[Cnt+1]),0,sizeof(socket_queue)); + (*sock)[Cnt+1].descriptor = NO_SOCKET; + + (*sock)[Cnt].descriptor = new_socket; + } + + if (init_socket(&((*sock)[Cnt]))) + return NO_MEMORY; + + return 0; +} + +/****************************************************************************/ + +int del_socket(socket_queue **sock, int position) +{ + int Cnt; + + if (*sock == NULL) + return -1; + + Cnt = socket_size((*sock)); + if (position < 0 || position >= Cnt) + return -1; + + free((*sock)[position].msgbuf.buf); + free((*sock)[position].restbuf.buf); + free((*sock)[position].f_hostname); + free((*sock)[position].f_username); + + if (position == 0 && Cnt == 1) + { + free(*sock); + *sock = NULL; + return 0; + } + + close((*sock)[position].descriptor); + memcpy(&((*sock)[position]), + &((*sock)[Cnt-1]), + sizeof(socket_queue)); + + memset(&((*sock)[Cnt-1]),0,sizeof(socket_queue)); + (*sock)[Cnt-1].descriptor = NO_SOCKET; + + (*sock) = (socket_queue*) realloc((*sock),sizeof(socket_queue)*Cnt); + + return (*sock)?0:NO_MEMORY; +} + +/****************************************************************************/ + +int socket_size(socket_queue *sock) +{ + int Cnt = 0; + + if (sock != NULL) + while(sock[Cnt].descriptor != NO_SOCKET) + Cnt++; + + return Cnt; +} + +/****************************************************************************/ + +int Set_Info_Struct(CALL **Info, char *String) +{ + int Cnt = 0; + int channel; + char** Array = String_to_Array(String,C_DELIMITER); + + while(Array[Cnt++]); + + if (Cnt != 21) + { + del_Array(Array); + fprintf(stderr,"Internal error: wrong structure (%d elements)\n",Cnt); + return -1; + } + + if (*Info == NULL) + if (((*Info) = (CALL*) calloc(1,sizeof(CALL))) == NULL) + return NO_MEMORY; + + Cnt = 0; + + channel = atoi(Array[Cnt++]); + (*Info)->stat = atoi(Array[Cnt++]); + (*Info)->dialin = atoi(Array[Cnt++]); + strcpy((*Info)->num[_ME((*Info))],Array[Cnt++]); /* Meine MSN */ + strcpy((*Info)->alias[_ME((*Info))],Array[Cnt++]); + strcpy((*Info)->num[_OTHER((*Info))],Array[Cnt++]); + strcpy((*Info)->vorwahl[_OTHER((*Info))],Array[Cnt++]); + strcpy((*Info)->rufnummer[_OTHER((*Info))],Array[Cnt++]); + strcpy((*Info)->alias[_OTHER((*Info))],Array[Cnt++]); + strcpy((*Info)->area[_OTHER((*Info))],Array[Cnt++]); + (*Info)->connect = atoi(Array[Cnt++]); + (*Info)->t_duration = atoi(Array[Cnt++]); + (*Info)->aoce = atoi(Array[Cnt++]); + strcpy((*Info)->money,Array[Cnt++]); + strcpy((*Info)->currency,Array[Cnt++]); + (*Info)->ibytes = atoi(Array[Cnt++]); + (*Info)->obytes = atoi(Array[Cnt++]); + (*Info)->ibps = atof(Array[Cnt++]); + (*Info)->obps = atof(Array[Cnt++]); + strcpy((*Info)->msg,Array[Cnt++]); + + del_Array(Array); + return channel; +} + +/****************************************************************************/ + +char *GetHostByAddr(struct sockaddr *Addr) +{ + char *RetCode = NULL; + char *Ptr; + struct hostent *hp = NULL; + struct in_addr *In = &((struct sockaddr_in*) Addr)->sin_addr; + + + if ((hp = gethostbyaddr((char*) In,sizeof(long int),AF_INET)) != NULL) + { + if ((RetCode = (char*) calloc(strlen(hp->h_name)+1,sizeof(char))) ==NULL) + return NULL; + + strcpy(RetCode,hp->h_name); + } + else + if ((Ptr = inet_ntoa(*In)) != NULL) + { + if ((RetCode = (char*) calloc(strlen(Ptr)+1,sizeof(char))) ==NULL) + return NULL; + + strcpy(RetCode,Ptr); + } + + return RetCode; +} + +/****************************************************************************/ + +char *GetHostByName(char *Name) +{ + char *RetCode = NULL; + struct hostent *hp = NULL; + + + if ((hp = gethostbyname(Name)) != NULL) + { + if ((RetCode = (char*) calloc(strlen(hp->h_name)+1,sizeof(char))) ==NULL) + return NULL; + + strcpy(RetCode,hp->h_name); + } + + return RetCode; +} + +/****************************************************************************/ + diff --git a/isdnlog/connect/socket.h b/isdnlog/connect/socket.h new file mode 100644 index 00000000..5d0efb24 --- /dev/null +++ b/isdnlog/connect/socket.h @@ -0,0 +1,214 @@ +/* + * ISDN accounting for isdn4linux. + * + * Copyright 1996 by Stefan Luethje (luethje@sl-gw.lake.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/****************************************************************************/ + +#ifndef __MY_SOCKET_H_ +#define __MY_SOCKET_H_ + +/****************************************************************************/ + +#define PUBLIC extern + +/****************************************************************************/ + +#include + +/****************************************************************************/ + +#define SERV_ISDNLOG "isdnlog" +#define MAX_CLIENTS_LISTEN 5 + +#define PROT_VERSION "V0.2" + +#ifndef SERV_PORT +# define SERV_PORT 20011 +#endif + +/****************************************************************************/ + +#define NO_NEXT_MSG 0 +#define NEXT_MSG 1 + +/****************************************************************************/ + +#define NO_MSG 0 +#define MSG_WHO_IS 1 /* Vom Server: String mit Nummer */ +#define MSG_CALL_INFO 2 /* Vom Server: String mit Gebuehren-Info */ +#define MSG_ANNOUNCE 3 /* Vom Client: Anmeldung beim Server mit User als String */ +#define MSG_ANN_ACC 4 /* Vom Server: Mit Server-Typ z.B. T_ISDN4LINUX */ +#define MSG_ANN_REJ 5 /* Vom Server: Ablehnung ohne weitere Info */ +#define MSG_NEW_CALLER 6 /* Vom Client: String mit neuen Anrufer-Daten */ +#define MSG_CALLER 7 /* Vom Server: String mit Anrufer-Daten */ +#define MSG_TOPICS 8 /* Vom Server: Topics vom aktuellen Gespraech */ +#define MSG_NOTICE 9 /* Vom Server: Uebermitteln von einer Notiz */ +#define MSG_THRUPUT_INFO 10 /* Vom Server: Datendurchsatz */ +#define MSG_CLOCK_INFO 11 /* Vom Server: Uhrzeit vom Amt */ +#define MSG_SERVER 12 /* Vom Server: print_msg Meldungen */ +#define MSG_CHANGE_CHAN 13 /* Vom Server: Kanal wurde gewechselt */ +#define MSG_VERSION 14 /* Vom Server: Version des Protokolls: "PROT_VERSION" */ +#define MSG_CLOSE 15 /* Die Verbindung wird beendet ohne Parameter, Dummy-Message */ + +/****************************************************************************/ + +#define _MSG_LEN 4 +#define _MSG_MSG 2 +#define _MSG_2B 2 + +/****************************************************************************/ + +#define WF_NOTHING 0 /* WF : Wait for */ +#define WF_ACC 1 +#define WF_CLOSE 2 + +/****************************************************************************/ + +/* Die folgenden Flags stehen im direkten Bezug zu user_access.c:ValidFlags */ +#define T_NOTHING 0 /* Unterbau nicht vorhanden */ +#define T_I4LCONF 1 /* Unterbau ist isdn4liunx und darf configuriert werden */ +#define T_PROTOCOL 2 /* Meldungen vom S0 */ +#define T_ADDRESSBOOK 4 /* Es soll das Adressbuch erlaubt werden. */ + +/* ACHTUNG: Die folgende muss immer Upgedatet werden */ +#define T_ALL 6 /* Dieses ist die Summe aller gueltigen Flags. */ + +/****************************************************************************/ + +#define NO_SOCKET -2 +#define NO_BIND -3 +#define NO_LISTEN -4 +#define NO_CONNECT -5 +#define NO_MEMORY -6 + +/****************************************************************************/ + +#define C_DELIMITER '|' + +/****************************************************************************/ + +typedef struct { + int len; + int used; + char *buf; + } buffer; + +typedef struct _socket_queue{ + int descriptor; + FILE *fp; + pid_t pid; + int chan; + info_args *info_arg; + int call_event; + int msg; + int status; + int waitstatus; + int servtyp; + int input_id; + char *f_hostname; + char *f_username; + int (*eval)(struct _socket_queue*); + buffer restbuf; + buffer msgbuf; + } socket_queue; + +typedef struct { +char* Number; +char* Alias; +} PhoneNumber; + +typedef struct { +char *Company; +char *Street; +char *Country; +char *PLZ; +char *City; +int NumTel; +PhoneNumber *Tel; +int NumFax; +PhoneNumber *Fax; +int NumEmail; +char **Email; +} Addresses; + +typedef struct { +char *NName; +char *FName; +int NumAdr; +Addresses *Adr; +char* Birthday; +/* +time_t Birthday; +*/ +} Address; + +/****************************************************************************/ + +#ifdef _SOCKET_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN int Write(socket_queue* sock); +_EXTERN int Read(socket_queue* sock); +_EXTERN unsigned long stoi (unsigned char* s, int len); +_EXTERN char *itos (unsigned long val, int len); +_EXTERN int add_socket(socket_queue **sock,int new_socket); +_EXTERN int del_socket(socket_queue **sock,int position); +_EXTERN int socket_size(socket_queue *sock); +_EXTERN int msgcpy(socket_queue *sock, char *String, int len); +_EXTERN int init_socket(socket_queue *sock); +_EXTERN int Set_Info_Struct(CALL **Info, char *String); +_EXTERN char *GetHostByAddr(struct sockaddr *Addr); +_EXTERN char *GetHostByName(char *Name); + +#undef _EXTERN + +/****************************************************************************/ + +#ifdef _CONNECT_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN int client_connect(char *name, int port); +_EXTERN int server_connect(struct servent **sp, int port); + +#undef _EXTERN + +/****************************************************************************/ + +#ifdef _CONV_ADDRESS_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN Address* read_address(char* Ptr1); +_EXTERN char* write_address(Address *Ptr); +_EXTERN void free_Address(Address *APtr); + +#undef _EXTERN + +/****************************************************************************/ + +#endif /* __MY_SOCKET_H_*/ diff --git a/isdnlog/contrib/isdnbill/LIESMICH.isdnbill b/isdnlog/contrib/isdnbill/LIESMICH.isdnbill new file mode 100644 index 00000000..1f9c283a --- /dev/null +++ b/isdnlog/contrib/isdnbill/LIESMICH.isdnbill @@ -0,0 +1,11 @@ +Diese Verzeichnis enthaelt 3 Files: +- LIESMICH.isdnbill > dieses File +- README.isdnbill > englische Version dieses Files +- isdnbill.tar.gz > einige Tcl/Tk scripts, um Einheiten eines Users anzuzeigen, +sowie einige bunte Buttons, wenn man die -i oder -S-- Option von ISDNLOG ohne +Sound verwenden will... + +Die Scripts wurden mit ISDNLOG 2.30 getestet, Hinweise zur neuen Version 2.40 +in der DOKU ! + +Doku (bis jetzt nur auf deutsch) als PostScript im isdnbill.tar.gz ! diff --git a/isdnlog/contrib/isdnbill/README.isdnbill b/isdnlog/contrib/isdnbill/README.isdnbill new file mode 100644 index 00000000..887e2887 --- /dev/null +++ b/isdnlog/contrib/isdnbill/README.isdnbill @@ -0,0 +1,7 @@ +This dir contains 3 files: +- README.isdnbill > this file +- LIESMICH.isdnbill > german version of this file +- isdnbill.tar.gz > some Tcl/Tk scripts to display user's units and colourful + buttons, if you want to use the -i or -S-- option of ISDNLOG without sound... + +Sorry, but there is no english version of the DOCU yet ! diff --git a/isdnlog/contrib/isdnbill/isdnbill.tar.gz b/isdnlog/contrib/isdnbill/isdnbill.tar.gz new file mode 100644 index 00000000..b2f59f82 Binary files /dev/null and b/isdnlog/contrib/isdnbill/isdnbill.tar.gz differ diff --git a/isdnlog/contrib/winpopup/winpopup b/isdnlog/contrib/winpopup/winpopup new file mode 100644 index 00000000..78228382 --- /dev/null +++ b/isdnlog/contrib/winpopup/winpopup @@ -0,0 +1,101 @@ +Da sind sie endlich, die Skripte fuer den Versand von WinPopUp-Meldungen. + +In die isdnlog.conf wird als allgemeines Event das START_Ring-Skript +eingetragen, dass bei eingehenden Anrufen einmal aufgerufen wird und mit +Send_WinPopup eine Meldung verschickt. + +Ausserdem habe ich sowohl bei Connect als auch bei Hangup bei meinem +Provider ein Skripte eingetragen: ZDV_Connect und ZDV_Hangup. Diese +beiden senden ebenfalls mit Send_WinPopup einen Hinweis, dass die +ISDN-Leitung gerade auf- bzw. abgebaut wird. (Allerdings nur, wenn eine +Datei /etc/isdnlog/isdn.debug existiert, so kann man dies relativ leicht +an und abschalten.) + +Das Hauptskript Send_WinPopup versendet mit smbclient die eigentlichen +Messages, in diesem Fall an die Rechner "mizar" und "alcor" (Das sollte +der TCP/IP-Name (aus dem Nameserver) der jeweiligen Rechner sein, oder +falls mit WINS gearbeitet wird, kann es auch der im Windows-Netzwerk +eingetragene Name sein, am Besten nimmt man an beiden Stellen den +gleichen Namen.) + +Die Meldung im ersten Parameter wird an das Programm gepiped, da +smbclient sie normalerweise von der Tastatur einlesen wuerde. Ausserdem +kann man mit -U noch einen Absender angeben, den WinPopup anzeigt. + +Auf den jeweiligen Rechnern muss WinPopup (3.11/95) oder der +Nachrichtendienst (NT) gestartet sein. + +Als kleine Ergaenzung: Auch auf Linux-Rechnern kann man die WinPopups +empfangen, dann muss man allerdings im smb.conf die entsprechende Zeile +eintragen und ein Skript anlegen, was die Meldung irgendwie anzeigt oder +loggt. + +Falls noch weiteres Interesse an der Konfiguration von Samba besteht, +kann ich auch gerne mal meine Konfig-Dateien posten. + +Ich hoffe Ihr koennt was damit anfangen, die Skripte sind nicht gerade +elegant, aber ich hab sowas noch nicht oft gemacht. + +Viel Spass, + +-Michael + +---- isdnlog.conf ---- +MYMSNS=4 +MYPREFIX=07472 +START=IR=/etc/isdnlog/START_Ring $1 $2 $3; +MSN1 Telefon 1 - +MSN2 Telefax 1 - +MSN3,1 Michael 1 - +MSN4,7 Teles 1 - +PROVIDER ZDV_Internet 1 ippp0 OC=/etc/isdnlog/ZDV_Connect; OH=/etc/isdnlog/ZDV_Hangup; + +---- START_Ring --- +#!/bin/sh +# Michael Ruder +# +# Version: 08.10.96 +# +# /etc/isdnlog/START_Ring +# + +/etc/isdnlog/Send_WinPopup 'Eingehender Anruf von '$2' auf '$3'.' & + +# if test $3="IRGENDEINE_NUMMER"; then +# isdnctrl dial ippp0 +# fi + +---- Send_WinPopup ---- +#!/bin/sh +# Michael Ruder +# +# Version: 08.10.96 +# +# /etc/isdnlog/Send_WinPopup +# + +echo $1 | smbclient -M mizar -U ISDN-Administrator >/dev/null +echo $1 | smbclient -M alcor -U ISDN-Administrator >/dev/null + +---- ZDV_Connect ---- +#!/bin/sh +# Michael Ruder +# +# Version: 08.10.96 +# +# /etc/isdnlog/ZDV_Connect +# + +if test -e "/etc/isdnlog/isdn.debug"; then + /etc/isdnlog/Send_WinPopup 'Die ISDN-Leitung wird aufgebaut.' & +fi + +---- Auschnitt aus smb.conf ---- +[global] + message command = mv %s %s.working; echo WinPopup-Message from %f@%m for %t: > %s; cat %s.working >> %s; wall %s; rm %s %s.working & + + -Michael + + /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ + < Michael Ruder, Fax +49-7472-91382, email: Michael.Ruder@Uni-Tuebingen.DE > + \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ diff --git a/isdnlog/isdnconf/isdnconf.c b/isdnlog/isdnconf/isdnconf.c new file mode 100644 index 00000000..f005bc11 --- /dev/null +++ b/isdnlog/isdnconf/isdnconf.c @@ -0,0 +1,589 @@ +/* +Der SI muss auch als Eingabe (mit Hex) erlaubt sein +MSNxx -> MSN +*/ +/* $Id: isdnconf.c,v 1.1 1997/03/16 20:58:33 luethje Exp $ + * + * ISDN accounting for isdn4linux. (Report-module) + * + * Copyright 1996, 1997 by Stefan Luethje (luethje@sl-gw.lake.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "isdnconf.h" + +/*****************************************************************************/ + +int print_in_modules(const char *fmt, ...); +int print_msg(int Level, const char *fmt, ...); +int add_data(section **conf_dat); +int delete_data(char *, char *, section **conf_dat); +int look_data(section **conf_dat); +int find_data(char *_alias, char *_number, section *conf_dat); +const char* make_word(const char *in); +char* tmp_dup(const char *in); +int add_line(section **Ptr, const char *Name); + +/*****************************************************************************/ + +static int and = 0; +static int add = 0; +static int del = 0; +static int msn = 0; +static int quiet = 0; +static int short_out= 0; +static int long_out= 0; + +static int match_flags = F_NO_HOLE_WORD; + +static char areacode[SHORT_STRING_SIZE] = ""; +static char si[SHORT_STRING_SIZE]; +static char number[BUFSIZ] = ""; +static char alias[BUFSIZ] = ""; +static char conffile[BUFSIZ]; + +/*****************************************************************************/ + +int add_line(section **Ptr, const char *Name) +{ + char buf[BUFSIZ] = ""; + + + if (fgets(buf,BUFSIZ,stdin) != NULL) + { + if (strlen(buf) > 1) + { + buf[strlen(buf)-1] = '\0'; + + if (Set_Entry(*Ptr,NULL,tmp_dup(Name),buf,C_WARN) == NULL) + { + print_msg(PRT_ERR,"%s\n","Can not allocate memory!"); + return -1; + } + } + } + else + { + free_section(*Ptr); + *Ptr = NULL; + return -1; + } + + return 0; +} + +/*****************************************************************************/ + +int add_data(section **conf_dat) +{ + int Cnt = 0; + section *NewPtr = NULL; + section *SubPtr = NULL; + + + while(1) + { + NewPtr = NULL; + + if (Set_Section(&NewPtr,tmp_dup(msn?CONF_SEC_MSN:CONF_SEC_NUM),C_NOT_UNIQUE) == NULL) + { + print_msg(PRT_ERR,"%s\n","Can not allocate memory!"); + return -1; + } + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_ALIAS)); + if (add_line(&NewPtr,CONF_ENT_ALIAS)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_NUM)); + if (add_line(&NewPtr,CONF_ENT_NUM)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t\t",CONF_ENT_SI); + if (add_line(&NewPtr,CONF_ENT_SI)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_ZONE)); + if (add_line(&NewPtr,CONF_ENT_ZONE)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t",make_word(CONF_ENT_INTFAC)); + if (add_line(&NewPtr,CONF_ENT_INTFAC)) + break; + + while(1) + { + SubPtr = NULL; + + if (Set_Section(&SubPtr,tmp_dup(CONF_SEC_FLAG),C_NOT_UNIQUE) == NULL) + { + print_msg(PRT_ERR,"%s\n","Can not allocate memory!"); + return -1; + } + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_FLAGS)); + if (add_line(&SubPtr,CONF_ENT_FLAGS)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t",make_word(CONF_ENT_PROG)); + if (add_line(&SubPtr,CONF_ENT_PROG)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_USER)); + if (add_line(&SubPtr,CONF_ENT_USER)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_GROUP)); + if (add_line(&SubPtr,CONF_ENT_GROUP)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t",make_word(CONF_ENT_INTVAL)); + if (add_line(&SubPtr,CONF_ENT_INTVAL)) + break; + + if (!quiet) + print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_TIME)); + if (add_line(&SubPtr,CONF_ENT_TIME)) + break; + + Set_SubSection(NewPtr,tmp_dup(CONF_ENT_START),SubPtr,C_APPEND | C_WARN); + } + + if (!quiet) + print_msg(PRT_NORMAL,"\n\n"); + + while(*conf_dat != NULL) + conf_dat = &((*conf_dat)->next); + + *conf_dat = NewPtr; + Cnt++; + } + + if (!quiet) + print_msg(PRT_NORMAL,"\n"); + + return Cnt; +} + +/*****************************************************************************/ + +int delete_data(char * _alias , char * _number, section **conf_dat) +{ + short_out = 1; + + if (!quiet) + print_msg(PRT_NORMAL,"Following entry deleted!\n"); + + if (!quiet) + find_data(_alias,_number,*conf_dat); + + Del_Section(conf_dat,NULL); + return 0; +} + +/*****************************************************************************/ + +int find_data(char *_alias, char *_number, section *conf_dat) +{ + auto char *ptr; + auto entry *CEPtr; + auto section *SPtr; + + if (quiet) + { + print_msg(PRT_NORMAL,"%s",_alias?_alias:(number[0]?expand_number(number):alias)); + } + else + { + print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_ALIAS),_alias?_alias:S_UNKNOWN); + print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_NUM),_number?_number:S_UNKNOWN); + + if (_number != NULL && (ptr = get_areacode(_number,NULL,C_NO_ERROR)) != NULL) + print_msg(PRT_NORMAL,"Location:\t%s\n",ptr); + + if (!short_out) + { + ptr = (CEPtr = Get_Entry(conf_dat->entries,CONF_ENT_SI))?(CEPtr->value?CEPtr->value:"0"):"0"; + print_msg(PRT_NORMAL,"%s:\t\t%s\n",CONF_ENT_SI,ptr); + + ptr = (CEPtr = Get_Entry(conf_dat->entries,CONF_ENT_ZONE))?(CEPtr->value?CEPtr->value:""):""; + print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_ZONE),ptr); + + ptr = (CEPtr = Get_Entry(conf_dat->entries,CONF_ENT_INTFAC))?(CEPtr->value?CEPtr->value:""):""; + print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_INTFAC),ptr); + } + + if (long_out) + { + SPtr = Get_SubSection(conf_dat,CONF_ENT_START); + + while (SPtr != NULL) + { + ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_FLAGS))?(CEPtr->value?CEPtr->value:""):""; + print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_FLAGS),ptr); + + ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_PROG))?(CEPtr->value?CEPtr->value:""):""; + print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_PROG),ptr); + + ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_USER))?(CEPtr->value?CEPtr->value:""):""; + print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_USER),ptr); + + ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_GROUP))?(CEPtr->value?CEPtr->value:""):""; + print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_GROUP),ptr); + + ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_INTVAL))?(CEPtr->value?CEPtr->value:""):""; + print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_INTVAL),ptr); + + ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_TIME))?(CEPtr->value?CEPtr->value:""):""; + print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_TIME),ptr); + + SPtr = SPtr->next; + } + } + } + + print_msg(PRT_NORMAL,"\n"); + + return 0; +} + +/*****************************************************************************/ + +int look_data(section **conf_dat) +{ + int Cnt = 0; + auto entry *CEPtr; + char *_number = NULL, *_alias; + char _si[SHORT_STRING_SIZE]; + section *old_conf_dat = NULL; + + + while (*conf_dat != NULL) + { + old_conf_dat = *conf_dat; + + if (!strcmp((*conf_dat)->name,CONF_SEC_NUM) || !strcmp((*conf_dat)->name,CONF_SEC_MSN)) + { + int Ret = 0; + + _number = _alias = NULL; + _si[0] = '\0'; + + if ((CEPtr = Get_Entry((*conf_dat)->entries,CONF_ENT_NUM)) != NULL) + _number = CEPtr->value; + + if ((CEPtr = Get_Entry((*conf_dat)->entries,CONF_ENT_ALIAS)) != NULL) + _alias = CEPtr->value; + + if ((CEPtr = Get_Entry((*conf_dat)->entries,CONF_ENT_SI)) != NULL && + CEPtr->value != NULL) + sprintf(_si,"%ld",strtol(CEPtr->value, NIL, 0)); + + if (and) + Ret = 1; + else + Ret = 0; + + if (number[0] && _number != NULL) + { + if (!num_match(_number,number)) + Ret = 1; + else + Ret = 0; + } + + if (alias[0] && _alias != NULL) + { + int Ret2 = 0; + + if (!match(alias,_alias,match_flags)) + Ret2 = 1; + + if (and) + Ret &= Ret2; + else + Ret |= Ret2; + } + + if (si[0]) + { + int Ret2 = 0; + + if (!strcmp(_si,si)) + Ret2 = 1; + + if (and) + Ret &= Ret2; + else + Ret |= Ret2; + } + + if (Ret == 1) + { + if (del) + { + delete_data(_alias,_number,conf_dat); + Cnt++; + } + else + { + find_data(_alias,_number,*conf_dat); + Cnt++; + } + } + } + + if (*conf_dat != NULL && old_conf_dat == *conf_dat) + conf_dat = &((*conf_dat)->next); + } + + if (Cnt == 0 && quiet && !del) + find_data(NULL,_number,*conf_dat); + + return Cnt; +} + +/*****************************************************************************/ + +char* tmp_dup(const char *in) +{ + static char out[SHORT_STRING_SIZE]; + + strcpy(out,in); + return out; +} + +/*****************************************************************************/ + +const char* make_word(const char *in) +{ + int i = 0; + static char out[SHORT_STRING_SIZE]; + + out[0] ='\0'; + + while(in[i] != '\0') + out[i] = tolower(in[i]),i++; + + out[i] ='\0'; + out[0] = toupper(out[0]); + + return out; +} + +/*****************************************************************************/ + +int print_msg(int Level, const char *fmt, ...) +{ + auto va_list ap; + auto char String[LONG_STRING_SIZE]; + + + va_start(ap, fmt); + vsnprintf(String, LONG_STRING_SIZE, fmt, ap); + va_end(ap); + + if (Level & PRT_ERR) + fprintf(stderr, "%s", String); + else + fprintf(stdout, "%s", String); + + return 0; +} + +/*****************************************************************************/ + +int print_in_modules(const char *fmt, ...) +{ + auto va_list ap; + auto char String[LONG_STRING_SIZE]; + + + va_start(ap, fmt); + (void)vsnprintf(String, LONG_STRING_SIZE, fmt, ap); + va_end(ap); + + return print_msg(PRT_ERR, "%s", String); +} + +/*****************************************************************************/ + +int main(int argc, char *argv[], char *envp[]) +{ + int c; + int Cnt = 0; + section *conf_dat = NULL; + char *myname = basename(argv[0]); + + static char usage[] = "%s: usage: %s [ -%s ]\n"; + static char options[] = "ADdn:a:t:f:c:wslimqV"; + + + set_print_fct_for_tools(print_in_modules); + + alias[0] = '\0'; + number[0] = '\0'; + sprintf(conffile,"%s%c%s",confdir(),C_SLASH,CONFFILE); + + while ((c = getopt(argc, argv, options)) != EOF) + switch (c) { + case 'A' : add++; + break; + + case 'D' : del++; + break; + + case 'V' : print_version(myname); + exit(0); + + case 'd' : and++; + break; + + case 'm' : msn++; + break; + + case 'i' : match_flags |= F_IGNORE_CASE; + break; + + case 'n' : strcpy(number, optarg); + break; + + case 'a' : strcpy(alias, optarg); + break; + + case 't' : sprintf(si,"%ld",strtol(optarg, NIL, 0)); + break; + + case 's' : short_out++; + break; + + case 'l' : long_out++; + break; + + case 'w' : match_flags &= ~F_NO_HOLE_WORD; + break; + + case 'q' : quiet++; + break; + + case 'f' : strcpy(conffile, optarg); + break; + + case 'c' : strcpy(areacode, optarg); + break; + + case '?' : print_msg(PRT_ERR, usage, myname, myname, options); + return(1); + } + + if (add || del) + { + if ((conf_dat = read_file(NULL, conffile, C_NOT_UNIQUE)) == NULL) + exit(2); + + if (Set_Codes(conf_dat) != 0) + { + print_msg(PRT_ERR,"Error: Variables `%s' and `%s' are not set!\n",CONF_ENT_AREA,CONF_ENT_COUNTRY); + exit(5); + } + } + else + { + if (read_isdnconf(&conf_dat) == NULL) + exit(2); + } + + if (number[0] != '\0') + strcpy(number, expand_number(number)); + + if (areacode[0] != '\0') + { + char *ptr; + + if ((ptr = get_areacode(areacode,NULL,0)) != NULL) + { + print_msg(PRT_NORMAL,"%s\n",ptr); + exit(0); + } + else + exit(3); + } + + if (optind < argc && !add) + { + if (!alias[0] && optind + 1 == argc) + strcpy(alias, argv[optind]); + else + { + print_msg(PRT_ERR,"Can not set two strings for alias!\n"); + exit(3); + } + } + + if (!add) + { + if (!alias[0] && !number[0] && !si[0]) + { + print_msg(PRT_ERR, usage, argv[0], argv[0], options); + exit(4); + } + } + else + { + if (alias[0] || number[0] || si[0]) + { + print_msg(PRT_ERR, usage, argv[0], argv[0], options); + exit(5); + } + } + + if (add && del) + { + print_msg(PRT_ERR,"Can not do add and delete together!\n"); + exit(1); + } + + if (short_out && long_out) + { + print_msg(PRT_ERR,"Can not do long and short output together!\n"); + exit(1); + } + + if (add) + Cnt = add_data(&conf_dat); + else + Cnt = look_data(&conf_dat); + + if ((add || del) && Cnt > 0) + if (write_file(conf_dat,conffile,myname,VERSION) == NULL) + exit(5); + + free_section(conf_dat); + + return 0; +} + diff --git a/isdnlog/isdnconf/isdnconf.h b/isdnlog/isdnconf/isdnconf.h new file mode 100644 index 00000000..296f2957 --- /dev/null +++ b/isdnlog/isdnconf/isdnconf.h @@ -0,0 +1,40 @@ +/* $Id: isdnconf.h,v 1.1 1997/03/16 20:58:34 luethje Exp $ + * + * ISDN accounting for isdn4linux. + * + * Copyright 1995, 1996 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. + * + */ + +#ifndef _ISDN_CONF_H_ +#define _ISDN_CONF_H_ + +#define PRT_ERR 1 +#define PRT_NORMAL 4 + +#define PUBLIC extern +#include "tools.h" + +#ifdef _ISDN_CONF_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +#undef _EXTERN + +#endif /* _ISDN_CONF_H_ */ diff --git a/isdnlog/isdnlog/functions.c b/isdnlog/isdnlog/functions.c new file mode 100644 index 00000000..af930a57 --- /dev/null +++ b/isdnlog/isdnlog/functions.c @@ -0,0 +1,313 @@ +/* $Id: functions.c,v 1.1 1997/03/16 20:58:39 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 + */ + +#define _FUNCTIONS_C_ + +#include "isdnlog.h" +#ifdef POSTGRES +#include "postgres.h" +#endif + + +/*****************************************************************************/ + +static void saveCharge() +{ + register int i; + auto FILE *f; + auto char fn[BUFSIZ], fno[BUFSIZ]; + + + sprintf(fn, "%s/%s", confdir(), CHARGEFILE); + sprintf(fno, "%s.old", fn); + (void)rename(fn, fno); + + if ((f = fopen(fn, "w")) != (FILE *)NULL) { + for (i = 0; i < knowns; i++) + if (known[i]->day > -1) + fprintf(f, "%s %d %g %g %d %g %g %g %g\n", known[i]->who, + known[i]->day, known[i]->charge, known[i]->scharge, + known[i]->month, known[i]->online, known[i]->sonline, + known[i]->bytes, known[i]->sbytes); + + fclose(f); + } /* if */ +} /* saveCharge */ + +/*****************************************************************************/ + +void _Exit(char *File, int Line, int RetCode) /* WARNING: RetCode==-9 does _not_ call exit()! */ +{ +#ifdef Q931 + if (!q931dmp) +#endif + +#ifdef DEBUG + print_msg(PRT_NORMAL, "exit now %d in module `%s' at line %d!\n", RetCode, File, Line); +#else + print_msg(PRT_NORMAL, "exit now %d\n", RetCode); +#endif + + if (socket_size(sockets) >= 2) { + close(sockets[ISDNCTRL].descriptor); + close(sockets[ISDNINFO].descriptor); + + if (xinfo && sockets[IN_PORT].descriptor != -2) + close(sockets[IN_PORT].descriptor); + } /* if */ + + closelog(); + +#ifdef POSTGRES + dbClose(); +#endif + + if (!replay) { + saveCharge(); + delete_runfile(pidfile); + } /* if */ + + if (RetCode != -9) + exit(RetCode); +} /* Exit */ + +/*****************************************************************************/ + +int Change_Channel(int old_channel, int new_channel) +{ + change_channel(old_channel,new_channel); + Change_Channel_Ring(old_channel,new_channel); + + return 0; +} + +/*****************************************************************************/ + +void now(void) +{ + auto struct tms tms; + + + time(&cur_time); + tto = tt; + tt = times(&tms); + set_time_str(); +} /* now */ + +/*****************************************************************************/ + +void set_time_str(void) +{ + auto struct tm *tm_time = localtime(&cur_time); + + + tm_time->tm_isdst = 0; + + strftime(stl, 64, "%a %b %d %X %Y", tm_time); + strftime(st, 64, "%a %b %d %X", tm_time); + strftime(idate, 256, "%a%b%d%T", tm_time); + + fullhour = (!tm_time->tm_min && (tm_time->tm_sec <= (wakeup + 2))); + + day = tm_time->tm_mday; + month = tm_time->tm_mon + 1; +} /* set_time_str */ + +/*****************************************************************************/ + +void logger(int chan) +{ + auto int tries, fd; + register char *p; + auto char s[BUFSIZ]; +#ifdef POSTGRES + auto DbStrIn db_set; +#endif + + + strcpy(s, ctime(&call[chan].connect)); + + if ((p = strchr(s, '\n'))) + *p = 0; + + + /* + .aoce :: -1 -> keine aOC Meldung von VSt, muss berechnet werden + 0 -> free of Charge (0130/...) + >0 -> #of Units + */ + + if (!call[chan].aoc) { + if (!call[chan].dialin) + call[chan].aoce = -1; + + call[chan].pay = 0.0; + } /* if */ + + tries = 0; + + while (((fd = open(logname, O_WRONLY | O_APPEND | O_EXCL)) == -1) && (tries < 1000)) + tries++; + + if ((tries < 1000) && ((flog = fdopen(fd, "a")) == (FILE *)NULL)) + print_msg(PRT_ERR, "Can not open file `%s': %s!\n", logname, strerror(errno)); + else { + fprintf(flog, "%s|%-16s|%-16s|%5d|%10d|%10d|%5d|%c|%3d|%10ld|%10ld|%d.%d|%d|%d|%g|%s|%8.2f|\n", + s + 4, call[chan].num[CALLING], call[chan].num[CALLED], + (int)(call[chan].disconnect - call[chan].connect), + (int)call[chan].duration, (int)call[chan].connect, + call[chan].aoce, call[chan].dialin ? 'I' : 'O', + call[chan].cause, call[chan].ibytes, call[chan].obytes, + LOG_MAJOR_VERSION, LOG_MINOR_VERSION, call[chan].si1, call[chan].si11, + currency_factor, currency, call[chan].pay); + + fclose(flog); + } /* else */ + +#ifdef POSTGRES + db_set.connect = call[chan].connect; + strcpy(db_set.calling, call[chan].num[CALLING]); + strcpy(db_set.called, call[chan].num[CALLED]); + db_set.duration = (int)(call[chan].disconnect - call[chan].connect); + db_set.hduration = (int)call[chan].duration; + db_set.aoce = call[chan].aoce; + db_set.dialin = call[chan].dialin ? 'I' : 'O'; + db_set.cause = call[chan].cause; + db_set.ibytes = call[chan].ibytes; + db_set.obytes = call[chan].obytes; + db_set.version = LOG_MAJOR_VERSION * 100 + LOG_MINOR_VERSION; + db_set.si1 = call[chan].si1; + db_set.si11 = call[chan].si11; + db_set.currency_factor = currency_factor; + strcpy(db_set.currency, currency); + + dbAdd(&db_set); +#endif +} /* logger */ + +/*****************************************************************************/ + +int print_msg(int Level, const char *fmt, ...) +{ + /* ACHTUNG IN DIESER FKT DARF KEIN print_msg() AUFGERUFEN WERDEN !!!!! */ + auto int SLevel = PRT_NOTHING, l; + auto char String[LONG_STRING_SIZE], s[LONG_STRING_SIZE]; + auto va_list ap; + + + va_start(ap, fmt); + l = vsnprintf(String, LONG_STRING_SIZE, fmt, ap); + va_end(ap); + + if (width) { + memcpy(s, String, l + 1); + + if (l > width) { + if (s[l - 1] < ' ') { + s[width] = s[l - 1]; + s[width + 1] = 0; + } + else + s[width] = 0; + } /* if */ + } /* if */ + + SLevel = IS_DEBUG(Level) ? LOG_DEBUG : LOG_INFO; + + if (Level & syslogmessage) + syslog(SLevel, "%s", String); + + if (Level & stdoutput) { + (void)fputs(width ? s : String, stdout); + fflush(stdout); + } /* if */ + + if (Level & message) + if (fcons == NULL) { + fputs(width ? s : String, stderr); + fflush(stderr); + } + else { + fputs(width ? s : String, fcons); + fflush(fcons); + } /* else */ + + if (Level & xinfo) + print_from_server(String); + + if (Level & PRT_LOG) { + fprintf(fprot, "%s %s", stl, String); + + if (synclog) + fflush(fprot); + } /* if */ + + return(0); +} /* print_msg */ + +/*****************************************************************************/ + +int ringer(int chan, int event) +{ + register int i, j, c; + int ProcessStarted = 0; + int old_c = -1; + info_args *infoarg = NULL; + + print_msg(PRT_DEBUG_EXEC, "Got ring event %d on channel %d, number of sockets: %d\n", event, chan, socket_size(sockets)); + + /* chan; Der jeweilige B-Kanal (0 oder 1) + + event: + RING_RING = Nummern wurden uebertragen + RING_CONNECT = Hoerer abgenommen + RING_HANGUP = Hoerer aufgelegt + RING_AOCD = Gebuehrenimpuls (wird noch nicht verwendet) + */ + + if (event != RING_HANGUP) + { + if (event == RING_RING || event == RING_CONNECT) + call[chan].cur_event = event; + } + else + call[chan].cur_event = 0; + + for (i = CALLING; i <= CALLED; i++) { /* fuer beide beteilige Telefonnummern */ + c = call[chan].confentry[i]; + + if (c != -1 && c != old_c) { /* wenn Eintrag in isdnlog.conf gefunden */ + old_c = c; + + for (j = 0;known[c]->infoargs != NULL && (infoarg = known[c]->infoargs[j]) != NULL;j++) + ProcessStarted += Start_Ring(chan,infoarg,event,0); + } + } + + if (ProcessStarted == 0) + { + for (j = 0;start_procs.infoargs != NULL && (infoarg = start_procs.infoargs[j]) != NULL;j++) + ProcessStarted += Start_Ring(chan,infoarg,event,0); + } + + return ProcessStarted; +} /* ringer */ + +/*****************************************************************************/ diff --git a/isdnlog/isdnlog/isdnlog.8 b/isdnlog/isdnlog/isdnlog.8 new file mode 100644 index 00000000..ea0162d0 --- /dev/null +++ b/isdnlog/isdnlog/isdnlog.8 @@ -0,0 +1,75 @@ +.TH ISDNLOG 8 "ISDN Utilities" "AKsoftware" \" -*- nroff -*- +.SH NAME +isdnlog \- Auswertung des ISDN D-Kanal Protokolls +.SH SYNOPSIS +.B isdnlog +[\-asrSVTDPMnNbF2] [\-v verbose-level] [\-p Port] [\-x X-Meldungen] +[\-m stderr-Meldungen] [\-l syslog-Meldungen] [\-t Clock stellen] +[\-c X-Buffer-Size] [\-C Device] [\-w Poll-Rate] [\-h Chargeint-Offset] +[\-W Columns] [\-H Einheiten] [\-f Conffile] [\-L X-Buffer-Size] +[\-A Amtsholung] +/dev/isdnctrlX | - +.SH DESCRIPTION +.BR isdnlog +ermoeglicht in Zusammenhang mit isdn4linux eine vollstaendige +Dekodierung des D-Kanal-Protokolls eines ISDN-Anschlusses. + +Neben einem Protokoll aller Verbindungen kann +.B isdnlog +bei beliebigen Events (Verbindung entstanden, Verbindung beendet usw.) +Aktionen starten. + +Fuer weitere Informationen siehe README +.SS OPTIONS +.TP +.I "\-V" +.B isdnlog +Print version information on standard output then exit successfully. +.SS MELDUNGEN +Bei den Optionen +.I "\-m", +.I "\-l" +oder +.I "\-x" +kann jeweils eine beliebige Kombination aus folgenden Meldungstypen +angegeben werden: +.RE +.sp +.RS +.2i +.ta 1.0i +.nf + 1 PRT_ERR + 2 PRT_WARN + 4 PRT_INFO + 4 PRT_PROG_OUT + 4 PRT_NORMAL + 8 PRT_LOG + 0x10 PRT_SHOWNUMBERS + 0x20 PRT_SHOWAOCD + 0x40 PRT_SHOWCONNECT + 0x80 PRT_SHOWHANGUP + 0x100 PRT_SHOWCAUSE + 0x200 PRT_SHOWTIME + 0x400 PRT_SHOWBYTE + 0x800 PRT_SHOWIMON + 0x1000 PRT_SHOWBEARER + 0x2000 PRT_SHOWTICKS + 0x4000 PRT_DEBUG_GENERAL + 0x8000 PRT_DEBUG_DIAG + 0x10000 PRT_DEBUG_INFO + 0x20000 PRT_DEBUG_EXEC + 0x40000 PRT_DEBUG_BUGS + 0x80000 PRT_DEBUG_DECODE + 0x100000 PRT_DEBUG_RING + 0x200000 PRT_DEBUG_CS + 0x400000 PRT_DEBUG_PROT + 0x800000 PRT_NOTHING +.fi +.RE +.sp +.SH FILES +.BR isdnlog +benoetigt zwingend die Konfigurationsdatei +.BR /etc/isdnlog/isdn.conf +.SH BUGS +Z.Zt. keine bekannt ;-) diff --git a/isdnlog/isdnlog/isdnlog.c b/isdnlog/isdnlog/isdnlog.c new file mode 100644 index 00000000..939ce04f --- /dev/null +++ b/isdnlog/isdnlog/isdnlog.c @@ -0,0 +1,888 @@ +/* $Id: isdnlog.c,v 1.1 1997/03/16 20:58:41 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 + */ + +#define _ISDNLOG_C_ + +#include "isdnlog.h" +#ifdef POSTGRES +#include "postgres.h" +#endif + +/*****************************************************************************/ + + /* Letzte Exit-Nummer: 42 */ + +/*****************************************************************************/ + +static void loop(void); +static void init_variables(int argc, char* argv[]); +static int set_options(int argc, char* argv[]); +static void hup_handler(int isig); +static void exit_on_signal(int Sign); +int print_in_modules(const char *fmt, ...); +static int read_param_file(char *FileName); + +/*****************************************************************************/ + +static char usage[] = "%s: usage: %s [ -%s ] file\n"; +#ifdef Q931 +static char options[] = "av:sp:x:m:l:rt:c:C:w:SVTDPMh:nW:H:f:bL:NqFA:2:"; +#else +static char options[] = "av:sp:x:m:l:rt:c:C:w:SVTDPMh:nW:H:f:bL:NFA:2:"; +#endif +static char msg1[] = "%s: Can't open %s (%s)\n"; +static char *ptty = NULL; +static section *opt_dat = NULL; + +/*****************************************************************************/ + +static void exit_on_signal(int Sign) +{ + print_msg(PRT_NORMAL, "Got signal %d\n", Sign); + + Exit(7); +} /* exit_on_signal */ + +/*****************************************************************************/ + +static void hup_handler(int isig) +{ + print_msg(PRT_INFO, "re-reading %s\n", CONFFILE); + + discardconfig(); + if (readconfig(myname) != 0) + Exit(41); + + signal(SIGHUP, hup_handler); +} /* hup_handler */ + +/*****************************************************************************/ + +static void loop(void) +{ + auto fd_set readmask; + auto fd_set exceptmask; + auto int Cnt; + auto int len; + auto int queuenumber; + auto int NewSocket; + auto int NewClient = 0; + auto struct sockaddr incoming; + auto int Interval; + + + if (xinfo) { + first_descr++; + + if ((NewSocket = listening(port)) >= 0) { + if (add_socket(&sockets, NewSocket)) + Exit(11); + } + else + Exit(17); + } + else + if (add_socket(&sockets, -1)) + Exit(11); + + while (1) { + if (replay) { + + if (trace) + dotrace(); + + if (!morectrl(0)) + break; + } + else { + FD_ZERO(&readmask); + FD_ZERO(&exceptmask); + + queuenumber = socket_size(sockets); + + if (NewClient) { + /* Damit sich der neue Client anmelden kann, ohne + das was anderes dazwischen funkt ... */ + FD_SET(sockets[NewClient].descriptor, &readmask); + NewClient = 0; + } + else { + for (Cnt = 0; Cnt < queuenumber; Cnt++) + FD_SET(sockets[Cnt].descriptor, &readmask); + + for (Cnt = first_descr; Cnt < queuenumber; Cnt++) + FD_SET(sockets[Cnt].descriptor, &exceptmask); + } /* else */ + + if (newcps && ((ifo[0].u & ISDN_USAGE_MASK) + (ifo[1].u & ISDN_USAGE_MASK))) + Interval = wakeup; /* AK:06-Jun-96 */ + else + Interval = 0; + + while ((Cnt = select(FD_SETSIZE, &readmask, NULL, &exceptmask, Get_Interval(Interval))) < 0 && (errno == EINTR)); + + if ((Cnt < 0) && (errno != EINTR)) { /* kill -HUP ausgeschlossen */ + print_msg(PRT_DEBUG_CS, "Error select: %s\n", strerror(errno)); + Exit(12); + } /* if */ + + processrate(); + + if (!Cnt) /* Abbruch durch Timeout -> Programm starten */ + Start_Interval(); + + now(); + + for (Cnt = first_descr; Cnt < socket_size(sockets); Cnt++) { + if (FD_ISSET(sockets[Cnt].descriptor, &exceptmask)) { + if (sockets[Cnt].fp == NULL) { + disconnect_client(Cnt); + break; + } + else { + int event = sockets[Cnt].call_event; + int cur_call = sockets[Cnt].chan; + info_args *infoarg = sockets[Cnt].info_arg; + + Ring(NULL, NULL, Cnt, 0); + + if (infoarg->flag & RING_LOOP && call[cur_call].cur_event == event) + Start_Process(cur_call, infoarg, event); + + break; + } /* else */ + } + else if (FD_ISSET(sockets[Cnt].descriptor, &readmask)) + if (sockets[Cnt].fp == NULL) { + eval_message(Cnt); + /* Arbeite immer nur ein Client ab, du weisst nicht, ob der + naechste noch lebt */ + break; + } + else + Print_Cmd_Output(Cnt); + } /* for */ + + if (xinfo && FD_ISSET(sockets[IN_PORT].descriptor, &readmask)) { + len = sizeof(incoming); + + if ((NewSocket = accept(sockets[IN_PORT].descriptor, &incoming, &len)) == -1) + print_msg(PRT_DEBUG_CS, "Error accept: %s\n", strerror(errno)); + else { + if (add_socket(&sockets, NewSocket)) + Exit(13); + + queuenumber = socket_size(sockets); + + sockets[queuenumber - 1].f_hostname = GetHostByAddr(&incoming); + sockets[queuenumber - 1].waitstatus = WF_ACC; + + NewClient = queuenumber - 1; + } /* else */ + } + else if (FD_ISSET(sockets[ISDNINFO].descriptor, &readmask)) + moreinfo(); + else if (FD_ISSET(sockets[ISDNCTRL].descriptor, &readmask)) + (void)morectrl(0); + else if (FD_ISSET(sockets[ISDNCTRL2].descriptor, &readmask)) + (void)morectrl(1); + } /* else */ + } /* while */ +} /* loop */ + +/*****************************************************************************/ + +int print_in_modules(const char *fmt, ...) +{ + auto va_list ap; + auto char String[LONG_STRING_SIZE]; + + + va_start(ap, fmt); + (void)vsnprintf(String, LONG_STRING_SIZE, fmt, ap); + va_end(ap); + + return print_msg(PRT_ERR, "%s", String); +} /* print_in_modules */ + +/*****************************************************************************/ + +static void init_variables(int argc, char* argv[]) +{ + flog = NULL; /* /var/adm/isdn.log */ + fcons = NULL; /* /dev/ttyX (or stderr) */ + fprot = NULL; /* /tmp/isdnctrl0 */ + isdnctrl = NULL; + + first_descr = FIRST_DESCR; + message = PRT_NORMAL | PRT_WARN | PRT_ERR | PRT_INFO; + syslogmessage = PRT_NOTHING; + xinfo = 0; + sound = 0; + trace = 0; + isdaemon = 0; + imon = 0; + port = 0; + wakeup = 1; + fullhour = 0; + tty_dv = 0; + net_dv = 0; + inf_dv = 0; + settime = 0; + replay = 0; + replaydev = 0; + verbose = 0; + synclog = 0; + any = 1; + stdoutput = 0; + allflags = 0; + newcps = 0; + chans = 2; + hupctrl = 0; + hup1 = hup2 = 0; + bilingual = 0; + mcalls = MAX_CALLS_IN_QUEUE; + xlog = MAX_PRINTS_IN_QUEUE; + + sockets = NULL; + allflags = 0; + known = NULL; + + opt_dat = NULL; + newline = 1; + width = 0; + watchdog = 0; + use_new_config = 1; +#ifdef Q931 + q931dmp = 0; +#endif + CityWeekend = 0; + + sprintf(mlabel, "%%s%s %%s%%s", "%e.%b %T %I"); + *amtsholung = 0; + dual = 0; + + myname = argv[0]; + myshortname = basename(myname); +} /* init_variables */ + +/*****************************************************************************/ + +#ifdef Q931 +static void traceoptions() +{ + q931dmp++; + use_new_config = 0; + replay++; + port = 20012; +} /* traceoptions */ +#endif + + +int set_options(int argc, char* argv[]) +{ + register int c; + register char *p; + auto int defaultmsg = PRT_NORMAL | PRT_WARN | PRT_ERR | PRT_INFO; + auto int newmessage = 0; + + + if (!message) + message = defaultmsg; + +#ifdef Q931 + if (!strcmp(myshortname, "trace")) + traceoptions(); +#endif + + while ((c = getopt(argc, argv, options)) != EOF) + switch (c) { + case 'V' : print_version(myshortname); + exit(0); + break; + + case 'v' : verbose = strtol(optarg, NIL, 0); + break; + + case 's' : synclog++; + break; + + case 'p' : port = strtol(optarg, NIL, 0); + break; + + case 'm' : newmessage = strtol(optarg, NIL, 0); + + if (!newmessage) { + newmessage = defaultmsg; + printf("%s: WARNING: \"-m\" Option now requires numeric Argument\n", myshortname); + } /* if */ + break; + + case 'l' : syslogmessage = strtol(optarg, NIL, 0); + + if (!syslogmessage) { + syslogmessage = defaultmsg; + printf("%s: WARNING: \"-l\" Option requires numeric Argument\n", myshortname); + } /* if */ + break; + + case 'x' : xinfo = strtol(optarg, NIL, 0); + + if (!xinfo) + xinfo = defaultmsg; + break; + + case 'r' : replay++; + break; + + case 't' : settime = strtol(optarg, NIL, 0); /* 1=once, 2=ever */ + break; + + case 'C' : ptty = strdup(optarg); + break; + + case 'M' : imon++; + break; + + case 'S' : sound++; + break; + + case 'w' : wakeup = strtol(optarg, NIL, 0); + break; + + case 'D' : isdaemon++; + break; + + case 'T' : trace++; + break; + + case 'a' : any = 0; + break; + + case 'P' : stdoutput = PRT_LOG; + break; + + case 'h' : hupctrl++; + + if ((p = strchr(optarg, ':'))) { + *p = 0; + hup1 = atoi(optarg); + hup2 = atoi(p + 1); + } + else + printf("%s: WARNING: \"-h\" Option requires two Arguments\n", myshortname); + break; + + case 'b' : bilingual++; + break; + + case 'c' : mcalls = strtol(optarg, NIL, 0); + break; + + case 'L' : xlog = strtol(optarg, NIL, 0); + break; + + case 'f' : read_param_file(optarg); + break; + + case 'n' : newline = 0; + break; + + case 'W' : width = strtol(optarg, NIL, 0); + break; + + case 'H' : watchdog = strtol(optarg, NIL, 0); + break; + + case 'N' : use_new_config = 0; + break; + +#ifdef Q931 + case 'q' : traceoptions(); + break; +#endif + + case 'F' : CityWeekend++; + break; + + case 'A' : strcpy(amtsholung, optarg); + break; + + case '2' : dual = strtol(optarg, NIL, 0); + break; + + case '?' : printf(usage, myshortname, myshortname, options); + exit(1); + } /* switch */ + + if (newmessage) + message = newmessage; + + if (trace && isdaemon) { + printf("%s","Can not trace and daemon together!\n"); + exit(20); + } /* if */ + + if (stdoutput && isdaemon) { + printf("%s","Can not write to stdout as daemon!\n"); + exit(21); + } /* if */ + + if (isdaemon) { + if (syslogmessage == -1) + syslogmessage = defaultmsg; + + switch (fork()) { + case -1 : print_msg(PRT_ERR,"%s","Can not start fork()!\n"); + Exit(18); + break; + case 0 : break; + + default : _exit(0); + } + + /* Wenn message nicht explixit gesetzt wurde, dann gibt es beim daemon auch + kein Output auf der Console/ttyx */ + + if (!newmessage && ptty == NULL) + message = 0; + } /* if */ + + allflags = syslogmessage | message | xinfo | stdoutput; + + return optind; +} /* set_options */ + +/*****************************************************************************/ + +static int read_param_file(char *FileName) +{ + register char *p; + auto section *SPtr; + auto entry *Ptr; + + + if (opt_dat != NULL) + { + print_msg(PRT_ERR,"Can not more than one option file (file %s)!\n", FileName); + return -1; + } + + if ((SPtr = opt_dat = read_file(NULL, FileName, 0)) == NULL) + return -1; + + while (SPtr != NULL) + { + if (!strcmp(SPtr->name,CONF_SEC_OPT)) + { + Ptr = SPtr->entries; + + while (Ptr != NULL) + { + if (!strcmp(Ptr->name,CONF_ENT_DEV)) + isdnctrl = Ptr->value; + else + if (!strcmp(Ptr->name,CONF_ENT_LOG)) + verbose = (int)strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_FLUSH)) + synclog = toupper(*(Ptr->value)) == 'Y'?1:0; + else + if (!strcmp(Ptr->name,CONF_ENT_PORT)) + port = strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_STDOUT)) + message = strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_SYSLOG)) + syslogmessage = strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_XISDN)) + { + xinfo = strtol(Ptr->value, NIL, 0); + } + else + if (!strcmp(Ptr->name,CONF_ENT_TIME)) + settime = (int)strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_CON)) + ptty = Ptr->value; + else + if (!strcmp(Ptr->name,CONF_ENT_START)) + sound = toupper(*(Ptr->value)) == 'Y'?1:0; + else + if (!strcmp(Ptr->name,CONF_ENT_THRU)) + wakeup = strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_DAEMON)) + isdaemon = toupper(*(Ptr->value)) == 'Y'?1:0; + else + if (!strcmp(Ptr->name,CONF_ENT_MON)) + imon = toupper(*(Ptr->value)) == 'Y'?1:0; + else + if (!strcmp(Ptr->name,CONF_ENT_PIPE)) + stdoutput = toupper(*(Ptr->value)) == 'Y'?PRT_LOG:0; + else + if (!strcmp(Ptr->name,CONF_ENT_MON)) + imon = toupper(*(Ptr->value)) == 'Y'?1:0; + else + if (!strcmp(Ptr->name,CONF_ENT_HANGUP)) { + hupctrl++; + if ((p = strchr(Ptr->value, ':'))) { + *p = 0; + hup1 = atoi(Ptr->value); + hup2 = atoi(p + 1); + } /* if */ + } + else + if (!strcmp(Ptr->name,CONF_ENT_BI)) + bilingual = toupper(*(Ptr->value)) == 'Y'?1:0; + else + if (!strcmp(Ptr->name,CONF_ENT_CALLS)) + mcalls = strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_XLOG)) + xlog = strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_NL)) + newline = toupper(*(Ptr->value)) == 'Y'?1:0; + else + if (!strcmp(Ptr->name,CONF_ENT_WIDTH)) + width = (int)strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_CW)) + CityWeekend = toupper(*(Ptr->value)) == 'Y'?1:0; + else + if (!strcmp(Ptr->name,CONF_ENT_DUAL)) + dual = (int)strtol(Ptr->value, NIL, 0); + else + if (!strcmp(Ptr->name,CONF_ENT_AMT)) + strcpy(amtsholung,Ptr->value); + else +#ifdef Q931 + if (!strcmp(Ptr->name,CONF_ENT_Q931)) + { + if(toupper(*(Ptr->value)) == 'Y') + traceoptions(); + } + else +#endif + if (!strcmp(Ptr->name,CONF_ENT_WD)) + watchdog = (int)strtol(Ptr->value, NIL, 0); + else + print_msg(PRT_ERR,"Error: Invalid entry `%s'!\n",Ptr->name); + + Ptr = Ptr->next; + } + } + else + print_msg(PRT_ERR,"Error: Invalid section `%s'!\n",SPtr->name); + + SPtr = SPtr->next; + } + + return 0; +} + +/*****************************************************************************/ + +static void restoreCharge() +{ + register int i, j, n = 0, nx = max(knowns, 1); + auto FILE *f; + auto char fn[BUFSIZ]; + + typedef struct { + char who[16]; + int day; + double charge; + double scharge; + int month; + double online; + double sonline; + double bytes; + double sbytes; + } CHARGE; + + auto CHARGE *charge; + + + + if ((charge = (CHARGE *)malloc(sizeof(CHARGE) * nx)) != (CHARGE *)NULL) { + + sprintf(fn, "%s/%s", confdir(), CHARGEFILE); + + if ((f = fopen(fn, "r")) != (FILE *)NULL) { + + while (fscanf(f, "%s %d %lg %lg %d %lg %lg %lg %lg\n", + charge[n].who, &charge[n].day, &charge[n].charge, &charge[n].scharge, + &charge[n].month, &charge[n].online, &charge[n].sonline, + &charge[n].bytes, &charge[n].sbytes) == 9) { + + n++; + + if (n == nx) { + nx++; + + if ((charge = (CHARGE *)realloc((void *)charge, sizeof(CHARGE) * nx)) == (CHARGE *)NULL) { + fclose(f); + return; + } /* if */ + } /* if */ + + } /* while */ + + if (n) { + for (i = 0; i < knowns; i++) + for (j = 0; j < n; j++) + if (!strcmp(known[i]->who, charge[j].who)) { + known[i]->day = charge[j].day; + known[i]->charge = charge[j].charge; + known[i]->scharge = charge[j].scharge; + known[i]->month = charge[j].month; + known[i]->online = charge[j].online; + known[i]->sonline = charge[j].sonline; + known[i]->bytes = charge[j].bytes; + known[i]->sbytes = charge[j].sbytes; + + break; + } /* if */ + } /* if */ + + fclose(f); + } /* if */ + + free(charge); + } /* if */ +} /* restoreCharge */ + +/*****************************************************************************/ + +int main(int argc, char *argv[], char *envp[]) +{ + register char *p; + register int i, res = 0; + auto int lastarg; + auto char fn[BUFSIZ]; +#ifdef TESTCENTER + extern void test_center(void); +#endif + + + if (getuid() != 0) { + fprintf(stderr,"Can only run as root!\n"); + exit(35); + } /* if */ + + set_print_fct_for_lib(print_in_modules); + init_variables(argc, argv); + + lastarg = set_options(argc,argv); + + if (lastarg < argc) + isdnctrl = argv[lastarg]; + + if (isdnctrl == NULL) { + print_msg(PRT_ERR,"There is no valid input device!\n"); + Exit(31); + } + else { + p = strrchr(isdnctrl, C_SLASH); + sprintf(pidfile, "%s.%s", myshortname, p ? p + 1 : isdnctrl); + + if (add_socket(&sockets, -1) || /* reserviert fuer isdnctrl */ + add_socket(&sockets, -1) || /* reserviert fuer isdnctrl2 */ + add_socket(&sockets, -1) ) /* reserviert fuer isdninfo */ + Exit(19); + + if (replay) { + verbose = 0; + synclog = 0; + settime = 0; + xinfo = 0; + *isdnctrl2 = 0; + } + else { + if (strcmp(isdnctrl, "-") && dual) { + strcpy(isdnctrl2, isdnctrl); + p = strrchr(isdnctrl2, 0) - 1; + + if (!isdigit(*p)) /* "/dev/isdnctrl" */ + strcat(++p, "0"); + + if (isdigit(*(p - 1))) + p--; + + i = atoi(p); + + sprintf(p, "%d", i + 2); + } + else + *isdnctrl2 = 0; + + } /* else */ + + strcpy((char *)logname, LOGFILE); + + if (replay) + strcat((char *)logname, ".rep"); + + openlog(myshortname, LOG_NDELAY, LOG_DAEMON); + +#ifdef TESTCENTER + test_center(); +#endif + + if (xinfo && read_user_access()) + Exit(22); + + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, hup_handler); + signal(SIGINT, exit_on_signal); + signal(SIGTERM, exit_on_signal); + signal(SIGALRM, exit_on_signal); + signal(SIGQUIT, exit_on_signal); + signal(SIGILL, exit_on_signal); + + if (!(allflags & PRT_DEBUG_GENERAL)) + signal(SIGSEGV, exit_on_signal); + + sockets[ISDNCTRL].descriptor = !strcmp(isdnctrl, "-") ? fileno(stdin) : open(isdnctrl, O_RDONLY | O_NONBLOCK); + if (*isdnctrl2) + sockets[ISDNCTRL2].descriptor = open(isdnctrl2, O_RDONLY | O_NONBLOCK); + + if ((sockets[ISDNCTRL].descriptor >= 0) && (!*isdnctrl2 || (sockets[ISDNCTRL2].descriptor >= 0))) { + + if (ptty != NULL) + fcons = fopen(ptty, "a"); + + if ((ptty == NULL) || (fcons != (FILE *)NULL)) { + if (verbose) { + if ((p = strrchr(isdnctrl, '/'))) + p++; + else + p = argv[lastarg]; + + sprintf(fn, "%s/%s", TMPDIR, p); + } /* if */ + + if (!verbose || ((fprot = fopen(fn, "a")) != (FILE *)NULL)) { + + for (i = 0; i < MAXCHAN; i++) + clearchan(i, 1); + +#ifdef Q931 + if (q931dmp) { + mymsns = 3; + mycountry = "+49"; + myarea = "6408"; + currency = NULL; + dual = 1; + chargemax = 0.0; + connectmax = 0.0; + bytemax = 0.0; + connectmaxmode = 0; + bytemaxmode = 0; + knowns = retnum = 0; + known = (KNOWN **)NULL; + start_procs.infoargs = NULL; + start_procs.flags = 0; + + setDefaults(); + } + else +#endif + { + if (readconfig(myshortname) < 0) + Exit(30); + + restoreCharge(); + } /* if */ + + if (!replay) { + switch (i = create_runfile(pidfile)) { + case 0 : break; + + case -1 : print_msg(PRT_ERR,"Can not open pid file: %s!\n", strerror(errno)); + Exit(36); + + default : print_msg(PRT_ERR,"Another %s is running with pid %d!\n", myshortname, i); + Exit(37); + } /* switch */ + } /* if */ + + if (replay || ((sockets[ISDNINFO].descriptor = open(INFO, O_RDONLY | O_NONBLOCK)) >= 0)) { + + now(); + +#ifdef Q931 + if (!q931dmp) +#endif + print_msg(PRT_NORMAL, "%s Version %s loaded\n", myshortname, VERSION); + +#ifdef POSTGRES + dbOpen(); +#endif + loop(); + + if (sockets[ISDNINFO].descriptor >= 0) + close(sockets[ISDNINFO].descriptor); + } + else { + print_msg(PRT_ERR, msg1, myshortname, INFO, strerror(errno)); + res = 7; + } /* else */ + + if (verbose) + fclose(fprot); + } + else { + print_msg(PRT_ERR, msg1, myshortname, fn, strerror(errno)); + res = 5; + } /* else */ + + if (ptty != NULL) + fclose(fcons); + } + else { + print_msg(PRT_ERR, msg1, myshortname, fn, strerror(errno)); + res = 3; + } /* else */ + + if (strcmp(isdnctrl, "-")) + close(sockets[ISDNCTRL].descriptor); + if (*isdnctrl2) + close(sockets[ISDNCTRL2].descriptor); + } + else { + print_msg(PRT_ERR, msg1, myshortname, isdnctrl, strerror(errno)); + res = 2; + } /* else */ + +#ifdef Q931 + if (!q931dmp) +#endif + print_msg(PRT_NORMAL, "%s Version %s exiting\n", myshortname, VERSION); + + } /* else */ + + Exit(res); + return(res); +} /* main */ diff --git a/isdnlog/isdnlog/isdnlog.h b/isdnlog/isdnlog/isdnlog.h new file mode 100644 index 00000000..c1c6b3bf --- /dev/null +++ b/isdnlog/isdnlog/isdnlog.h @@ -0,0 +1,334 @@ +/* $Id: isdnlog.h,v 1.1 1997/03/16 20:58:43 luethje Exp $ + * + * ISDN accounting for isdn4linux. + * + * 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: isdnlog.h,v $ + * Revision 1.1 1997/03/16 20:58:43 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/11 18:21:43 akool + * isdnctrl2 implemented + * + * Revision 2.6.30 1997/01/28 16:49:43 akool + * LOG_MAJOR_VERSION auf 3 erhoeht + * + * Revision 2.6.26 1997/01/18 12:56:43 akool + * huptimeofs neu definiert + * + * Revision 2.3.4 1996/04/05 11:30:43 akool + * New ibytes/obytes ioctl() from Fritz implemented + * USERFILE + * + * Revision 2.23 1996/03/14 18:07:43 akool + * + * Revision 2.15 1996/02/21 20:14:43 akool + * + * Revision 2.12 1996/02/13 20:08:43 root + * Nu geht's (oder?) + * + * Revision 2.12 1996/02/13 20:08:43 root + * Nu geht's (oder?) + * + * Revision 1.2 1996/02/13 20:05:28 root + * so nun gehts + * + * Revision 1.1 1996/02/13 14:28:14 root + * Initial revision + * + * Revision 2.05 1995/02/11 17:10:16 akool + * + */ + +/****************************************************************************/ + +#ifndef _ISDNLOG_H_ +#define _ISDNLOG_H_ + +/****************************************************************************/ + +#define PUBLIC extern + +/****************************************************************************/ + +#include +#include "socket.h" + +/****************************************************************************/ + +#define LOG_MAJOR_VERSION 3 +#define LOG_MINOR_VERSION 0 + +/****************************************************************************/ + +#define MAX_CALLS_IN_QUEUE 100 +#define MAX_PRINTS_IN_QUEUE 500 + +/****************************************************************************/ + +#define BROADCAST 0x7f + +/****************************************************************************/ + +#define ISDNCTRL 0 +#define ISDNCTRL2 1 +#define ISDNINFO 2 +#define IN_PORT 3 + +#define FIRST_DESCR 3 + +/****************************************************************************/ + +#define PRT_ERR 1 +#define PRT_WARN 2 +#define PRT_INFO 4 +#define PRT_PROG_OUT 4 +#define PRT_NORMAL 4 +#define PRT_LOG 8 +#define PRT_SHOWNUMBERS 0x10 +#define PRT_SHOWAOCD 0x20 +#define PRT_SHOWCONNECT 0x40 +#define PRT_SHOWHANGUP 0x80 +#define PRT_SHOWCAUSE 0x100 +#define PRT_SHOWTIME 0x200 +#define PRT_SHOWBYTE 0x400 +#define PRT_SHOWIMON 0x800 +#define PRT_SHOWBEARER 0x1000 +#define PRT_SHOWTICKS 0x2000 +#define PRT_DEBUG_GENERAL 0x4000 +#define PRT_DEBUG_DIAG 0x8000 +#define PRT_DEBUG_INFO 0x10000 +#define PRT_DEBUG_EXEC 0x20000 +#define PRT_DEBUG_BUGS 0x40000 +#define PRT_DEBUG_DECODE 0x80000 +#define PRT_DEBUG_RING 0x100000 +#define PRT_DEBUG_CS 0x200000 +#define PRT_DEBUG_PROT 0x400000 +#define PRT_NOTHING 0x800000 + +#define IS_DEBUG(VALUE) (VALUE >= PRT_DEBUG_GENERAL && VALUE < PRT_NOTHING) + +/****************************************************************************/ + +#define AOC_INITIAL 0 +#define AOCDCurrency 1 +#define AOCDChargingUnit 2 +#define AOCECurrency 3 +#define AOCEChargingUnit 4 +#define AOCDCurrencyInfo 5 +#define AOCECurrencyInfo 6 +#define AOCDChargingUnitInfo 7 +#define AOCEChargingUnitInfo 8 +#define RecordedCurrency 9 +#define TypeOfChargingInfo 10 +#define Currency 11 +#define Amount 12 +#define CurrencyAmount 13 +#define Multiplier 14 +#define RecordedUnitsList 15 +#define RecordedUnits 16 +#define NumberOfUnits 17 + +/****************************************************************************/ + +#define VERBOSE_HEX 1 /* only "HEX:" messages from /dev/isdnctrl */ +#define VERBOSE_CTRL 2 /* any message from /dev/isdnctrl */ +#define VERBOSE_INFO 4 /* any message from /dev/isdninfo */ +#define VERBOSE_RATE 8 /* any message from ioctl(IIOCGETCPS) */ + +/****************************************************************************/ + +#ifndef USERFILE +#define USERFILE "isdnlog.users" +#endif + +/****************************************************************************/ + +typedef struct _interval { + int event; + int chan; + info_args *infoarg; + time_t next_start; + struct _interval *next; +} interval; + +/****************************************************************************/ + +#ifdef _ISDNLOG_C_ +#define _EXTERN +socket_queue *sockets = NULL; +#else +#define _EXTERN extern +extern socket_queue *sockets; +#endif + +_EXTERN FILE *flog; /* /var/adm/isdn.log */ +_EXTERN FILE *fcons; /* /dev/ttyX (or stderr) */ +_EXTERN FILE *fprot; /* /tmp/isdnctrl0 */ + +_EXTERN int first_descr; +_EXTERN int chan; +_EXTERN int message; +_EXTERN int syslogmessage; +_EXTERN int xinfo; +_EXTERN int sound; +_EXTERN int trace; +_EXTERN int isdaemon; +_EXTERN int imon; +_EXTERN int port; +_EXTERN int wakeup; +_EXTERN int fullhour; +_EXTERN int tty_dv; +_EXTERN int net_dv; +_EXTERN int inf_dv; +_EXTERN clock_t tt; +_EXTERN clock_t tto; +_EXTERN char st[FNSIZE]; +_EXTERN char stl[FNSIZE]; +_EXTERN int settime; +_EXTERN int replay; +_EXTERN int replaydev; +_EXTERN int verbose; +_EXTERN int synclog; +_EXTERN int any; +_EXTERN int stdoutput; +_EXTERN int allflags; +_EXTERN int newcps; +_EXTERN int chans; +_EXTERN int bilingual; +_EXTERN int hupctrl; +_EXTERN int hup1; +_EXTERN int hup2; +_EXTERN int mcalls; +_EXTERN int xlog; +_EXTERN char *myname, *myshortname; +_EXTERN int newline; +_EXTERN int width; +_EXTERN int watchdog; +_EXTERN char *isdnctrl; +_EXTERN char isdnctrl2[FNSIZE]; +_EXTERN char logname[FNSIZE]; +_EXTERN char pidfile[SHORT_STRING_SIZE]; + +_EXTERN IFO ifo[ISDN_MAX_CHANNELS]; +_EXTERN IO io[ISDN_MAX_CHANNELS]; + +#undef _EXTERN + +/****************************************************************************/ + +#ifdef _PROCESSOR_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN void dotrace(void); +_EXTERN int morectrl(int card); +_EXTERN void moreinfo(void); +_EXTERN void processrate(void); +_EXTERN void clearchan(int chan, int total); + +#undef _EXTERN + +/****************************************************************************/ + +#ifdef _FUNCTIONS_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +#define Exit(a) _Exit(__FILE__,__LINE__,a) + +_EXTERN void _Exit(char *File, int Line, int RetCode); +_EXTERN int print_msg(int Level, const char *fmt, ...); +_EXTERN int Change_Channel(int old_channel, int new_channel); +_EXTERN void set_time_str(void); +_EXTERN void now(void); +_EXTERN void logger(int chan); +_EXTERN int ringer(int chan, int event); + +#undef _EXTERN + +/****************************************************************************/ + +#ifdef _SERVER_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN int message_from_server(CALL *call, int chan); +_EXTERN int eval_message(int sock); +_EXTERN int start_server(int port); +_EXTERN int listening(int port); +_EXTERN int print_from_server(char *String); +_EXTERN int change_channel(int old_chan, int new_chan); +_EXTERN int disconnect_client(int sock); + +#undef _EXTERN + +/****************************************************************************/ + +#ifdef _START_PROG_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN int Ring(info_args *, char *[], int, int); +_EXTERN void Alarm(void); +_EXTERN int CheckTime(char *); +_EXTERN int Print_Cmd_Output( int sock ); +_EXTERN int Get_Sock_From_Call_And_Info_Args( int chan, info_args *Ptr, int Cnt ); +_EXTERN int Get_Sock_From_Call( int chan, int Cnt ); +_EXTERN int Get_Sock_From_Info_Args( info_args *Ptr, int Cnt ); +_EXTERN int Condition_Changed( int condition, int flag ); +_EXTERN const char *Set_Ringer_Flags( int condtion, int InOut ); +_EXTERN int Start_Ring(int chan, info_args *infoarg, int event, int intervalflag); +_EXTERN int Start_Process(int chan, info_args *infoarg, int event); +_EXTERN int New_Interval(int chan, info_args *infoarg, int event); +_EXTERN int Del_Interval(int chan, info_args *infoarg); +_EXTERN struct timeval *Get_Interval(int Sec); +_EXTERN int Change_Channel_Ring( int old_channel, int new_channel); +_EXTERN int Start_Interval(void); + +#undef _EXTERN + +/****************************************************************************/ + +#ifdef _USER_ACCESS_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN int read_user_access( void ); +_EXTERN int write_user_access( void ); +_EXTERN int user_has_access(char *User, char *Host); +_EXTERN int User_Get_Message(char *User, char *Host, char* mymsn, int Flag); +_EXTERN const char *userfile(void); + +#undef _EXTERN + +/****************************************************************************/ + +#endif /* _ISDNLOG_H_ */ diff --git a/isdnlog/isdnlog/messages.c b/isdnlog/isdnlog/messages.c new file mode 100644 index 00000000..3f5da8d4 --- /dev/null +++ b/isdnlog/isdnlog/messages.c @@ -0,0 +1,334 @@ +/* $Id: messages.c,v 1.1 1997/03/16 20:58:44 luethje Exp $ + * + * ISDN accounting for isdn4linux. (Q.931-Messages) + * + * 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 + */ + +#define _MESSAGES_C_ + +#include "isdnlog.h" + + +static char *MessageType[] = { /* According to Table 4-2/Q.931 */ + "\x01 ALERTING", + "\x02 CALL PROCEEDING", + "\x03 PROGRESS", + "\x05 SETUP", + "\x07 CONNECT", + "\x0d SETUP ACKNOWLEDGE", + "\x0f CONNECT ACKNOWLEDGE", + "\x20 USER INFORMATION", + "\x21 SUSPEND REJECT", + "\x22 RESUME REJECT", + "\x24 HOLD", + "\x25 SUSPEND", + "\x26 RESUME", + "\x28 HOLD ACKNOWLEDGE", /* Makeln Acknowledge */ + "\x2d SUSPEND ACKNOWLEDGE", + "\x2e RESUME ACKNOWLEDGE", + "\x30 HOLD REJECT", + "\x31 RETRIEVE", + "\x33 RETRIEVE ACKNOWLEDGE", /* Makeln Eesume Acknowledge */ + "\x37 RETRIEVE REJECT", + "\x45 DISCONNECT", + "\x46 RESTART", + "\x4d RELEASE", + "\x4e RESTART ACKNOWLEDGE", + "\x5a RELEASE COMPLETE", + "\x60 SEGMENT", + "\x62 FACILITY", + "\x64 REGISTER", + "\x6e NOTIFY", + "\x75 STATUS ENQUIRY", + "\x79 CONGESTION CONTROL", + "\x7b INFORMATION", + "\x7d STATUS", + NULL }; + +static char *MessageType1TR6[] = { + "\x61 REGister INDication", + "\x62 CANCel INDication", + "\x63 FACility STAtus", + "\x64 STAtus ACKnowledge", + "\x65 STAtus REJect", + "\x66 FACility INFormation", + "\x67 INFormation ACKnowledge", + "\x68 INFormation REJect", + "\x75 CLOSE", + "\x77 CLOse ACKnowledge", + + "\x00 ESCape", + "\x01 ALERT", + "\x02 CALL SENT", + "\x07 CONNect", + "\x0f CONNect ACKnowledge", + "\x05 SETUP", + "\x0d SETUP ACKnowledge", + "\x26 RESume", + "\x2e RESume ACKnowledge", + "\x22 RESume REJect", + "\x25 SUSPend", + "\x2d SUSPend ACKnowledge", + "\x21 SUSPend REJect", + "\x20 USER INFO", + "\x40 DETach", + "\x45 DISConnect", + "\x4d RELease", + "\x5a RELease ACKnowledge", + "\x6e CANCel ACKnowledge", + "\x67 CANCel REJect", + "\x69 CONgestion CONtrol", + "\x60 FACility", + "\x68 FACility ACKnowledge", + "\x66 FACility CANcel", + "\x64 FACility REGister", + "\x65 FACility REJect", + "\x6d INFOrmation", + "\x6c REGister ACKnowledge", + "\x6f REGister REJect", + "\x63 STATus", + NULL }; + + +static char *InformationElement[] = { + "\x00 Segmented message", + "\x04 bearer service indication", /* Bearer capability */ + "\x08 Cause", + "\x0c Connected address (obsolete)", + "\x0d Extended facility information element identifier", + "\x10 Call identity", + "\x14 Call state", + "\x18 Channel identification", + "\x19 Data link connection identifier", + "\x1c Facility information element identifier", /* Facility */ + "\x1e Progress indicator", + "\x20 Network-specific facilities", + "\x24 Terminal capabilities (obsolete)", + "\x27 Notification indicator", + "\x28 Display", + "\x29 Date/Time", + "\x2c Keypad facility", + "\x34 Signal", + "\x40 Information rate", + "\x42 End-to-end transit delay", + "\x43 Transit delay selection and indication", + "\x44 Packet layer binary parameters", + "\x45 Packet layer window size", + "\x46 Packet size", + "\x47 Closed user group", + "\x4a Reverse charge indication", + "\x4c COLP", + "\x6c Calling party number", + "\x6d Calling party subaddress", + "\x70 Called party number", + "\x71 Called party subaddress", + "\x74 Redirecting number", + "\x78 Transit network selection", + "\x79 Restart indicator", + "\x7c Low layer compatibility", + "\x7d High layer compatibility", + "\x7e User-user", + "\x7f Escape for extension", + NULL }; + +static char *InformationElement1TR6[] = { + "\x08 Cause", + "\x0c Connecting Address", + "\x10 Call IDentity", + "\x18 Channel IDentity", + "\x20 Network Specific Facility", + "\x28 Display", + "\x2c Keypad", + "\x6c Origination Address", + "\x70 Destination Address", + "\x7e User Info", + + "\x01 Service Indicator", + "\x02 Charging Information", + "\x03 Date", + "\x05 Facility Select", + "\x06 Facility Status", + "\x07 Status Called", + "\x08 Additional Transmission Attributes", + NULL }; + +static char *CauseValue[] = { /* According to Q.850 */ + "\x01 Unallocated (unassigned) number", + "\x02 No route to specified transit network", + "\x03 No route to destination", + "\x04 Send special information tone", + "\x05 Misdialled trunk prefix", + "\x06 Channel unacceptable", + "\x07 Channel awarded and being delivered in an established channel", + "\x08 Preemption", + "\x09 Preemption - circuit reserved for reuse", + "\x10 Normal call clearing", + "\x11 User busy", + "\x12 No user responding", + "\x13 No answer from user (user alerted)", + "\x14 Subscriber absent", + "\x15 Call rejected", + "\x16 Number changed", + "\x1a non-selected user clearing", + "\x1b Destination out of order", + "\x1c Invalid number format (address incomplete)", + "\x1d Facility rejected", + "\x1e Response to Status enquiry", + "\x1f Normal, unspecified", + "\x22 No circuit/channel available", + "\x26 Network out of order", + "\x27 Permanent frame mode connection out-of-service", + "\x28 Permanent frame mode connection operational", + "\x29 Temporary failure", + "\x2a Switching equipment congestion", + "\x2b Access information discarded", + "\x2c Requested circuit/channel not available", + "\x2e Precedence call blocked", + "\x2f Resource unavailable, unspecified", + "\x31 Quality of service unavailable", + "\x32 Requested facility not subscribed", + "\x35 Outgoing calls barred within CUG", + "\x37 Incoming calls barred within CUG", + "\x39 Bearer capability not authorized", + "\x3a Bearer capability not presently available", + "\x3e Inconsistency in designated outgoing access information and subscriber class", + "\x3f Service or option not available, unspecified", + "\x41 Bearer capability not implemented", + "\x42 Channel type not implemented", + "\x43 Requested facility not implemented", + "\x44 Only restricted digital information bearer capability is available", + "\x45 angeforderte Eigenschaft nicht implementiert", + "\x46 Nur beschraenkte digitale Information ueber Uebermittlungsfunktion ist verfuegbar", + "\x4f Service or option not implemented", + "\x51 Invalid call reference value", + "\x52 Identified channel does not exist", + "\x53 A suspended call exists, but this call identity does not", + "\x54 Call identity in use", + "\x55 No call suspended", + "\x56 Call having the requested call identity has been cleared", + "\x57 User not member of CUG", + "\x58 Incompatible destination", + "\x5a Non-existent CUG", + "\x5b Invalid transit network selection", + "\x5f Invalid message, unspecified", + "\x60 Mandatory information element is missing", + "\x61 Message type non-existent or not implemented", + "\x62 Message not compatible with call state or message type non-existent or not implemented", + "\x63 Information element/parameter non-existent or not implemented", + "\x64 Invalid information element contents", + "\x65 Message not compatible with call state", + "\x66 Recovery on timer expiry", + "\x67 Parameter non-existent or not implemented - passed on", + "\x6e Message with unrecognized parameter discarded", + "\x6f Protocol error, unspecified", + "\x7f Interworking, unspecified", + NULL }; + +static char *CauseValue1TR6[] = { + "\x00 Normal Call Clearing", + "\x01 Invalid Call Reference", + "\x03 Bearer Service Not Implemented", + "\x07 Caller Identity unknown", + "\x08 Caller Identity in Use", + "\x09 No Channels available", + "\x0a No Channels available", + "\x10 Facility Not Implemented", + "\x11 Facility Not Subscribed", + "\x20 Outgoing calls barred", + "\x21 User Access Busy", + "\x22 Negative GBG", + "\x23 Unknown GBG", + "\x25 No SPV known", + "\x35 Destination not obtainable", + "\x38 Number changed", + "\x39 Out Of Order", + "\x3a No User Response", + "\x3b User Busy", + "\x3d Incoming Barred", + "\x3e Call Rejected", + "\x58 Invalid destination address", + "\x59 Network Congestion", + "\x5a Remote User initiated", + "\x70 Local Procedure Error", + "\x71 Remote Procedure Error", + "\x72 Remote User Suspend", + "\x73 Remote User Resumed", + "\x7f User Info Discarded", + NULL }; + + +static char *Service1TR6[] = { + "\x01 Fernsprechen", + "\x02 Telefax Gruppe 2/3, Modem-DFUE", + "\x03 X.21-Terminaladapter", + "\x04 Telefax Gruppe 4 (digital)", + "\x05 Bildschirmtext (64 kBit/s)", + "\x07 Datenuebertragung (64 kBit/s oder V.110)", + "\x08 X.25-Terminaladapter", + "\x09 Teletex (64 kBit/s)", + "\x0a Text-Fax (ASCII-Text und Grafiken gemischt)", + "\x0d Fernwirken, Telemetrie, Alarmierung", + "\x0e Fernzeichnen", + "\x0f Bildschirmtext (zukuenftiger Standard)", + "\x10 Bildtelefon", + NULL }; + + +char *qmsg(int type, int version, int val) +{ + register char **p, *what; + static char *nix = ""; + + + switch (type) { + case TYPE_MESSAGE : p = (version == VERSION_1TR6) ? MessageType1TR6 : MessageType; + what = "Message type"; + break; + + case TYPE_ELEMENT : p = (version == VERSION_1TR6) ? InformationElement1TR6 : InformationElement; + what = "Information Element"; + break; + + case TYPE_CAUSE : if (val == -1) + return(nix); + + p = (version == VERSION_1TR6) ? CauseValue1TR6 : CauseValue; + what = "Cause"; + break; + + case TYPE_SERVICE : p = Service1TR6; + what = "Service"; + break; + + default : p = (char **)NULL; + what = ""; + break; + } /* switch */ + + while (*p && **p != val) + p++; + + if (*p && (**p == val)) + return(*p + 2); + else { + if (++retnum == MAXRET) + retnum = 0; + + sprintf(retstr[retnum], "UNKNOWN %s 0x%02x", what, val); + return(retstr[retnum]); + } /* else */ +} /* qmsg */ diff --git a/isdnlog/isdnlog/postgres.c b/isdnlog/isdnlog/postgres.c new file mode 100644 index 00000000..4a375149 --- /dev/null +++ b/isdnlog/isdnlog/postgres.c @@ -0,0 +1,220 @@ +/* $Id: postgres.c,v 1.1 1997/03/16 20:58:45 luethje Exp $ + * + * Interface for Postgres95-Database for isdn4linux. (db-module) + * + * by Markus Leist (markus@hal.dirnet.com) + * + * 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: postgres.c,v $ + * Revision 1.1 1997/03/16 20:58:45 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 1.2 1996/12/05 10:20:04 admin + * first version auf Postgres95-Interface seems to be ok + * + * Revision 1.1 1996/12/04 10:03:24 admin + * Initial revision + * + * + */ + + +#ifdef POSTGRES +#define _POSTGRES_C_ + +#include "postgres.h" + + + + + +int dbOpen(void) +{ + + /* get strings from macros */ + + db_Host = NULL; + if ( DB_HOST ) + { + db_Host = malloc( strlen( DB_HOST)); + strcpy( db_Host, DB_HOST); + } + + db_Name = NULL; + if ( DB_NAME ) + { + db_Name = malloc( strlen( DB_NAME)); + strcpy( db_Name, DB_NAME); + } + + db_Table = NULL; + if ( DB_TABLE ) + { + db_Table = malloc( strlen( DB_TABLE)); + strcpy( db_Table, DB_TABLE); + } + + db_Port = NULL; + if ( DB_PORT ) + { + db_Port = malloc( strlen( DB_PORT)); + strcpy( db_Port, DB_PORT); + } + + db_Options = NULL; + if ( DB_OPTIONS ) + { + db_Options = malloc( strlen( DB_OPTIONS)); + strcpy( db_Options, DB_OPTIONS); + } + + db_Tty = NULL; + if ( DB_TTY ) + { + db_Tty = malloc( strlen( DB_TTY)); + strcpy( db_Tty, DB_TTY); + } + + + /* make a connection to the database */ + + db_Conn = PQsetdb( db_Host, db_Port, db_Options, db_Tty, db_Name); + + /* check to see that the backend connection was successfully made */ + if ( PQstatus( db_Conn) == CONNECTION_BAD) + { + syslog( LOG_ERR, "%s", "Connection to ISDN-database failed."); + syslog( LOG_ERR, "%s", PQerrorMessage( db_Conn)); + PQfinish( db_Conn); + return( -1); + } + + return( 0); +} + +int dbClose(void) +{ + PQfinish( db_Conn); + + if ( db_Host) + free( db_Host); + + if ( db_Name) + free( db_Name); + + if ( db_Table) + free( db_Table); + + if ( db_Port) + free( db_Port); + + if ( db_Options) + free( db_Options); + + if ( db_Tty) + free( db_Tty); + + return( 0); +} + +int dbAdd( DbStrIn *in) +{ + PGresult *res; + char out_txt[400]; + struct tm *tm; + + assert( (int)in); + + if ( dbStatus() ) /* returns -1 when not open */ + if ( dbOpen() ) /* returns -1 when error appears */ + return( -1); + + res = PQexec( db_Conn, "BEGIN"); + + if ( PQresultStatus( res) != PGRES_COMMAND_OK) + { + syslog( LOG_ERR, "%s", "Connection to ISDN-database failed."); + syslog( LOG_ERR, "%s", PQerrorMessage( db_Conn)); + PQfinish( db_Conn); + return( -1); + } + + /* should PQclear PGresult whenever it is no longer needed to avoid + memory leaks */ + PQclear( res); + + tm = localtime( (__const time_t *) &(in->connect)); + + sprintf( out_txt +, "INSERT INTO %s " + "( sdate, stime, calling, called, charge, dir, " + " in_bytes, out_bytes, msec, sec, status, service, " + " source, vrsion, factor, currency) values " + "( \'%02d.%02d.%d\', \'%02d:%02d:%02d\', " + "\'%s\', \'%s\', \'%d\', \'%c\', " + "\'%ld\', \'%ld\', \'%d\', \'%d\', \'%d\', \'%d\', " + "\'%d\', \'%d\', \'%5.2f\', \'%s\' );", + db_Table, + tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900, + tm->tm_hour, tm->tm_min, tm->tm_sec, + in->calling, in->called, + in->aoce, in->dialin, + in->ibytes, in->obytes, + in->hduration, in->duration, + in->cause, in->si1, in->si11, + in->version, in->currency_factor, + in->currency); + + /* fetch instances from the pg_database, the system catalog of databases*/ + res = PQexec( db_Conn, out_txt); + + if ( PQresultStatus( res) != PGRES_COMMAND_OK) + { + syslog( LOG_ERR, "%s", "Connection to ISDN-database failed."); + syslog( LOG_ERR, "%s", PQerrorMessage( db_Conn)); + PQfinish( db_Conn); + return( -1); + } + + PQclear( res); + + + /* end the transaction */ + res = PQexec( db_Conn, "END"); + + if ( PQresultStatus( res) != PGRES_COMMAND_OK) + { + syslog( LOG_ERR, "%s", "Connection to ISDN-database failed."); + syslog( LOG_ERR, "%s", PQerrorMessage( db_Conn)); + PQfinish( db_Conn); + return( -1); + } + + PQclear(res); + + return( 0); +} + +int dbStatus( void) +{ + if ( PQstatus( db_Conn) == CONNECTION_BAD) + return( -1); + else + return( 0); +} +#endif diff --git a/isdnlog/isdnlog/postgres.h b/isdnlog/isdnlog/postgres.h new file mode 100644 index 00000000..0048bb4b --- /dev/null +++ b/isdnlog/isdnlog/postgres.h @@ -0,0 +1,120 @@ +/* $Id: postgres.h,v 1.1 1997/03/16 20:58:46 luethje Exp $ + * + * Interface for Postgres95-Database for isdn4linux. + * + * by Markus Leist (markus@hal.dirnet.com) + * + * 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: postgres.h,v $ + * Revision 1.1 1997/03/16 20:58:46 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 1.2 1996/12/05 10:18:17 admin + * first version auf Postgres95-Interface seems to be ok + * + * Revision 1.1 1996/12/04 09:57:44 admin + * Initial revision + * + * + */ + +/****************************************************************************/ + +#ifndef _POSTGRES_H_ +#define _POSTGRES_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* functions for postgres95 */ + + +/* if DB_*-Macro=NULL, Postgres will use following environment variables: + PGHOST, PGPORT, PGOPTIONS, PGTTY, PGDATABASE */ +#define DB_HOST NULL /* host name of backend-server */ +#define DB_PORT NULL /* port of backend-server */ +#define DB_OPTIONS NULL /* special options to start up backend-server */ +#define DB_TTY NULL /* debugging tty for backend-server */ +#define DB_NAME "isdn" /* name of database */ +#define DB_TABLE "isdn2" /* name of table in database */ + +#define NUMSIZE 20 + + +struct _DbStrIn +{ + time_t connect; /* Zeitpunkt des Verbindungsaufbaues */ + char calling[NUMSIZE]; /* Telefonnummer des Anrufers */ + char called[NUMSIZE]; /* Telefonnummer des Gegners */ + int duration; /* Dauer der Verbindung in Sekunden */ + int hduration; /* Dauer der Verbindung in 1/100 Sekunden */ + int aoce; /* Anzahl zu zahlender Gebuehreneinheiten (AOC-D) */ + int dialin; /* "I" fuer incoming call, "O" fuer outgoing call */ + int cause; /* Kam eine Verbindung nicht zustande ist hier der Grund */ + long ibytes; /* Summe der uebertragenen Byte _von_ draussen (incoming) */ + long obytes; /* Summe der uebertragenen Byte _nach_ draussen (outgoing) */ + int version; /* Versionsnummer (LOG_MAJOR_VERSION*100 + LOG_MINOR_VERSION) */ + int si1; /* Dienstkennung fuer diese Verbindung (1=Speech, 7=Data usw.) */ + int si11; /* Bei Dienstkennung 1=Speech -> analog oder digital ? */ + double currency_factor; /* Der Currency Factor fuer diese Verbinung (hier z.Zt. 0,12) */ + char currency[32]; /* (16) Die Waehrung fuer diese Verbindung (in Deutschland "DM") */ +}; + +typedef struct _DbStrIn DbStrIn; + + +/****************************************************************************/ + +#ifdef _POSTGRES_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif +_EXTERN int dbOpen( void); +_EXTERN int dbClose( void); +_EXTERN int dbAdd( DbStrIn *in); +_EXTERN int dbStatus( void); +#undef _EXTERN + +#ifdef _POSTGRES_C_ +#define _EXTERN static +#else +#define _EXTERN extern +#endif +_EXTERN char *db_Host, *db_Port, *db_Options, *db_Tty; +_EXTERN char *db_Name, *db_Table; +_EXTERN PGconn *db_Conn; +#undef _EXTERN + + +#endif /* _POSTGRES_H_ */ diff --git a/isdnlog/isdnlog/processor.c b/isdnlog/isdnlog/processor.c new file mode 100644 index 00000000..5342e0b2 --- /dev/null +++ b/isdnlog/isdnlog/processor.c @@ -0,0 +1,4049 @@ +/* $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„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*#, 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 fr 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„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„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„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 */ diff --git a/isdnlog/isdnlog/server.c b/isdnlog/isdnlog/server.c new file mode 100644 index 00000000..ed059786 --- /dev/null +++ b/isdnlog/isdnlog/server.c @@ -0,0 +1,727 @@ +/* + * ISDN accounting for isdn4linux. + * + * Copyright 1996 by Stefan Luethje (luethje@sl-gw.lake.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/****************************************************************************/ + +#define _SERVER_C_ + +/****************************************************************************/ + +#include "isdnlog.h" + +/****************************************************************************/ + +static char **Old_Prints = NULL; +static char **Old_Info = NULL; +static char **Cur_Info = NULL; +static int Cur_Info_Size = 0; + +/****************************************************************************/ + +static int new_client(int sock); +static int del_Cur_Info(int channel); +static int add_Cur_Info(int channel, char *String); +static int append_Old_Info(char *String); +static char *Get_Address(char *Number); +static int Set_Address(char *String); +static int Write_Caller_Message(int sock, CALL *info); +static char *Build_Call_Info(CALL *call, int chan); +static int save_messages(char *String, int channel, int stat); +static int broadcast_from_server(char* Num, int Flag, int Message, char *String); +static int append_Old_Prints(char *String); +static int String_For_Output(char *String); + +/****************************************************************************/ + +extern time_t cur_time; + +/****************************************************************************/ + +int listening(int port) +{ + int sock; + struct servent *sp = NULL; + + + if ((sock = server_connect(&sp,port)) < 0) + { + if (sock == NO_SOCKET) + { + print_msg(PRT_NORMAL,"Can not open socket %d: %s\n",sock,strerror(errno)); + } + else + if (sock == NO_BIND) + { + print_msg(PRT_NORMAL,"Can not bind socket: %s\n",strerror(errno)); + } + else + if (sock == NO_LISTEN) + { + print_msg(PRT_NORMAL,"Can not start listening: %s\n",strerror(errno)); + } + + return -1; + } + + if (sp) + { + print_msg(PRT_DEBUG_CS,"Got service %s on port %d\n", + sp->s_name,ntohs(sp->s_port)); + } + else + { + print_msg(PRT_DEBUG_CS,"Got port %d\n", port); + } + + return sock; +} + +/****************************************************************************/ + +int new_client(int sock) +{ + int Accept; + int Cnt; + int RetCode; + char *Host = NULL; + static CALL *Info = NULL; + + + if ((RetCode = read_user_access()) != 0) + { + print_msg(PRT_ERR,"Error while reading file \"%s\"!\n",userfile()); + Exit(24); + } + + sockets[sock].f_username = (char*) calloc(strlen(sockets[sock].msgbuf.buf)+1, + sizeof(char)); + strcpy(sockets[sock].f_username,sockets[sock].msgbuf.buf); + + Accept = user_has_access(sockets[sock].f_username,sockets[sock].f_hostname); + + + sockets[sock].msg = MSG_VERSION; + msgcpy(&(sockets[sock]),PROT_VERSION,strlen(PROT_VERSION)+1); + + if (Write(&(sockets[sock])) < 1) + { + disconnect_client(sock); + return 0; + } + + Host = sockets[sock].f_hostname != NULL ? sockets[sock].f_hostname : "unknown"; + print_msg(PRT_DEBUG_CS,"connection from client %s@%s %s\n", + sockets[sock].f_username, + Host, + Accept != -1?"accepted":"rejected"); + + if (Accept == -1) + { /* Ablehnung der Verbindung */ + sockets[sock].waitstatus = WF_CLOSE; + sockets[sock].msg = MSG_ANN_REJ; + sockets[sock].msgbuf.used = 0; + + Write(&(sockets[sock])); + + /* Die naechste Zeile wird nicht gebraucht + disconnect_client(sock); + */ + return 0; + } + else + { /* Verbindung wird angenommen */ + sockets[sock].msg = MSG_ANN_ACC; + msgcpy(&(sockets[sock]),itos(Accept,_MSG_2B),_MSG_2B+1); + + if (Write(&(sockets[sock])) < 1) + { + disconnect_client(sock); + return 0; + } + } + + sockets[sock].waitstatus = WF_NOTHING; + + if (Old_Info != NULL) + for (Cnt = 0; Cnt < mcalls; Cnt++) + if (Old_Info[Cnt] != NULL && + Set_Info_Struct(&Info,Old_Info[Cnt]) >= 0 && + User_Get_Message(sockets[sock].f_username,sockets[sock].f_hostname,Info->num[_ME(Info)],0) == 0) + { + sockets[sock].msg = MSG_CALL_INFO; + msgcpy(&(sockets[sock]),Old_Info[Cnt],strlen(Old_Info[Cnt])+1); + + if (Write(&(sockets[sock])) < 1) + { + disconnect_client(sock); + return 0; + } + } + + if (Cur_Info != NULL) + for (Cnt = 0; Cnt < Cur_Info_Size; Cnt++) + if (Cur_Info[Cnt] != NULL && + Set_Info_Struct(&Info,Cur_Info[Cnt]) >= 0 && + User_Get_Message(sockets[sock].f_username,sockets[sock].f_hostname,Info->num[_ME(Info)],0) == 0) + { + sockets[sock].msg = MSG_CALL_INFO; + msgcpy(&(sockets[sock]),Cur_Info[Cnt],strlen(Cur_Info[Cnt])+1); + + if (Write(&(sockets[sock])) < 1) + { + disconnect_client(sock); + return 0; + } + } + + if (Old_Prints != NULL && User_Get_Message(sockets[sock].f_username,sockets[sock].f_hostname,NULL,T_PROTOCOL) == 0) + for (Cnt = 0; Cnt < xlog; Cnt++) + if (Old_Prints[Cnt] != NULL) + { + sockets[sock].msg = MSG_SERVER; + msgcpy(&(sockets[sock]),Old_Prints[Cnt],strlen(Old_Prints[Cnt])+1); + + if (Write(&(sockets[sock])) < 1) + { + disconnect_client(sock); + return 0; + } + } + else + break; + + + return 0; +} + +/****************************************************************************/ + +int disconnect_client(int sock) +{ + char User[SHORT_STRING_SIZE]; + char Host[SHORT_STRING_SIZE]; + + if (sockets[sock].f_username == NULL) + strcpy(User,"unknown"); + else + strcpy(User,sockets[sock].f_username); + + if (sockets[sock].f_hostname == NULL) + strcpy(Host,"unknown"); + else + strcpy(Host,sockets[sock].f_hostname); + + close(sockets[sock].descriptor); + + if (del_socket(&sockets,sock)) + Exit(16); + + print_msg(PRT_DEBUG_CS,"disconnect from client %s@%s!\n",User,Host); + print_msg(PRT_DEBUG_CS,"I/O error: %s!\n",strerror(errno)); + + return 0; +} + +/****************************************************************************/ + +int eval_message (int sock) +{ + long int Value; + int Msg; + + do + { + if ((Value = Read(&(sockets[sock]))) < 0) + { + disconnect_client(sock); + break; + } + else + { + Msg = sockets[sock].msg; + switch(sockets[sock].waitstatus) + { + case WF_ACC: + switch (Msg) + { + case MSG_ANNOUNCE: + new_client(sock); + break; + + default: + /* Meldung: Unbekannter Message-Typ Msg */ + print_msg(PRT_ERR,"Unknown Message %d: %s\n",Msg,sockets[sock].msgbuf.buf); + disconnect_client(sock); + break; + } + break; + + case WF_CLOSE: + switch (Msg) + { + case MSG_CLOSE: + disconnect_client(sock); + break; + + default: + /* Meldung: Unbekannter Message-Typ Msg */ + print_msg(PRT_ERR,"Unknown Message %d: %s\n",Msg,sockets[sock].msgbuf.buf); + disconnect_client(sock); + break; + } + break; + + default: + switch (Msg) + { + case MSG_NEW_CALLER: + Set_Address(sockets[sock].msgbuf.buf); + break; + default: + /* Meldung: Unbekannter Message-Typ Msg */ + print_msg(PRT_ERR,"Unknown Message %d: %s\n",Msg,sockets[sock].msgbuf.buf); + disconnect_client(sock); + break; + } + break; + } + } + } while (sockets[sock].status == NEXT_MSG); + + + return 0; +} + +/****************************************************************************/ + +int broadcast_from_server(char* Num, int Flag, int Message, char *String) +{ + int Cnt; + + for(Cnt = first_descr; Cnt < socket_size(sockets); Cnt++) + { + if (sockets[Cnt].fp == NULL && + sockets[Cnt].waitstatus == WF_NOTHING && + User_Get_Message(sockets[Cnt].f_username,sockets[Cnt].f_hostname,Num,Flag) == 0) + { + sockets[Cnt].msg = Message; + msgcpy(&(sockets[Cnt]),String,strlen(String)+1); + + if (Write(&(sockets[Cnt])) < 1) + disconnect_client(Cnt); + } + } + + return 0; +} + +/****************************************************************************/ + +int print_from_server(char *String) +{ + int RetCode; + char NewString[LONG_STRING_SIZE]; + time_t t = time(NULL); + struct tm *tm_time = localtime(&t); + + + tm_time->tm_isdst = 0; + + strftime(NewString,LONG_STRING_SIZE,"%b %d %X ",tm_time); + strcat(NewString,String); + + if ((RetCode = String_For_Output(NewString)) < 0) + return RetCode; + + if ((RetCode = append_Old_Prints(NewString)) < 0) + return RetCode; + + return broadcast_from_server(NULL,T_PROTOCOL,MSG_SERVER,NewString); +} + +/****************************************************************************/ + +int message_from_server(CALL *call, int chan) +{ + int Cnt; + int RetCode; + char *String = Build_Call_Info(call,chan); + + if ((RetCode = String_For_Output(String)) < 0) + return RetCode; + + if ((RetCode = save_messages(String,chan,call->stat)) < 0) + return RetCode; + + for(Cnt = first_descr; Cnt < socket_size(sockets); Cnt++) + { + if (sockets[Cnt].fp == NULL && + sockets[Cnt].waitstatus == WF_NOTHING && + User_Get_Message(sockets[Cnt].f_username,sockets[Cnt].f_hostname,call->num[_ME(call)],0) == 0) + { + sockets[Cnt].msg = MSG_CALL_INFO; + msgcpy(&(sockets[Cnt]),String,strlen(String)+1); + + if (Write(&(sockets[Cnt])) < 1) + disconnect_client(Cnt); + else + if (Write_Caller_Message(Cnt,call) < 0) + disconnect_client(Cnt); + } + } + + return 0; +} + +/****************************************************************************/ + +char *Build_Call_Info(CALL *call, int chan) +{ + static char RetCode[LONG_STRING_SIZE]; + +/* Anmerkungen dazu: + + 1. ``connect'' kann auch (time_t)0 sein! + Dann besteht noch gar keine Verbindung - z.b. weil es gerade + klingelt, man aber noch nicht abgenommen hat! + + 2. Die ``Dauer'' zu uebertragen halte ich fuer unwichtig - bitte + korrigiert mich, wenn ich da falsch liege! + Die Dauer ist doch ``(jetzt) - connect'' ? + + 3. Die Einheiten sind: + + 0 : kostet nix (0130 Gespraech, oder man wird angerufen) + -1 .. -x : Gebuehrenimpuls + 1 .. x : AOCE (Gebuehreninfo am Ende) +*/ + + sprintf(RetCode, "%d|%d|%d|%s|%s|%s|%s|%s|%s|%s|%d|%d|%d|%s|%s|%ld|%ld|%g|%g|%s\n", + chan, /* Kennung: 0 = erste, 1 = zweite laufende Verbindung */ + call->stat, /* Satzart fuer _diese_ Meldung */ + call->dialin, /* 1 = ein Anruf, 0 = man waehlt raus */ + call->num[_ME(call)], /* Eigene MSN */ + call->alias[_ME(call)], /* Alias de eigenen MSN */ + call->num[_OTHER(call)], /* Telefonnummer des Anrufers/Angerufenen (wie von der VSt uebermittelt) */ + call->vorwahl[_OTHER(call)], /* Vorwahl des Anrufers/Angerufenen */ + call->rufnummer[_OTHER(call)], /* Rufnummer des Anrufers/Angerufenen */ + call->alias[_OTHER(call)], /* Alias des Anrufers/Angerufenen */ + call->area[_OTHER(call)], /* Ortsnetz des Anrufers/Angerufenen */ + (int)(call->connect?call->connect:cur_time), /* Beginn (als (time_t) ) */ + (int)(call->connect?cur_time - call->connect:0), /* aktuelle Dauer - in Sekunden seit CONNECT */ + call->aoce, /* Einheiten (negativ: laufende Impulse, positiv: AOCE) */ + double2str(abs(call->aoce) * currency_factor, 6, 2, DEB), /* kostet gerade */ + currency_factor ? currency : "DM", /* Waehrung */ + call->ibytes, /* Frank's ibytes */ + call->obytes, /* Frank's obytes */ + call->ibps, /* Aktueller Durchsatz INPUT: Bytes/Sekunde */ + call->obps, /* Aktueller Durchsatz OUTPUT: Bytes/Sekunde */ + call->msg); /* Status */ + + return RetCode; +} + +/****************************************************************************/ + +int Write_Caller_Message(int sock, CALL *Info) +{ + char *Address = NULL; + + if (Info->num[0][0] == '\0') + return 0; + + if (User_Get_Message(sockets[sock].f_username,sockets[sock].f_hostname,NULL,T_ADDRESSBOOK) != 0) + return 0; + + /* Dirty Hack fuer emulation von neuen Anrufern */ + if (Info->stat == STATE_CONNECT) + { + if ((Address = Get_Address(Info->num[0])) == NULL) + { + sockets[sock].msg = MSG_WHO_IS; + msgcpy(&(sockets[sock]),Info->num[0],strlen(Info->num[0])+1); + + if (Write(&(sockets[sock])) < 1) + { + disconnect_client(sock); + return -1; + } + } + else + { + sockets[sock].msg = MSG_CALLER; + msgcpy(&(sockets[sock]),Address,strlen(Address)+1); + + if (Write(&(sockets[sock])) < 1) + { + disconnect_client(sock); + return -1; + } + } + } + + return 0; +} + +/****************************************************************************/ + +char *Get_Address(char *Number) +{ + /* Hier sollte die Adresse zur uebergebenen Telefonummer geliefert werden */ + return NULL; + return "Burmester:Fred:2::Lohe 4:D:23869:Fischbek:2:04532/123:04532/124:0:0::Elmenhorster Str. 16:D:20000:Hamburg:0:0:1:fred@wo.auch.immer:08.01.68"; +} + +/****************************************************************************/ + +int Set_Address(char *String) +{ + /* Hier sollte die Adresse zur uebergebenen Telefonummer geliefert werden */ + print_msg(PRT_DEBUG_CS,"New Address*%s*\n",String); + return 0; +} + +/****************************************************************************/ + +int save_messages(char *String, int channel, int stat) +{ + int RetCode; + + + if (stat == STATE_HANGUP) + { + if ((RetCode = del_Cur_Info(channel)) < 0) + { + print_msg(PRT_DEBUG_CS,"Invalid Channel No. %d\n",channel); + } + + if ((RetCode = append_Old_Info(String)) < 0) + return RetCode; + } + else + { + if ((RetCode = add_Cur_Info(channel,String)) < 0) + return RetCode; + } + + return 0; +} + +/****************************************************************************/ + +int del_Cur_Info(int channel) +{ + if (Cur_Info == NULL || Cur_Info[channel] == NULL || + channel >= Cur_Info_Size || channel < 0 ) + return -1; + + free(Cur_Info[channel]); + Cur_Info[channel] = NULL; + return 0; +} + +/****************************************************************************/ + +int append_Old_Prints(char *String) +{ + int Cnt = 0; + + if (Old_Prints == NULL) + if ((Old_Prints = (char**) calloc(xlog,sizeof(char*))) == NULL) + return NO_MEMORY; + + + while(Cnt < xlog && Old_Prints[Cnt] != NULL) + Cnt++; + + if (Cnt == xlog) + { + Cnt = 1; + + if (Old_Prints[0] != NULL) + free(Old_Prints[0]); + + while(Cnt < xlog) + { + Old_Prints[Cnt-1] = Old_Prints[Cnt]; + Cnt++; + } + + Cnt = xlog - 1; + } + + if ((Old_Prints[Cnt] = (char*) calloc(strlen(String)+1,sizeof(char))) == NULL) + return NO_MEMORY; + else + strcpy(Old_Prints[Cnt],String); + + return 0; +} + +/****************************************************************************/ + +int append_Old_Info(char *String) +{ + int Cnt = 0; + + + if (Old_Info == NULL) + if ((Old_Info = (char**) calloc(mcalls,sizeof(char*))) == NULL) + return NO_MEMORY; + + + while(Cnt < mcalls && Old_Info[Cnt] != NULL) + Cnt++; + + if (Cnt == mcalls) + { + Cnt = 1; + free(Old_Info[0]); + + while(Cnt < mcalls) + { + Old_Info[Cnt-1] = Old_Info[Cnt]; + Cnt++; + } + + Cnt = mcalls - 1; + } + + if ((Old_Info[Cnt] = (char*) calloc(strlen(String)+1,sizeof(char))) == NULL) + return NO_MEMORY; + else + strcpy(Old_Info[Cnt],String); + + return 0; +} + +/****************************************************************************/ + +int add_Cur_Info(int channel, char *String) +{ + char **Ptr; + + + if (channel < 0) + return 0; + + if (Cur_Info == NULL) + if ((Cur_Info = (char**) calloc(channel + 1,sizeof(char*))) == NULL) + return NO_MEMORY; + else + Cur_Info_Size = channel + 1; + else + if (channel >= Cur_Info_Size) + { + if ((Ptr = (char**) calloc(channel + 1,sizeof(char*))) == NULL) + return NO_MEMORY; + + memcpy(Ptr,Cur_Info,Cur_Info_Size*sizeof(char*)); + Cur_Info_Size = channel + 1; + free(Cur_Info); + Cur_Info = Ptr; + } + + if (Cur_Info[channel] != NULL) + free(Cur_Info[channel]); + + if ((Cur_Info[channel] = (char*) calloc(strlen(String)+1,sizeof(char))) == NULL) + return NO_MEMORY; + else + strcpy(Cur_Info[channel],String); + + return 0; +} + +/****************************************************************************/ + +int String_For_Output(char* String) +{ + char *Ptr; + char *CurPtr; + char NewString[LONG_STRING_SIZE]; + + strcpy(NewString,String); + CurPtr = NewString; + String[0] = '\0'; + + while ((Ptr = strtok(CurPtr,"\n\r")) != NULL) + { + CurPtr = NULL; + strcat(String,Ptr); + } + + return 0; +} + +/****************************************************************************/ + +int change_channel(int old_chan, int new_chan) +{ + int RetCode = 0; + int Cnt; + char tmp_string[SHORT_STRING_SIZE]; + char *String = NULL; + static CALL *Info = NULL; + + + print_msg(PRT_DEBUG_CS,"Will change channel from %d to %d\n",old_chan,new_chan); + + if (old_chan < 0 || old_chan >= Cur_Info_Size || + new_chan < 0 || Cur_Info[old_chan] == NULL ) + return -1; + + if (old_chan == new_chan) + return 0; + + if ((RetCode = Set_Info_Struct(&Info,Cur_Info[old_chan])) < 0) + return RetCode; + + if ((String = Build_Call_Info(Info, new_chan)) == NULL) + return -1; + + if ((RetCode = del_Cur_Info(old_chan)) != 0) + return RetCode; + + if ((RetCode = add_Cur_Info(new_chan,String)) != 0) + return RetCode; + + print_msg(PRT_DEBUG_CS,"Change channel from %d to %d\n",old_chan,new_chan); + + for(Cnt = first_descr; Cnt < socket_size(sockets); Cnt++) + { + if (sockets[Cnt].waitstatus == WF_NOTHING && + User_Get_Message(sockets[Cnt].f_username,sockets[Cnt].f_hostname,Info->num[_ME(Info)],0) == 0) + { + sockets[Cnt].msg = MSG_CHANGE_CHAN; + sprintf(tmp_string,"%d%c%d",old_chan,C_DELIMITER,new_chan); + msgcpy(&(sockets[Cnt]),tmp_string,strlen(tmp_string)+1); + + if (Write(&(sockets[Cnt])) < 1) + disconnect_client(Cnt); + } + } + + return 0; +} + +/****************************************************************************/ + diff --git a/isdnlog/isdnlog/start_prog.c b/isdnlog/isdnlog/start_prog.c new file mode 100644 index 00000000..302b18b2 --- /dev/null +++ b/isdnlog/isdnlog/start_prog.c @@ -0,0 +1,811 @@ +/* $Id: start_prog.c,v 1.1 1997/03/16 20:58:55 luethje Exp $ + * + * ISDN accounting for isdn4linux. + * + * Copyright 1996 by Michael 'Ghandi' Herold, + * Stefan Luethje (luethje@sl-gw.lake.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: start_prog.c,v $ + * Revision 1.1 1997/03/16 20:58:55 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.3.27 1996/05/05 20:35:46 akool + * + * Revision 2.21 1996/03/13 11:58:46 akool + */ + + +#define _START_PROG_C_ +#include "isdnlog.h" +#include +#include +#include + +/*************************************************************************/ + +static interval *RootIntervall = NULL; + +/** Prototypes ***********************************************************/ + +static void KillCommand(int); +static int GetArgs(char *, char *[], char *[], int); +static interval *Next_Interval(void); +static int set_user(char *User); +static int set_group(char *Group); + +/****************************************************************************/ + +static int set_user(char *User) +{ + struct passwd* Ptr = NULL; + + if (User == NULL || User[0] == '\0') + return 0; + + setpwent(); + + while ((Ptr = getpwent()) != NULL) + { + if (!strcmp(Ptr->pw_name,User)) + { + endpwent(); + return setuid(Ptr->pw_uid); + } + } + + endpwent(); + return 0; +} + +/****************************************************************************/ + +static int set_group(char *Group) +{ + struct group* Ptr = NULL; + + + if (Group == NULL || Group[0] == '\0') + return 0; + + setgrent(); + + while ((Ptr = getgrent()) != NULL) + { + if (!strcmp(Ptr->gr_name,Group)) + { + endgrent(); + return setgid(Ptr->gr_gid); + } + } + + endgrent(); + return 0; +} + +/************************************************************************* + ** Ring(-) - Externes Kommando ausfuehren oder loeschen. Bei einem Fehl- ** + ** er wird -1 zurueckgegeben; ansonsten die PID des neuen ** + ** Prozesses. Wenn das Kommando mit system() aufgerufen wur- ** + ** de (Async), wird -1 zurueckgegeben, da die PID nicht ge- ** + ** sichert werden muss. ** + ************************************************************************* + ** Die : <= 0 Kommando ausfuehren. ** + ** > 0 PID killen. ** + ** Async: == 1 Kommando mit system() starten. ** + ** == 0 Kommando mit eigenem Prozess starten. ** + *************************************************************************/ + +int Ring(info_args *Cmd, char *Opts[], int Die, int Async) +{ + char Command[SHORT_STRING_SIZE + 1]; + char String[LONG_STRING_SIZE]; + int filedes[2]; + char *Args[64]; + pid_t pid; + FILE *fp; + + print_msg(PRT_DEBUG_EXEC, "Ring: Cmd: '%s' Die: %d Async: %d\n", (Cmd&&Cmd->infoarg)?Cmd->infoarg:"NO COMMAND", Die, Async); + + if (Die <= 0) + { + sprintf(Command,"%.*s",SHORT_STRING_SIZE-6,Cmd->infoarg); + + + /* Kommando soll gestartet werden - 'Async' gibt an, ob dieses */ + /* mit system() oder mit einem eigenen Prozeß aufgerufen wer- */ + /* den soll. */ + + if (GetArgs(Command,Args,Opts,64) == -1) + { + print_msg(PRT_ERR, "Can't start \"%s\" with execvp().\n", Args[0]); + return -1; + } + + pipe(filedes); + switch (pid = fork()) + { + case -1: print_msg(PRT_ERR, "%s\n", "Can't start fork()!"); + return 0; + break; + case 0: if (paranoia_check(Args[0]) < 0) + exit(-1); + + if (set_group(Cmd->group) < 0) + { + print_msg(PRT_ERR, "Can not set group %s: %s\n",Cmd->group,strerror(errno)); + exit(-1); + } + + if (set_user(Cmd->user) < 0) + { + print_msg(PRT_ERR, "Can not set user %s: %s\n",Cmd->user,strerror(errno)); + exit(-1); + } + + dup2(filedes[1],STDOUT_FILENO); + dup2(filedes[1],STDERR_FILENO); + + execvp(Args[0], Args); + print_msg(PRT_ERR, "Can't start \"%s\" with execvp().\n", Args[0]); + /* Alarm(); */ + exit(-1); + break; + } + + fp = fdopen(filedes[0],"r"); + close(filedes[1]); + + print_msg(PRT_DEBUG_INFO, "Program \"%s\" \"%s\" started %ssynchronous.\n", Args[0], Args[1], (Async?"a":"")); + + if (Async == 1) + { + while(fgets(String,LONG_STRING_SIZE,fp) != NULL) + print_msg(PRT_PROG_OUT,"%s\n",String); + + waitpid(pid,NULL,0); + fclose(fp); + return(0); + } + else + { + int sock; + + if (add_socket(&sockets,filedes[0])) + return NO_MEMORY; + + sock = socket_size(sockets)-1; + sockets[sock].fp = fp; + sockets[sock].pid = pid; + + return sock; + } + } + else + { + KillCommand(Die); + return 0; + } + + return(-1); +} + +/************************************************************************* + ** GetArgs(-) - Zerlegt eine Kommandozeile in einzelne Argumente. ** + *************************************************************************/ + +static int GetArgs(char *Line, char *Args[], char *Opts[], int MaxArgs) +{ + char *Arg = NULL; + char *Use = Line; + char *Ptr = NULL; + char *Ptr2 = NULL; + char *Org_Arg; + int MaxOpts= 0; + int i = 0; + int j = 0; + int Num = 0; + char HelpString[SHORT_STRING_SIZE]; + static char **MemPtr = NULL; + + if (MemPtr != NULL) + { + while(MemPtr[j] != NULL) + free(MemPtr[j++]); + + free(MemPtr); + MemPtr = NULL; + j = 0; + } + + while (Opts[MaxOpts] != NULL) + MaxOpts++; + + while ((Org_Arg = Arg = strtok(Use, " \t"))) + { + Use = NULL; + + if (*Arg == '@') + { + FILE *fp = fopen(Arg+1,"r"); + + if (fp != NULL) + { + fgets(HelpString,SHORT_STRING_SIZE,fp); + + if (*HelpString != '\0') + HelpString[strlen(HelpString)-1] = '\0'; + + Arg = strdup(HelpString); + + MemPtr = (char**) realloc(MemPtr,sizeof(char*)*(j+2)); + MemPtr[j++] = Arg; + MemPtr[j] = NULL; + fclose(fp); + } + else + Arg = NULL; + } + else + if (*Arg == '$') + { + if (Opts != NULL && (Num = atoi(Arg+1)) > 0 && Num <= MaxOpts) + Arg = Opts[Num-1]; + else + if (strlen(Arg) > 3 && Arg[1] == '{' && (Ptr = strrchr(Arg,'}')) != NULL) + { + *Ptr = '\0'; + + if ((Ptr2 = getenv(To_Upper(Arg+2))) != NULL) + { + strcpy(HelpString,Ptr2); + strcat(HelpString,Ptr+1); + Arg = strdup(HelpString); + + MemPtr = (char**) realloc(MemPtr,sizeof(char*)*(j+2)); + MemPtr[j++] = Arg; + MemPtr[j] = NULL; + } + else + Arg = NULL; + } + else + Arg = getenv(To_Upper(Arg+1)); + } + + if (Arg == NULL || *Arg == '\0') + { + if (Arg == NULL) + print_msg(PRT_WARN,"Invalid argument `%s' for program start!\n",Org_Arg); + + Arg = "?"; + } + + Ptr = Arg; + while((Ptr = Check_Quote(Ptr, S_QUOTES, QUOTE_DELETE)) != NULL && Ptr[0] != '\0') + Ptr++; + + if (i < MaxArgs) Args[i++] = Arg; + } + + Args[i] = NULL; + + return(i); +} + +/************************************************************************* + ** KillCommand(-) - Beendet ein Programm anhand seiner PID. ** + *************************************************************************/ + +static void KillCommand(int sock) +{ + char String[LONG_STRING_SIZE] = ""; + /* Kein Erbarmen - Alles was uns zwischen die Finger kommt wird */ + /* gelöscht :-) */ + + if (sock > 0) + { + while (fgets(String,LONG_STRING_SIZE,sockets[sock].fp)) + print_msg(PRT_PROG_OUT,"%s\n",String); + + kill(sockets[sock].pid, SIGTERM); + kill(sockets[sock].pid, SIGKILL); + + /* ACHTUNG: Die naechste Zeile kann schwierigkeiten machen!!! + Der Prozess kann eventuell hier haengen bleiben. Dann Zeile + auskommentieren. Ich weiss nicht, ob kill den Prozess auch + sauber beendet. Damit keine Zombies rumfahren vorsichtshaber + der waitpid. + Alternativ: waitpid(sockets[sock].pid,NULL,WNOHANG) */ + + waitpid(sockets[sock].pid,NULL,0); + fclose(sockets[sock].fp); + del_socket(&sockets,sock); + } +} + +/************************************************************************* + ** Alarm(-) - Gibt ein Alarmsignal über den internen Lautsprecher aus. ** + *************************************************************************/ + +void Alarm(void) +{ +#ifdef ALARM + + int FD; + int i; + + if ((FD = open("/dev/console", O_WRONLY)) == -1) FD = 0; + + for (i = 0; i < 30; i++) + { + ioctl(FD, KIOCSOUND, (3000 - (i * 10))); + + usleep((1 * 1000)); + } + + ioctl(FD, KIOCSOUND, 0); + +#endif +} + +/************************************************************************* + ** CheckTime(-) - Prüft ob die Zeitangabe in den lokalen Zeitrahmen ** + ** fällt. Rückgabe ist TRUE/FALSE. ** + *************************************************************************/ + +int CheckTime(char *Line) +{ + char Temp[SHORT_STRING_SIZE + 1]; + char Time[24]; + char *Use; + struct tm *tm_Time; + char *Arg; + char *Minus; + int i; + int r; + int Beg; + int End; + time_t Local; + + if (Line == NULL || *Line == '\0') + return 1; + + strncpy(Temp, Line, SHORT_STRING_SIZE); + + for (i = 0; i < 24; i++) Time[i] = 0; + + Use = Temp; + + /* Zeile in die einzelnen Komponenten trennen, die durch ',', */ + /* ' ' oder ';' voneinander getrennt sein können. */ + + while ((Arg = strtok(Use, ", ;"))) + { + Use = NULL; + + if (*Arg == '*') + return 1; + + if (!isdigit(*Arg)) + { + print_msg(PRT_WARN, " Wrong time in `%s`: \"%s\"\n", CONFFILE, Arg); + continue; + } + + if ((Minus = strchr(Arg, '-'))) + { + *Minus++ = 0; + + Beg = atoi(Arg); + End = atoi(Minus); + } + else + { + Beg = atoi(Arg); + End = Beg+1; + } + + if ((Beg < 0) || (End < 0) || (Beg > 24) || (End > 25)) + { + print_msg(PRT_WARN, "Time range not correct in `%s`: (%d-%d)\n", CONFFILE, Beg, End); + } + else + { + if (End <= Beg) + End += 24; + + for (r = Beg; r < End; r++) Time[r%24] = 1; + } + } + + /* Lokale Zeit errechnen und mit den Stunden im Zeitarray ver- */ + /* gleichen. */ + + Local = time(NULL); + + if ((tm_Time = localtime(&Local)) != NULL) + { + if (Time[tm_Time->tm_hour] == 1) + return(1); + } + else print_msg(PRT_ERR, "Can't get local time.\n"); + + return(0); +} + +/****************************************************************************/ + +int Print_Cmd_Output( int sock ) +{ + char String[LONG_STRING_SIZE] = ""; + + + if (feof(sockets[sock].fp)) + { + KillCommand(sock); + return -1; + } + + fgets(String,LONG_STRING_SIZE,sockets[sock].fp); + + print_msg(PRT_PROG_OUT,"%s\n",String); + + return 0; +} + +/****************************************************************************/ + +int Get_Sock_From_Info_Args( info_args *Ptr, int Cnt ) +{ + if (socket_size(sockets) > Cnt || Cnt < 0) + while (sockets[Cnt].descriptor != -2) + if (sockets[Cnt].info_arg == Ptr) + return Cnt; + else + Cnt++; + + return -1; +} + +/****************************************************************************/ + +int Get_Sock_From_Call( int chan, int Cnt ) +{ + if (socket_size(sockets) > Cnt || Cnt < 0) + while (sockets[Cnt].descriptor != -2) + if (sockets[Cnt].chan == chan) + return Cnt; + else + Cnt++; + + return -1; +} + +/****************************************************************************/ + +int Get_Sock_From_Call_And_Info_Args( int chan, info_args *Ptr, int Cnt ) +{ + if (socket_size(sockets) > Cnt || Cnt < 0) + while (sockets[Cnt].descriptor != -2) + if (sockets[Cnt].chan == chan && sockets[Cnt].info_arg == Ptr) + return Cnt; + else + Cnt++; + + return -1; +} + +/****************************************************************************/ + +int Condition_Changed( int condition, int flag ) +{ + if ((flag & RING_CONNECT) || (flag & RING_RING)) + { + if ((flag & RING_CONNECT) && condition == RING_CONNECT) + return 0; + + if ((flag & RING_CONNECT) && condition == RING_AOCD) + return 0; + + if ((flag & RING_CONNECT) && condition == RING_ERROR) + return 0; + + if ((flag & RING_RING) && condition == RING_RING) + return 0; + + if ((flag & RING_RING) && condition == RING_ERROR) + return 0; + + return 1; + } + return 0; +} + +/****************************************************************************/ + +const char *Set_Ringer_Flags( int condtion, int InOut ) +{ + char Char = 0; + static char RetCode[10]; + + if (InOut & RING_INCOMING) Char = 'I'; + else + if (InOut & RING_OUTGOING) Char = 'O'; + else + { + print_msg(PRT_ERR, "Error: Expected flag `I' or `O'!\n"); + return NULL; + } + + RetCode[0] = Char; + + if (condtion & RING_RING ) Char = 'R'; + else + if (condtion & RING_CONNECT ) Char = 'C'; + else + if (condtion & RING_BUSY ) Char = 'B'; + else + if (condtion & RING_AOCD ) Char = 'A'; + else + if (condtion & RING_ERROR ) Char = 'E'; + else + if (condtion & RING_HANGUP ) Char = 'H'; + else + if (condtion & RING_KILL ) Char = 'K'; + else + if (condtion & RING_SPEAK ) Char = 'S'; + else + if (condtion & RING_PROVIDER) Char = 'P'; + else + { + print_msg(PRT_ERR, "Internal error: Unknown flag %d for flag -S!\n",condtion); + return NULL; + } + + RetCode[1] = Char; + RetCode[2] = '\0'; + + return RetCode; +} + +/****************************************************************************/ + +int Start_Interval(void) +{ + interval *Ptr = RootIntervall; + time_t cur_time = time(NULL); + int RetCode = 0; + + while (Ptr != NULL) + { + if (Ptr->next_start <= cur_time) + { + RetCode += Start_Ring(Ptr->chan, Ptr->infoarg, Ptr->event, RING_INTERVAL); + Ptr->next_start = cur_time + Ptr->infoarg->interval; + } + + Ptr = Ptr->next; + } + + return RetCode; +} + +/****************************************************************************/ + +static interval *Next_Interval(void) +{ + interval *Ptr = RootIntervall; + interval *RetCode = NULL; + time_t next_time = 0; + + while (Ptr != NULL) + { + if (next_time == 0 || Ptr->next_start < next_time) + { + next_time = Ptr->next_start; + RetCode = Ptr; + } + + Ptr = Ptr->next; + } + + return RetCode; +} + +/****************************************************************************/ + +struct timeval *Get_Interval(int Sec) +{ + static struct timeval timeout; + interval *Ptr = NULL; + + + timeout.tv_usec = 0; + + if (Sec < 0) + Sec = 0; + + if ((Ptr = Next_Interval()) != NULL || Sec != 0) + { + if (Ptr != NULL && (timeout.tv_sec = (int) (Ptr->next_start - time(NULL))) < 0) + timeout.tv_sec = 0; + else if (Sec) + /* if (Sec != 0 && Sec < timeout.tv_sec) AK:06-Jun-96 */ + timeout.tv_sec = Sec; + } + else + return NULL; + + return &timeout; +} + +/****************************************************************************/ + +int Del_Interval(int chan, info_args *infoarg) +{ + interval **Ptr = &RootIntervall; + interval *Ptr2; + + while (*Ptr != NULL) + { + if ((*Ptr)->infoarg == infoarg && (*Ptr)->chan == chan) + { + Ptr2 = (*Ptr)->next; + free(*Ptr); + *Ptr = Ptr2; + return 0; + } + + Ptr = &((*Ptr)->next); + } + + return -1; +} + +/****************************************************************************/ + +int New_Interval(int chan, info_args *infoarg, int event) +{ + interval **Ptr = &RootIntervall; + + if (infoarg->interval == 0) + return -1; + + while (*Ptr != NULL) + Ptr = &((*Ptr)->next); + + if ((*Ptr = (interval*) calloc(1,sizeof(interval))) == NULL) + return -1; + + (*Ptr)->event = event; + (*Ptr)->infoarg = infoarg; + (*Ptr)->chan = chan; + (*Ptr)->next_start = infoarg->interval + time(NULL); + + return 0; +} + +/****************************************************************************/ + +int Start_Process(int chan, info_args *infoarg, int event) +{ + char *Opts[4]; + int InOut = call[chan].dialin?RING_INCOMING:RING_OUTGOING; + int sock = -1; + + Opts[0] = (char*) Set_Ringer_Flags(event,InOut); + Opts[1] = call[chan].num[CALLING]; + Opts[2] = call[chan].num[CALLED]; + Opts[3] = NULL; + + if ((infoarg->flag & event) && (infoarg->flag & InOut) && + CheckTime(infoarg->time) && /* wenn die angegebene Zeit passt */ + (sock = Ring(infoarg, Opts, 0, 0)) != -1 ) + { + sockets[sock].info_arg = infoarg; + sockets[sock].chan = chan; + sockets[sock].call_event = event; + } + + return sock<0?-1:0; +} + +/****************************************************************************/ + +int Start_Ring(int chan, info_args *infoarg, int event, int intervalflag) +{ + int ProcessStarted = 0; + char *Opts[4]; + int InOut = call[chan].dialin?RING_INCOMING:RING_OUTGOING; + int f = infoarg->flag; /* die Flags zu diesem Eintrag */ + int sock = 0; + + Opts[0] = (char*) Set_Ringer_Flags(event,InOut); + Opts[1] = call[chan].num[CALLING]; + Opts[2] = call[chan].num[CALLED]; + Opts[3] = NULL; + + if (intervalflag & RING_INTERVAL) + { + if (f & RING_KILL) + while ((sock = Get_Sock_From_Call_And_Info_Args(chan,infoarg,sock)) != -1) + if (sockets[sock].call_event == event) + Ring(NULL, NULL, sock++, 0); + else + sock++; + } + else + { + if (infoarg->interval != 0 && (event == RING_RING || event == RING_CONNECT)) + New_Interval(chan, infoarg, event); + } + + if (Condition_Changed(event,f)) + { + while ((sock = Get_Sock_From_Call_And_Info_Args(chan,infoarg,sock)) != -1) + Ring(NULL, NULL, sock++, 0); + + Del_Interval(chan,infoarg); + } + + /* Wenn Event (siehe oben) passt, und INCOMING/OUTGOING passen */ + + if (!((f & RING_UNIQUE) && + ((event == RING_RING) || (event == RING_CONNECT) )) || + Get_Sock_From_Call_And_Info_Args(chan,infoarg,0) == -1 ) + { + if ((f & event) && (f & InOut) && + CheckTime(infoarg->time) && /* wenn die angegebene Zeit passt */ + (sock = Ring(infoarg, Opts, 0, 0)) != -1 ) + { + sockets[sock].info_arg = infoarg; + sockets[sock].chan = chan; + sockets[sock].call_event = event; + ProcessStarted++; + } + } + + return ProcessStarted; +} + +/****************************************************************************/ + +int Change_Channel_Ring( int old_channel, int new_channel) +{ + interval *Ptr = RootIntervall; + int sock = 0; + + while ((sock = Get_Sock_From_Call( old_channel, sock )) >= 0) + { + sockets[sock].chan = new_channel; + } + + while (Ptr != NULL) + { + if (Ptr->chan == old_channel) + Ptr->chan = new_channel; + + Ptr = Ptr->next; + } + + return 0; +} + +/****************************************************************************/ + diff --git a/isdnlog/isdnlog/test_center.c b/isdnlog/isdnlog/test_center.c new file mode 100644 index 00000000..24c7a8c2 --- /dev/null +++ b/isdnlog/isdnlog/test_center.c @@ -0,0 +1,96 @@ +#include "isdnlog.h" + +void test_center (void) +{ +#if 0 + char File[256]; + int Cnt = 20000; + + sprintf(File,"%s%c%s",confdir(),C_SLASH,USERFILE); + + while(Cnt--) + { + utime(File,NULL); + /* sleep(1); */ + + if (read_user_access() != 0) + Exit(-1); + + if (write_user_access() != 0) + Exit(-1); + } +#elif 0 + int Cnt = 200000; + int Max = 0; + int add = 0, del = 0; + + while (Cnt--) + { + if (socket_size(sockets) == 0 || rand() % 2) + { + add++; + add_socket(&sockets,open("/dev/null",O_WRONLY)); + if (socket_size(sockets) > Max) Max = socket_size(sockets); + } + else + { + del++; + del_socket(&sockets,rand() % socket_size(sockets)); + } + } + + printf("Max: %d, del: %d, add: %d, RAND_MAX: %d\n",Max,del,add,RAND_MAX); + + Exit(-2); +#elif 0 + char User[256]; + char Host[256]; + + if (read_user_access() != 0) + Exit(-1); + + scanf("%s",User); + scanf("%s",Host); + printf("User:*%s*\n",User); + printf("Host:*%s*\n",Host); + + if (user_has_access(User,Host) == -1) + printf("Rejected\n"); + else + printf("Accepted\n"); + + Exit(-3); + /* Problem: Wenn Hosts vom Internet in der user-Datei sind, werden + diese beim Start von isdnlog auf Gueltigkeit geprueft + Loesung: Eintrag dieser Hosts in die /etc/hosts */ + /* Problem: Wenn Jeder Erdenbuerger von seiner Maschine Zugriff + auf meine Maschine haben soll */ +#elif 0 + char User[256]; + char Host[256]; + char MSN[256]; + int Flag; + + if (read_user_access() != 0) + Exit(-1); + + scanf("%s",User); + scanf("%s",Host); + scanf("%s",MSN); + scanf("%d",&Flag); + printf("User:*%s*\n",User); + printf("Host:*%s*\n",Host); + printf("MSN :*%s*\n",MSN); + printf("Flag:*%d*\n",Flag); + + if (User_Get_Message(User,Host,MSN,Flag) == -1) + printf("Rejected\n"); + else + printf("Accepted\n"); + + Exit(-3); +#elif 1 + readconfig("isdnlog"); + Exit(-4); +#endif +} diff --git a/isdnlog/isdnlog/user_access.c b/isdnlog/isdnlog/user_access.c new file mode 100644 index 00000000..4c80458e --- /dev/null +++ b/isdnlog/isdnlog/user_access.c @@ -0,0 +1,1018 @@ +/* + * ISDN accounting for isdn4linux. + * + * Copyright 1996 by Stefan Luethje (luethje@sl-gw.lake.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Alle Funktionen liefern im Fehlerfall -1 oder NULL */ + +/****************************************************************************/ + +#define _USER_ACCESS_C_ + +/****************************************************************************/ + +#include "isdnlog.h" + +#include +#include + +/****************************************************************************/ + +#define ANY -1 + +#define C_DELIMITER_FLAGS ';' +#define C_DELIMITER_FLAGOPTIONS ',' +#define C_DELIMITER_FLAG_AND_OPT '=' + +#define ALLOW_ALL "WORLD" + +/****************************************************************************/ + +typedef struct _access_flags{ + int type; + char **options; + struct _access_flags *next; +} access_flags; + +typedef struct _access_entry{ + char *name; + access_flags *flags; + struct _access_entry *next; +} access_entry; + +typedef struct _user_access{ + char *name; + access_entry *hosts; + access_entry *user; + struct _user_access *next; +} user_access; + +static struct ValidFlag{ + char *name; + int type; + int number; + int flag; +} ValidFlags[] = { + {"ALL", 0, 0, T_ALL}, + {"MSN", 1, ANY, 0}, + {"I4LCONF", 2, 0, T_I4LCONF}, + {"PROTOCOL", 3, 0, T_PROTOCOL}, + {"ADDRESSBOOK", 4, 0, T_ADDRESSBOOK}, + {NULL,0} +}; + +/****************************************************************************/ + +/* ACHTUNG: Alle #define's muessen mit der obigen Variable ValidFlags + abgestimmt sein. */ + +#define FLAG_ALL 0 +#define FLAG_MSN 1 +#define FLAG_I4LCONF 2 +#define FLAG_PROTOCOL 3 +#define FLAG_ADDRESSBOOK 4 + +/****************************************************************************/ + +static user_access *AllEntries = NULL; +static user_access *NewAllEntries = NULL; +static int NoName = 1; + +/****************************************************************************/ + +static int _read_file (void); +static char *Find_Section(char* String); +static int Clear_All (user_access **Cursor); +static int Set_Flags(access_flags **Cursor, char *String); +static int _Set_Entry (char* Name, char* User, char *Host, char *Flags); +static void free_user_access(user_access *Ptr); +static void free_access_entry(access_entry *Ptr); +static void free_access_flags(access_flags *Ptr); +static int write_entry(FILE *fp, user_access *Ptr); +static int write_user(FILE *fp, access_entry *Ptr); +static int write_hosts(FILE *fp, access_entry *Ptr); +static int write_flag(FILE *fp, access_flags *Ptr); +static int Check_Entries(void); +static int create_new_file(void); +static access_flags *Find_Data(user_access *Cursor, char *User, char *Host); +static int Find_Host(access_entry *Cursor, char *Host); +static char *IsFlag(char *Flag, int FlagIndex); +static access_flags *Set_Flag(char* Flag); +static char **Set_Options(char *String); +static int return_for_user_access(access_flags *Ptr); + +/****************************************************************************/ + +int read_user_access( void ) +{ + int RetCode = -1; + static int ModTime = -2; + static struct stat FileStat; + + /* Erster Durchlauf von read_user_access() */ + if (ModTime == -2) + { + if (stat(userfile(),&FileStat) != 0 && errno == ENOENT) + if ((RetCode = create_new_file()) == 0) + stat(userfile(),&FileStat); + else + /* Return, weil keine Date existiert und nicht angelegt werden kann */ + return RetCode; + + ModTime = FileStat.st_mtime; + } + else + { + ModTime = FileStat.st_mtime; + stat(userfile(),&FileStat); + + /* Wenn das File seit dem Letzten Lesen nicht mehr geaendert wurde, + dann wieder zurueck, sonst wieder neu einlesen */ + + if (ModTime == FileStat.st_mtime) + /* Alles beim alten */ + return 0; + } + + if ((RetCode = Clear_All(&NewAllEntries)) != 0) + return RetCode; + + if ((RetCode = _read_file()) != 0) + return RetCode; + + if ((RetCode = Clear_All(&AllEntries)) != 0) + return RetCode; + + AllEntries = NewAllEntries; + NewAllEntries = NULL; + + return 0; +} + +/****************************************************************************/ + +static int _read_file (void) +{ + int Line = 0; + int RetCode; + FILE *fp; + char String[SHORT_STRING_SIZE]; + char User[SHORT_STRING_SIZE]; + char Host[SHORT_STRING_SIZE]; + char Name[SHORT_STRING_SIZE]; + char dummy[SHORT_STRING_SIZE]; + char Flags[SHORT_STRING_SIZE]; + char *Ptr; + + + if ((fp = fopen(userfile(), "r")) == NULL) + { + print_msg(PRT_ERR,"Can't open \"%s\" (%s)\n",userfile(),strerror(errno)); + return -1; + } + + while (FGets(String, BUFSIZ, fp, &Line) != NULL) + { + Name[0] = User[0] = Host[0] = Flags[0] = '\0'; + + if (*String != '\0' && *String != '\n') + { + if ((Ptr = Find_Section(String)) != NULL) + { + strcpy(Name,Ptr); + To_Upper(Name); + print_msg(PRT_DEBUG_CS,"Name:*%s*\n",Name); + } + else + if (NoName) + { + if (sscanf(String,"%[^@]@%s %[^\n]",User,Host,Flags) >= 2) + print_msg(PRT_DEBUG_CS,"User:*%s* Host:*%s* Flags:*%s*\n",User,Host,Flags); + else + { + print_msg(PRT_ERR,"File \"%s\": error in line %d!\n",userfile(),Line); + Name[0] = User[0] = Host[0] = Flags[0] = '\0'; + } + } + else + { + if (sscanf(String,"%[^@]@%s %[^\n]",User,Host,Flags) >= 2) + { + print_msg(PRT_ERR,"File \"%s\": error in line %d!\n",userfile(),Line); + Name[0] = User[0] = Host[0] = Flags[0] = '\0'; + } + else + if ((RetCode = sscanf(String,"@%s %[^\n]",Host,dummy)) == 1) + print_msg(PRT_DEBUG_CS,"Host:*%s* Flags:*%s*\n",Host,Flags); + else + if (RetCode == 0 && sscanf(String,"%s %[^\n]",User,Flags) >= 1) + print_msg(PRT_DEBUG_CS,"User:*%s* Flags:*%s*\n",User,Flags); + else + { + print_msg(PRT_ERR,"File \"%s\": error in line %d!\n",userfile(),Line); + Name[0] = User[0] = Host[0] = Flags[0] = '\0'; + } + } + } + + if ((RetCode = _Set_Entry(Name,User,Host,Flags)) != 0) + return RetCode; + } + + Check_Entries(); + + fclose(fp); + return 0; +} + +/****************************************************************************/ + +static char *Find_Section(char* String) +{ + char *Ptr = NULL; + char Help[SHORT_STRING_SIZE]; + + + strcpy(Help,String); + String = Kill_Blanks(Help); + + if (*String == '\0' || *String != '[') + return NULL; + + Ptr = String + strlen(String)-1; + if (Ptr == strchr(String,']')) + { + *Ptr = '\0'; + return String+1; + } + + return NULL; +} + +/****************************************************************************/ + +static int Set_Flags(access_flags **Cursor, char *String) +{ + int Cnt = 0; + int RetCode = 0; + char **Ptr = NULL; + + if (String == NULL) + return RetCode; + + String = Kill_Blanks(To_Upper(String)); + + print_msg(PRT_DEBUG_CS,"Short Flags:*%s*\n",String); + + if ((Ptr = String_to_Array(String,C_DELIMITER_FLAGS)) != NULL) + while (Ptr[Cnt] != NULL) + { + if (Ptr[Cnt][0] != '\0') + { + *Cursor = Set_Flag(Ptr[Cnt]); + Cursor = &((*Cursor)->next); + } + + Cnt++; + } + + del_Array(Ptr); + + return RetCode; +} + +/****************************************************************************/ + +static access_flags *Set_Flag(char* Flag) +{ + int Cnt = 0; + char *Ptr; + access_flags *RetCode = NULL; + + if (*Flag == '\0') + return NULL; + + print_msg(PRT_DEBUG_CS,"One Flag:*%s*\n",Flag); + + while (ValidFlags[Cnt].name != NULL) + { + if ((Ptr = IsFlag(Flag,Cnt)) != NULL) + { + print_msg(PRT_DEBUG_CS,"Found Flag:*%s*\n",ValidFlags[Cnt].name); + + if ((RetCode = (access_flags*) calloc(1,sizeof(access_flags))) == NULL) + { + print_msg(PRT_ERR,"Can't alloc memory!\n"); + Exit(26); + } + + RetCode->type = ValidFlags[Cnt].type; + + if (ValidFlags[Cnt].number != 0) + RetCode->options = Set_Options(Ptr); + + return RetCode; + } + + Cnt++; + } + + print_msg(PRT_ERR,"Error: invalid Flag \"%s\"!\n",Flag); + + return RetCode; +} + +/****************************************************************************/ + +static char *IsFlag(char *Flag, int FlagIndex) +{ + char *RetCode = NULL; + int Len = strlen(ValidFlags[FlagIndex].name); + + if ((RetCode = strstr(Flag,ValidFlags[FlagIndex].name)) != NULL && + Flag == RetCode ) + { + if (ValidFlags[FlagIndex].number == 0) + { + if (Flag[Len] == '\0') + return RetCode; + } + else + { + if (*(RetCode = &(Flag[Len])) == C_DELIMITER_FLAG_AND_OPT ) + return (RetCode+1); + else + { + print_msg(PRT_ERR,"Warning: invalid option string \"%s\"!\n",Flag); + return NULL; + } + } + } + + return NULL; +} + +/****************************************************************************/ + +static char **Set_Options(char *String) +{ + int Cnt = 0; + int Size = 2; + char **Ptr = NULL; + char **Options = NULL; + + if ((Ptr = String_to_Array(String,C_DELIMITER_FLAGOPTIONS)) != NULL) + while (Ptr[Cnt] != NULL) + { + if (Ptr[Cnt][0] != '\0') + { + if ((Options = (char**) realloc(Options,sizeof(char*)*Size)) == NULL) + { + print_msg(PRT_ERR,"Can't alloc memory!\n"); + Exit(25); + } + + Options[Size-1] = NULL; + if ((Options[Size-2] = (char*) calloc(strlen(Ptr[Cnt]),sizeof(char))) == NULL) + { + print_msg(PRT_ERR,"Can't alloc memory!\n"); + Exit(25); + } + else + strcpy(Options[Size-2],Ptr[Cnt]); + + print_msg(PRT_DEBUG_CS,"Option:*%s*\n",Options[Size-2]); + Size++; + } + + Cnt++; + } + + del_Array(Ptr); + return Options; +} + +/****************************************************************************/ + +static int Check_Entries(void) +{ + user_access *Cursor = NewAllEntries; + + if (Cursor == NULL) + print_msg(PRT_WARN,"Warning: file \"%s\" is empty!\n",userfile()); + + while(Cursor) + { + if (Cursor->name == NULL) + { + if (Cursor->hosts == NULL) + print_msg(PRT_WARN, + "Warning: file \"%s\" in the first section has no host!\n",userfile()); + + if (Cursor->user == NULL) + print_msg(PRT_WARN, + "Warning: file \"%s\" in the first section has no user!\n",userfile()); + else + if (Cursor->user->flags == NULL) + print_msg(PRT_WARN, + "Warning: file \"%s\" in the first section a user has no flags!\n",userfile()); + } + else + if (strcmp(Cursor->name,ALLOW_ALL)) + { + if (Cursor->hosts == NULL) + print_msg(PRT_WARN, + "Warning: file \"%s\" in section \"%s\" has no host!\n",userfile(),Cursor->name); + + if (Cursor->user == NULL) + print_msg(PRT_WARN, + "Warning: file \"%s\" in section \"%s\" has no user!\n",userfile(),Cursor->name); + else + if (Cursor->user->flags == NULL) + print_msg(PRT_WARN, + "Warning: file \"%s\" in section \"%s\" a user has no flags!\n",userfile(),Cursor->name); + } + + Cursor = Cursor->next; + } + + return 0; +} + +/****************************************************************************/ + +static int _Set_Entry (char* Name, char* User, char *Host, char *Flags) +{ + char *NewHost; + access_entry **Ptr = NULL; + static user_access **Cursor = NULL; + + if (*Name == '\0' && *User == '\0' && *Host == '\0') + return 0; + + if (!strcmp(Name,ALLOW_ALL) || + (NewAllEntries != NULL && NewAllEntries->name != NULL && + !strcmp(NewAllEntries->name,ALLOW_ALL) ) ) + { + if (*Name != '\0' && NewAllEntries != NULL) + print_msg(PRT_WARN, + "Warning: There is more than section \"%s\" in user access!\n",ALLOW_ALL); + + Clear_All(&NewAllEntries); + strcpy(Name,ALLOW_ALL); + *User = *Host = '\0'; + } + + if (NewAllEntries == NULL) + { + Cursor = &NewAllEntries; + NoName = 1; + } + + if (NoName || *Name != '\0') + if (*Cursor != NULL) + { + Cursor = &((*Cursor)->next); + } + + if (*Cursor == NULL) + { + if ((*Cursor = (user_access*) calloc(1,sizeof(user_access))) == NULL) + { + print_msg(PRT_ERR,"Can't alloc memory!\n"); + Exit(28); + } + } + + if (*Name != '\0') + { + NoName = 0; + + if (((*Cursor)->name = (char*) calloc(strlen(Name)+1,sizeof(char))) == NULL) + { + print_msg(PRT_ERR,"Can't alloc memory!\n"); + Exit(28); + } + + strcpy((*Cursor)->name,Name); + } + else + { + if (*User != '\0') + { + Ptr = &((*Cursor)->user); + + while (*Ptr) + Ptr = &((*Ptr)->next); + + if ((*Ptr = (access_entry*) calloc(1,sizeof(access_entry))) == NULL) + { + print_msg(PRT_ERR,"Can't alloc memory!\n"); + Exit(28); + } + + if (((*Ptr)->name = (char*) calloc(strlen(User)+1,sizeof(char))) == NULL) + { + print_msg(PRT_ERR,"Can't alloc memory!\n"); + Exit(28); + } + + strcpy((*Ptr)->name,User); + + if (*Flags != '\0') + Set_Flags(&((*Ptr)->flags),Flags); + else + print_msg(PRT_WARN,"Warning: User \"%s\" has no Flags!\n",User); + } + + if (*Host != '\0') + if ((NewHost = GetHostByName(Host)) != NULL) + { + Ptr = &((*Cursor)->hosts); + + while (*Ptr) + Ptr = &((*Ptr)->next); + + if ((*Ptr = (access_entry*) calloc(1,sizeof(access_entry))) == NULL) + { + print_msg(PRT_ERR,"Can't alloc memory!\n"); + Exit(28); + } + + (*Ptr)->name = NewHost; + } + else + print_msg(PRT_WARN,"Warning: unknown host \"%s\"!\n",Host); + } + + return 0; +} + +/****************************************************************************/ + +static int Clear_All (user_access **Cursor) +{ + NoName = 1; + + if (*Cursor != NULL) + { + free_user_access(*Cursor); + *Cursor = NULL; + } + + return 0; +} + +/****************************************************************************/ + +static void free_user_access(user_access *Ptr) +{ + if (Ptr != NULL) + { + free_user_access(Ptr->next); + free_access_entry(Ptr->user); + free_access_entry(Ptr->hosts); + free(Ptr->name); + free(Ptr); + } + else + return; +} + +/****************************************************************************/ + +static void free_access_entry(access_entry *Ptr) +{ + if (Ptr != NULL) + { + free_access_entry(Ptr->next); + free_access_flags(Ptr->flags); + free(Ptr->name); + free(Ptr); + } + else + return; +} + +/****************************************************************************/ + +static void free_access_flags(access_flags *Ptr) +{ + int Cnt = 0; + + + if (Ptr != NULL) + { + free_access_flags(Ptr->next); + + if (Ptr->options != NULL) + { + while(Ptr->options[Cnt] != NULL) + free(Ptr->options[Cnt++]); + + free(Ptr->options); + } + + free(Ptr); + } + else + return; +} + +/****************************************************************************/ + +int write_user_access( void ) +{ + int RetCode = 0; + FILE *fp; + char Time[SHORT_STRING_SIZE] = ""; + time_t _Time = time(NULL); + + NoName = 1; + + + strftime(Time,SHORT_STRING_SIZE,"%c",localtime(&_Time)); + + if (AllEntries == NULL) + { + print_msg(PRT_ERR,"Error: file \"%s\": there are no user data!\n",userfile(),strerror(errno)); + return -1; + } + + if ((fp = fopen(userfile(), "w")) == NULL) + { + print_msg(PRT_ERR,"Can't open \"%s\" (%s)\n",userfile(),strerror(errno)); + return -1; + } + + fprintf(fp,"%s\n","###############################################################################"); + fprintf(fp,"%s\n","#"); + fprintf(fp,"%s %s %s on %s\n","#","Generated by isdnlog",VERSION,Time); + fprintf(fp,"%s\n","#"); + fprintf(fp,"%s\n\n","###############################################################################"); + + write_entry(fp,AllEntries); + + fclose(fp); + + return RetCode; +} + +/****************************************************************************/ + +static int write_entry(FILE *fp, user_access *Ptr) +{ + int RetCode = -1; + + if (Ptr == NULL) + return 0; + + if (Ptr->name == NULL || *(Ptr->name) == '\0') + { + if (NoName == 0) + { + print_msg(PRT_ERR,"%s\n","Internal error: file \"%s\": invalid user data in section with name",userfile()); + return RetCode; + } + + if (Ptr->user == NULL || Ptr->user->name == NULL || Ptr->user->next != NULL || + Ptr->hosts == NULL || Ptr->hosts->name == NULL || Ptr->hosts->next != NULL) + { + print_msg(PRT_ERR,"%s\n","Internal error: file \"%s\": invalid user data in section no name",userfile()); + return RetCode; + } + + fprintf(fp,"%s@%s",Ptr->user->name,Ptr->hosts->name); + + if (Ptr->user->flags) + if ((RetCode = write_flag(fp,Ptr->user->flags)) != 0) + return RetCode; + + fprintf(fp,"\n"); + } + else + { + NoName = 0; + + fprintf(fp,"\n[%s]\n",Ptr->name); + + if ((RetCode = write_user(fp,Ptr->user)) != 0) + return RetCode; + + if ((RetCode = write_hosts(fp,Ptr->hosts)) != 0) + return RetCode; + } + + return write_entry(fp,Ptr->next); +} + +/****************************************************************************/ + +static int write_flag(FILE *fp, access_flags *Ptr) +{ + int First = 1; + char** Cursor = NULL; + + if (Ptr != NULL) + { + Cursor = Ptr->options; + fprintf(fp," %s",ValidFlags[Ptr->type].name); + + if (Cursor != NULL) + { + fprintf(fp,"%c",C_DELIMITER_FLAG_AND_OPT); + + while(*Cursor != NULL) + { + if (!First) + fprintf(fp,"%c",C_DELIMITER_FLAGOPTIONS); + + fprintf(fp,"%s",*Cursor); + Cursor++; + + First = 0; + } + + } + + fprintf(fp,"%c",C_DELIMITER_FLAGS); + write_flag(fp,Ptr->next); + } + + return 0; +} + +/****************************************************************************/ + +static int write_user(FILE *fp, access_entry *Ptr) +{ + int RetCode = 0; + + + if (Ptr != NULL) + { + if (Ptr->name != NULL) + fprintf(fp,"%s",Ptr->name); + else + { + print_msg(PRT_ERR,"%s\n","Internal error: file \"%s\": user has no name!\n",userfile()); + return -1; + } + + if (Ptr->flags != NULL) + if ((RetCode = write_flag(fp,Ptr->flags)) != 0) + return RetCode; + + fprintf(fp,"\n"); + + return write_user(fp,Ptr->next); + } + + return 0; +} + +/****************************************************************************/ + +static int write_hosts(FILE *fp, access_entry *Ptr) +{ + if (Ptr != NULL) + { + if (Ptr->name != NULL) + fprintf(fp,"@%s\n",Ptr->name); + else + { + print_msg(PRT_ERR,"%s\n","Internal error: file \"%s\": host has no name!\n",userfile()); + return -1; + } + + if (Ptr->flags != NULL) + { + print_msg(PRT_ERR,"%s\n","Internal error: file \"%s\": host has flags!\n",userfile()); + return -1; + } + + return write_hosts(fp,Ptr->next); + } + + return 0; +} + +/****************************************************************************/ + +static int create_new_file(void) +{ + int RetCode = 0; + struct passwd *password; + char Name[SHORT_STRING_SIZE]; + + + strcpy(Name,ValidFlags[FLAG_ALL].name); + + print_msg(PRT_WARN,"Warning: no file \"%s\" exists.\nIt will be created a default file. Please edit it!\n",userfile()); + + if (AllEntries != NULL) + { + print_msg(PRT_WARN,"Internal warning: entries but no file \"%s\"!\n",userfile()); + + if ((RetCode = Clear_All(&AllEntries)) != 0) + return RetCode; + } + + if ((RetCode = Clear_All(&NewAllEntries)) != 0) + return RetCode; + + _Set_Entry("isdnlog-local","","",""); + _Set_Entry("","","localhost",""); + + setpwent(); + while ((password = getpwent()) != NULL) + { + _Set_Entry("",password->pw_name,"",Name); + } + endpwent(); + + AllEntries = NewAllEntries; + NewAllEntries = NULL; + + return write_user_access(); +} + +/****************************************************************************/ + +int user_has_access(char *User, char *Host) +{ + /* ACHTUNG IN DIESER FKT DARF KEIN print_msg() AUFGERUFEN WERDEN !!!!! */ + access_flags *Ptr = NULL; + int RetCode = -1; + + if (AllEntries != NULL && !strcmp(AllEntries->name,ALLOW_ALL)) + return T_ALL; + + if (Host == NULL || *Host == '\0' || User == NULL || *User == '\0') + return -1; + + if ((Ptr = Find_Data(AllEntries,User,Host)) != NULL) + RetCode = return_for_user_access(Ptr); + + return RetCode; +} + +/****************************************************************************/ + +static access_flags *Find_Data(user_access *Cursor, char *User, char *Host) +{ + /* ACHTUNG IN DIESER FKT DARF KEIN print_msg() AUFGERUFEN WERDEN !!!!! */ + access_entry *Ptr = NULL; + + + if (Cursor == NULL) + return NULL; + + Ptr = Cursor->user; + + while (Ptr) + { + if (!strcmp(Ptr->name,User) && Find_Host(Cursor->hosts,Host) == 0) + return Ptr->flags; + + Ptr = Ptr->next; + } + + return Find_Data(Cursor->next,User,Host); +} + +/****************************************************************************/ + +static int Find_Host(access_entry *Cursor, char *Host) +{ + /* ACHTUNG IN DIESER FKT DARF KEIN print_msg() AUFGERUFEN WERDEN !!!!! */ + while(Cursor) + { + if (Cursor->name != NULL) + if (!strcmp(Cursor->name,Host)) + return 0; + + Cursor = Cursor->next; + } + + return -1; +} + +/****************************************************************************/ + +int User_Get_Message(char *User, char *Host, char* mymsn, int Flag) +{ + /* Hier muss ueberprueft werden, ob der User die MSG vom Server erhalten + darf. */ + /* Die Bedingung der Fkt. gilt als erfuellt, wenn entweder die MSN + oder ein Flag uebereinstimmt. */ + /* ACHTUNG IN DIESER FKT DARF KEIN print_msg() AUFGERUFEN WERDEN !!!!! */ + + access_flags *Ptr = NULL; + char Help[SHORT_STRING_SIZE]; + char **Options = NULL; + int Cnt; + int RetCode = -1; + + + if (Host == NULL || *Host == '\0' || User == NULL || *User == '\0') + return RetCode; + + if (AllEntries != NULL && !strcmp(AllEntries->name,ALLOW_ALL)) + return 0; + + if ((Ptr = Find_Data(AllEntries,User,Host)) != NULL) + while (Ptr) + { + /* Damit ALL ueberall (auch bei MSN) seine Wirkung erhaelt: */ + if (Ptr->type == FLAG_ALL) + return 0; + + if (mymsn != NULL && Ptr->type == FLAG_MSN) + { + Cnt = 0; + Options = Ptr->options; + + if (Options) + while(Options[Cnt] != NULL) + { + if (Options[Cnt][0] == '*') + strcpy(Help,Options[Cnt]); + else + sprintf(Help,"%c%s",'*',Options[Cnt]); + + /* ACHTUNG: match("","*") ist false -> Workaround */ + if (!match(Help,mymsn,0) || (*mymsn == '\0' && !strcmp(Options[Cnt],"*"))) + return 0; + + Cnt++; + } + } + + if ((ValidFlags[Ptr->type].flag & Flag) != 0) + return 0; + + Ptr = Ptr->next; + } + + return RetCode; +} + +/****************************************************************************/ + +static int return_for_user_access(access_flags *Ptr) +{ + /* ACHTUNG IN DIESER FKT DARF KEIN print_msg() AUFGERUFEN WERDEN !!!!! */ + int RetCode = -1; + + + if (Ptr == NULL) + return RetCode; + + RetCode = ValidFlags[Ptr->type].flag; + + if (Ptr->next != NULL) + RetCode = RetCode | return_for_user_access(Ptr->next); + + return RetCode; +} + +/****************************************************************************/ + +const char *userfile(void) +{ + static char File[LONG_STRING_SIZE] = ""; + + + if (*File == '\0') + { + sprintf(File,"%s%c%s",confdir(),C_SLASH,USERFILE); + + if (*File == '\0') + { + print_msg(PRT_ERR,"%s\n","Invalid filename for user access!"); + Exit(23); + } + } + + return File; +} + +/****************************************************************************/ + diff --git a/isdnlog/isdnrep/cheap.c b/isdnlog/isdnrep/cheap.c new file mode 100644 index 00000000..3ae15d51 --- /dev/null +++ b/isdnlog/isdnrep/cheap.c @@ -0,0 +1,485 @@ +/* $Id: cheap.c,v 1.1 1997/03/16 20:59:02 luethje Exp $ + * + * ISDN accounting for isdn4linux. (Feiertagsberechnung) + * + * 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: cheap.c,v $ + * Revision 1.1 1997/03/16 20:59:02 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.24 1997/01/12 20:51:21 akool + * City Weekend Tarif implemented (Thanks to Oliver Schoett ) + * + * Revision 2.6.11 1996/12/30 10:05:21 Ad Aerts + * Dutch accounting + * + * Revision 2.50 1996/08/24 10:47:21 akool + * Korrektur bei Taktberechnung Wochenende/Feiertage (Jochen Heuer) + * + * Revision 2.43 1996/07/04 09:52:21 akool + * Korrektur bei Taktberechnung City (Jochen Heuer) + * + * Revision 2.40 1996/06/19 01:55:21 akool + * Neue Tarife ab 1.7.96 implementiert + * + * Revision 2.3.27 1996/05/06 17:51:21 akool + * Korrektur bei Taktberechnung Regio 200 + * + * Revision 2.01 1996/01/19 19:12:21 akool + * Korrektur bei Taktberechnung (Citytarif, 5:00 .. 9:00 war 240s, muss + * aber 150s heissen!) + * + * Revision 2.00 1996/01/10 20:10:21 akool + * + * Revision 1.22 1995/10/21 17:23:21 akool + * Tarife 1996 entsprechend Telekom-Unterlagen korrigiert + * + * Revision 1.14 1995/10/05 19:02:21 akool + * Ueberschreitung verschiedener Zeittakte bei einer Verbindung implementiert. + * + * Revision 1.2 1995/09/30 16:39:21 akool + * Um neue Tarifstruktur der Telekom ab 1.1.96 erweitert + * First public release + * + * Revision 1.1 1990/11/10 23:15:11 akool + * Initial revision (Code-Teile aus irgend einer alten c't) + * + */ + + +#include "isdnrep.h" + +#define MUTT 3 +#define KARF 4 +#define OST1 5 +#define OST2 6 +#define CHRI 7 +#define PFI1 8 +#define PFI2 9 +#define FRON 10 +#define EINH 11 +#define MARI 12 +#define ALLE 13 +#define BUSS 14 + +#define A_FEI 17 + +struct w_ftag { + char tag; + char monat; + char telekom; /* TRUE, wenn auch fuer die Deutsche Telekom ein Feiertag (siehe Telefonbuch!) */ +}; + + +static struct { + int tag; + int monat; + int jahr; + int tgind; +} _datum; + + +static char tab_tage[2][12] = {{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }}; + +static struct w_ftag t_ftag[A_FEI] = { +#ifdef ISDN_NL + { 1, 1, 1 }, /* Neujahr */ + { 6, 1, 0 }, /* Erscheinungsfest - nur Baden-Wuerttemberg und Bayern */ + { 1, 5, 0 }, /* Maifeiertag */ + { 0, 0, 0 }, /* Muttertag */ + { 0, 0, 0 }, /* Karfreitag */ + { 0, 0, 1 }, /* Ostersonntag */ + { 0, 0, 1 }, /* Ostermontag */ + { 0, 0, 0 }, /* Christi Himmelfahrt */ + { 0, 0, 1 }, /* Pfingstsonntag */ + { 0, 0, 1 }, /* Pfingstmontag */ + { 0, 0, 0 }, /* Fronleichnam - nur in Baden-Wuerttemberg, Bayern, Hessen, Nordrhein-Westfalen, Rheinland-Pfalz und im Saarland */ + { 3, 10, 0 }, /* Tag der deutschen Einheit - vor 1990 am 17.6. */ + { 15, 8, 0 }, /* Maria Himmelfahrt - nur Saarland und ueberwiegend katholischen Gemeinden Bayerns */ + { 1, 11, 0 }, /* Allerheiligen - nur Baden-Wuerttemberg, Bayern, Nordrhein-Westfalen, Rheinland-Pfalz und im Saarland */ + { 0, 0, 0 }, /* Buss- und Bettag - nur bis incl. 1994 (wg. Pflegeversicherung abgeschafft) */ + { 25, 12, 1 }, /* 1. Weihnachtsfeiertag */ + { 26, 12, 1 }}; /* 2. Weihnachtsfeiertag */ +#else + { 1, 1, 1 }, /* Neujahr */ + { 6, 1, 0 }, /* Erscheinungsfest - nur Baden-Wuerttemberg und Bayern */ + { 1, 5, 1 }, /* Maifeiertag */ + { 0, 0, 1 }, /* Muttertag */ + { 0, 0, 1 }, /* Karfreitag */ + { 0, 0, 1 }, /* Ostersonntag */ + { 0, 0, 1 }, /* Ostermontag */ + { 0, 0, 1 }, /* Christi Himmelfahrt */ + { 0, 0, 1 }, /* Pfingstsonntag */ + { 0, 0, 1 }, /* Pfingstmontag */ + { 0, 0, 0 }, /* Fronleichnam - nur in Baden-Wuerttemberg, Bayern, Hessen, Nordrhein-Westfalen, Rheinland-Pfalz und im Saarland */ + { 3, 10, 1 }, /* Tag der deutschen Einheit - vor 1990 am 17.6. */ + { 15, 8, 0 }, /* Maria Himmelfahrt - nur Saarland und ueberwiegend katholischen Gemeinden Bayerns */ + { 1, 11, 0 }, /* Allerheiligen - nur Baden-Wuerttemberg, Bayern, Nordrhein-Westfalen, Rheinland-Pfalz und im Saarland */ + { 0, 0, 0 }, /* Buss- und Bettag - nur bis incl. 1994 (wg. Pflegeversicherung abgeschafft) */ + { 25, 12, 1 }, /* 1. Weihnachtsfeiertag */ + { 26, 12, 1 }}; /* 2. Weihnachtsfeiertag */ +#endif + + +static int schalt(register int j) +{ + return(((j % 4 == 0) && (j % 100 != 0)) || (j % 400 == 0)); +} /* schalt */ + + +static int tag_num(register int t, register int m, register int j) +{ + register char *tm = tab_tage[schalt(j)]; + + while (--m) + t += *tm++; + + return(t); +} /* tag_num */ + + +static void num_tag(int jahr, int lfd) +{ + register int i; + register char *t; + + + while (lfd < 1) + lfd += tag_num(31, 12, --jahr); + + t = tab_tage[schalt(jahr)]; + + for (i = 1; lfd > *t && i < 13; i++) + lfd -= *t++; + + if (i > 12) + num_tag(++jahr, lfd); + else { + _datum.monat = i; + _datum.tag = lfd; + _datum.jahr = jahr; + } /* else */ +} /* num_tag */ + + +static void comp_feier_tage(int jj) +{ + static struct w_ftag t_stag[A_FEI]; + static int firsttime = 1; + static int l_jj = -1; + register int mm, tt, i, j, a, b; + + + if (jj == l_jj) + return; + + l_jj = jj; + + if (firsttime) { + for (i = 0; i < A_FEI; i++) + t_stag[i] = t_ftag[i]; + + firsttime = 0; + } + else + for (i = 0; i < A_FEI; i++) + t_ftag[i] = t_stag[i]; + + + /* Berechnung von Ostern nach C.F.Gauss */ + + i = jj / 100 - jj / 400 + 4; + j = i - jj / 300 + 11; + a = (((jj % 19) * 19) + j) % 30; + b = (((jj % 4) * 2 + (4 * jj) + (6 * a) + i) % 7) + a - 9; + + if (b < 1) { + tt = 31 + b; + mm = 3; + } + else { + if ((b == 26) || ((a == 28) && (b == 25) && ((11 * (j + 1) % 30) < 19))) + b -= 7; + tt = b; + mm = 4; + } /* else */ + + num_tag(jj, tag_num(tt, mm, jj)); + + t_ftag[OST1].monat = _datum.monat; t_ftag[OST1].tag = _datum.tag; + + num_tag(jj, 1 + tag_num(_datum.tag, _datum.monat, jj)); + t_ftag[OST2].monat = _datum.monat; t_ftag[OST2].tag = _datum.tag; + + num_tag(jj, - 3 + tag_num(_datum.tag, _datum.monat, jj)); + t_ftag[KARF].monat = _datum.monat; t_ftag[KARF].tag = _datum.tag; + + /* Pfingsten */ + num_tag(jj, 51 + tag_num(_datum.tag, _datum.monat, jj)); + t_ftag[PFI1].monat = _datum.monat; t_ftag[PFI1].tag = _datum.tag; + num_tag(jj, 1 + tag_num(_datum.tag, _datum.monat, jj)); + t_ftag[PFI2].monat = _datum.monat; t_ftag[PFI2].tag = _datum.tag; + + /* Himmelfahrt */ + num_tag(jj, -10 + tag_num(t_ftag[PFI1].tag, t_ftag[PFI1].monat, jj)); + t_ftag[CHRI].monat = _datum.monat; t_ftag[CHRI].tag = _datum.tag; + + /* Fronleichnam */ + num_tag(jj, 11 + tag_num(t_ftag[PFI1].tag, t_ftag[PFI1].monat, jj)); + t_ftag[FRON].monat = _datum.monat; t_ftag[FRON].tag = _datum.tag; +} /* comp_feier_tage */ + + +static int billig(time_t when) +{ + register int i; + auto struct tm *tm; + + + tm = localtime(&when); + + + if (tm->tm_wday == 6) /* Samstag immer */ + return(1); + + if (tm->tm_wday == 0) /* Sonntag immer */ + return(1); + + if ((tm->tm_hour > 17) || (tm->tm_hour < 8)) /* zwischen 18:00 .. 7:59 immer */ + return(1); + +#ifndef ISDN_NL + if ((tm->tm_mday == 24) && (tm->tm_mon == 11)) /* Heilig-Abend immer */ + return(1); + + if ((tm->tm_mday == 31) && (tm->tm_mon == 11)) /* Sylvester immer */ + return(1); + + comp_feier_tage(tm->tm_year + 1900); + + for (i = 0; i < A_FEI; i++) + if ((t_ftag[i].monat == tm->tm_mon + 1) && + (t_ftag[i].tag == tm->tm_mday) && + t_ftag[i].telekom) + return(1); +#endif + + return(0); /* Sorry, it's expensive! */ + +} /* billig */ + + +double cheap(time_t when, int zone) +{ + auto double takt = 0.0; + +#ifdef ISDN_NL + switch (zone) { + case 1 : takt = 1.000; break; /* local tariff Dfl 0.066/min */ + case 2 : takt = 0.316; break; /* long distance Dfl 0.2106/min */ + case 3 : takt = 0.074; break; /* International Dfl 0.90/min */ + case 4 : takt = 0.070; break; /* International Dfl 0.95/min */ + case 5 : takt = 0.060; break; /* International Dfl 1.10/min */ + } /* switch */ + + if (billig(when)) { + takt *= 2.0; + } /* if */ +#else + switch (zone) { + case 1 : takt = 360.00; break; + case 2 : takt = 60.00; break; + case 3 : takt = 21.00; break; + case 4 : takt = 21.00; break; + case 5 : takt = 12.00; break; + } /* switch */ + + if (billig(when)) { + if (takt == 12.00) + takt = 16.00; + else + takt *= 2.0; + } /* if */ +#endif + + return(takt); +} /* cheap */ + + +double cheap96(time_t when, int zone, int *zeit) +{ +#ifdef ISDN_NL + *zeit = 0; + return(cheap(when, zone)); +#else + register int i, takt = 0; + auto struct tm *tm; + + /* neue Tarife aus: iX 10/95, Pg 32 */ + static double gebuehr[3][5][5] = + {{{ 90.00, 90.00, 150.00, 240.00, 240.00 }, /* City */ + { 26.00, 30.00, 45.00, 60.00, 120.00 }, /* Region 50 */ + { 12.00, 13.50, 21.50, 30.00, 120.00 }, /* Region 200 */ + { 11.50, 12.50, 20.00, 25.00, 120.00 }, /* Fern */ + { 30.00, 30.00, 30.00, 30.00, 30.00 }}, /* Angrenzende Laender */ + + /* Tarife, Wochenendtarife ab 1.7.96 */ + {{ 90.00, 90.00, 150.00, 240.00, 240.00 }, /* City */ + { 26.00, 30.00, 45.00, 60.00, 120.00 }, /* Region 50 */ + { 13.00, 14.00, 22.50, 36.00, 120.00 }, /* Region 200 */ + { 12.00, 13.50, 21.50, 30.00, 120.00 }, /* Fern */ + { 26.00, 30.00, 45.00, 60.00, 60.00 }}, /* Vis-'a-vis 1 */ + + /* Tarife vom 27.-30.12., Feiertagstarife ab 1.7.96 */ + {{ 90.00, 90.00, 150.00, 240.00, 240.00 }, /* City */ + { 36.00, 36.00, 45.00, 60.00, 120.00 }, /* Region 50 */ + { 36.00, 36.00, 36.00, 36.00, 120.00 }, /* Region 200 */ + { 36.00, 36.00, 36.00, 36.00, 120.00 }, /* Fern */ + { 26.00, 30.00, 45.00, 60.00, 60.00 }}}; /* Vis-'a-vis 1 */ +/* Takt: 1 2 3 4 5 + + Werktag : + + 1 = Vormittag 9:00 .. 12:00 + 2 = Nachmittag 12:00 .. 18:00 + 3 = Freizeit 18:00 .. 21:00, 5:00 .. 9:00 + 4 = Mondschein 21:00 .. 2:00 + 5 = Nacht 2:00 .. 5:00 + + Wochenende/Feiertag : + + 3 = Freizeit 5:00 .. 21:00 + 4 = Mondschein 21:00 .. 5:00 + +*/ + + tm = localtime(&when); + + if ((tm->tm_wday == 6) || (tm->tm_wday == 0)) { /* Samstag/Sonntag */ + if ((tm->tm_hour > 4) && (tm->tm_hour < 21)) { + if (CityWeekend && (zone == 1)) + takt = 4; + else + takt = 3; + } + else + takt = 4; + } /* if */ + + if ((tm->tm_mday == 24) && (tm->tm_mon == 11)) /* Heilig-Abend */ + takt = 6; + + if ((tm->tm_mday == 31) && (tm->tm_mon == 11)) /* Sylvester */ + takt = 6; + + comp_feier_tage(tm->tm_year + 1900); + + for (i = 0; i < A_FEI; i++) + if ((t_ftag[i].monat == tm->tm_mon + 1) && + (t_ftag[i].tag == tm->tm_mday) && + t_ftag[i].telekom) + takt = 6; + + if ((!takt) || (zone == 5)) { + if ((tm->tm_hour > 8) && (tm->tm_hour < 12)) + takt = 1; + else if ((tm->tm_hour > 11) && (tm->tm_hour < 18)) + takt = 2; + else if ((tm->tm_hour > 20) || (tm->tm_hour < 2)) + takt = 4; + else if ((tm->tm_hour > 1) && (tm->tm_hour < 5)) + takt = 5; + else + takt = 3; + } /* if */ + + if (((tm->tm_year > 95) && (tm->tm_mon > 5)) || + (tm->tm_year > 96)) { /* Neuer Tarif ab 1.7.96 */ + if ((takt == 6) && (zone < 5)) { /* Feiertage */ + if ((tm->tm_hour > 4) && (tm->tm_hour < 21)) { + if (CityWeekend && (zone == 1)) { + *zeit = 8; + return(gebuehr[2][zone - 1][3]); + } + else + return(gebuehr[2][zone - 1][*zeit = 2]); + } + else + return(gebuehr[2][zone - 1][*zeit = 3]); + } + else if ((tm->tm_mon == 11) && /* Werktage vom 27.12. .. 30.12. */ + (tm->tm_mday > 26) && (zone < 5)) { + return(gebuehr[2][zone - 1][*zeit = --takt]); + } + else /* Werktage bzw. Wochenenden */ + return(gebuehr[1][zone - 1][*zeit = --takt]); + } + else { + if (zone == 5) { /* Angrenzende Laender */ + *zeit = 0; + return(30); + } + else { + if (takt == 6) { /* Feiertage */ + if ((tm->tm_hour > 4) && (tm->tm_hour < 21)) { + *zeit = 10; + return(gebuehr[0][zone - 1][2]); + } + else + return(gebuehr[0][zone - 1][*zeit = 3]); + } + else + return(gebuehr[0][zone - 1][*zeit = --takt]); + } /* else */ + } /* else */ +#endif +} /* cheap96 */ + + +#ifdef DEBUG_CHEAP +main() +{ + auto time_t cur_time, ltime; + auto struct tm *tm; + auto double o = 0.0, n; + + + time(&cur_time); + tm = localtime(&cur_time); + tm->tm_sec = 0; + tm->tm_min = 0; + tm->tm_hour = 0; + cur_time = ltime = mktime(tm); + + + while (cur_time - (7L * 24L * 60L * 60L) < ltime) { + n = cheap96(cur_time, 3); + + if (n != o) { + printf("%7.2f %s", n, ctime(&cur_time)); + o = n; + } /* if */ + + cur_time += 1L; /* (60L * 60L); */ + } /* while */ +} /* main */ +#endif diff --git a/isdnlog/isdnrep/isdnrep.1 b/isdnlog/isdnrep/isdnrep.1 new file mode 100644 index 00000000..5c4d998f --- /dev/null +++ b/isdnlog/isdnrep/isdnrep.1 @@ -0,0 +1,25 @@ +.TH ISDNREP 1 "ISDN Utilities" "AKsoftware" \" -*- nroff -*- +.SH NAME +isdnrep \- Gebuehrenabrechnung +.SH SYNOPSIS +.B isdnrep +[\-anvioN] [\-c Zone] [\-t Zeitabschnitt] [\-f logfile] [\-d Zeit] [\-p MSN] + +.SH DESCRIPTION +.BR isdnrep +wertet die von isdnlog(8) gesammelten Informationen aus, und erstellt +ueber einen frei waehlbaren Zeitraum eine Gebuehrenabrechnung. + +Fuer weitere Informationen siehe README +.SS OPTIONS +.TP +.I "\-V" +.B isdnrep +Print version information on standard output then exit successfully. +.SH FILES +.BR isdnrep +wertet ohne die Option "-f" die Datei +.BR "/var/log/isdn.log" +aus. +.SH BUGS +Z.Zt. keine bekannt ;-) diff --git a/isdnlog/isdnrep/isdnrep.c b/isdnlog/isdnrep/isdnrep.c new file mode 100644 index 00000000..545b32a8 --- /dev/null +++ b/isdnlog/isdnrep/isdnrep.c @@ -0,0 +1,1403 @@ +/* $Id: isdnrep.c,v 1.1 1997/03/16 20:59:05 luethje Exp $ + * + * ISDN accounting for isdn4linux. (Report-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: isdnrep.c,v $ + * Revision 1.1 1997/03/16 20:59:05 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.19 1997/01/04 13:00:35 akool + * Korrektur bzgl. ISDN_CH + * Danke an Markus Maeder (mmaeder@cyberlink.ch) + * + * Revision 2.6.15 1997/01/02 11:32:35 akool + * -V Option added + * + * Revision 2.6.11 1996/12/30 10:17:35 akool + * Dutch accounting (Ad Aerts ) + * + * Revision 2.50 1996/08/25 11:48:35 akool + * Auswertung bei non-AOCE-Anschluessen verbessert + * + * Revision 2.13 1996/03/16 16:11:35 akool + * Andruck der "ibytes" implementiert + * + * Revision 2.10 1996/01/16 01:04:35 sl + * Ausgabe von bestimmten MSN's ergaenzt, Nur ankommende dor ausgehende + * Gespraeche anzeigen, Ueberarbeitung der kompletten Sourcen. + * Funktion fuer fremde Waehrungen ergaenzt + * + * Revision 2.03 1996/01/07 03:35:17 sl + * Optionen -c und -6 entfernt, Tab-Bug behoben, Bug in automatischer + * Gebuehrenberechnung beim alten Logformat behoben, + * Zeitangabe beim Summary, + * + * Revision 2.02 1996/01/07 03:35:17 sl + * Zeitraumausgabe angepasst, loeschen von isdn.log-Eintraegen + * + * Revision 2.01 1996/01/06 18:15:20 sl + * Zeitraumausgabe, nur Calls-Anzeige, optionales Logfile + * + * Revision 2.00 1996/01/01 17:50:19 akool + * Auswertung der neuen Eintraege (I/O, Cause) implementiert + * Vollstaendiges Redesign + * + * Revision 1.25 1995/11/19 09:56:19 akool + * Neue Option "-c" aktiviert die eigene Berechnung der Einheiten bei + * fehlender Gebuehreninfo + * + * Revision 1.24 1995/11/12 11:09:19 akool + * Formatfelder vergroessert + * Fremdverursachte Einheiten werden ge-() + * Alle Floating-Point-Zahlen werden deutsch (mit Komma) ausgegeben + * + * Revision 1.23 1995/11/06 18:04:19 akool + * Denkfehler in der "-6" Berechnung :-( + * + * Revision 1.22 1995/10/22 15:31:19 akool + * Aufschluesselung bach Tarifzonen implementiert + * + * Revision 1.21 1995/10/17 19:53:19 akool + * Auf echte Charging-Info umgestellt + * + * Revision 1.20 1995/10/15 17:58:19 akool + * Vergleich errechnete zu uebermittelten Einheiten implementiert + * + * Revision 1.16 1995/10/12 13:50:19 akool + * Neue Option "MYMSNS=x" in der "isdnlog.conf" zum definieren der Anzahl + * eigener MSN's + * + * Revision 1.15 1995/10/09 18:42:18 akool + * Offensichtlich sinnlose Daten i.d. "isdn.log" werden nun ignoriert + * + * Revision 1.14 1995/10/08 10:25:16 akool + * Ueberschreitung verschiedener Zeittakte bei einer Verbindung implementiert. + * + * Revision 1.6 1995/09/30 19:55:17 akool + * First public release + * + * Revision 1.1 1995/09/23 16:44:19 akool + * Initial revision + * + */ + + +#include "isdnrep.h" + +/*****************************************************************************/ + +#define END_TIME 1 +#define STDOUT 0 +#define ERROUT 1 + +/*****************************************************************************/ + +#define LOG_VERSION_1 0 +#define LOG_VERSION_2 1 +#define LOG_VERSION_3 2 + +/*****************************************************************************/ + +static time_t get_month(char *String, int TimeStatus); +static time_t get_time(char *String, int TimeStatus); +static int get_term (char *String, time_t *Begin, time_t *End,int delentries); +static int set_msnlist(char *String); +static int show_msn(one_call *cur_call); +static int add_sum_calls(sum_calls *s1, sum_calls *s2); +static int print_sum_calls(sum_calls *s, int computed); +static int print_string(char *String, int outdir); +static int add_one_call(sum_calls *s1, one_call *s2, double units); +static int clear_sum(sum_calls *s1); +static char *print_currency(int units, double money, int Format); +static void strich(int type); +static int n_match(char *Pattern, char* Number, int version); + +/*****************************************************************************/ + +typedef struct { + char num[NUMSIZE]; + int called; + int connects; + time_t connect[MAXCONNECTS]; +} UNKNOWN; + +/*****************************************************************************/ + +static int invertnumbers = 0; +static int unknowns = 0; +static UNKNOWN unknown[MAXUNKNOWN]; +static int zones[MAXZONES]; +static int zones_usage[MAXZONES]; +static double zones_dm[MAXZONES]; +static double zones_dur[MAXZONES]; +static char** ShowMSN = NULL; + +/*****************************************************************************/ + +static char msg1[] = "%s: Can't open %s (%s)\n"; +static char usage[] = "%s: usage: %s [ -%s ]\n"; +static char wrongdate[] = "unknown date: %s\n"; +static char wrongdate2[] = "wrong date for delete: %s\n"; +static char nomemory[] = "Out of memory!\n"; + + +static char options[] = "ac:nviot:f:d:p:NV"; +static char fnbuff[512]; +static char *lfnam = LOGFILE; + +/*****************************************************************************/ + +int main(int argc, char *argv[], char *envp[]) +{ + register char *p, *p1, *p2; + register int i, j, k, n, cc; + auto FILE *fi, *ftmp = NULL; + auto char string[BUFSIZ], s[BUFSIZ], s1[BUFSIZ]; + auto char start[20], stop[20], timestring[256] = ""; + auto char tmp_string[256]; + auto char tmpfile[256]; + auto int hit, lday = -1; + auto double restdm = 0.0; + auto int computed, go, zone = 1; + auto int compute = 0, zeit; + extern int errno; + auto time_t now, from = (time_t)0; + auto time_t begintime, endtime; + auto double t1, t2, takt; + auto struct tm *tm; + auto double einheit = 0.23; + auto int nx[2]; + auto int Tarif96 = 0, Tarif962 = 0, c, notforus, resteh = 0; + auto double restdur = 0.0, restidur = 0.0; + auto int numbers = 0, restusage = 0; + auto int restiusage = 0; + auto int verbose = 0; + auto int timearea = 0, phonenumberonly = 0; + auto int delentries = 0; + auto int incomingonly = 0; + auto int outgoingonly = 0; + one_call cur_call; + sum_calls day_sum, day_com_sum, all_sum, all_com_sum, tmp_sum; + char *myname = basename(argv[0]); + + + set_print_fct_for_tools(printf); + + clear_sum(&day_sum); + clear_sum(&day_com_sum); + clear_sum(&all_sum); + clear_sum(&all_com_sum); + + use_new_config = 1; + + if (!currency_factor) + currency = "DM"; + + while ((c = getopt(argc, argv, options)) != EOF) + switch (c) { + case 'a' : timearea++; + begintime = 0; + time(&endtime); + break; + + case 'c' : compute = strtol(optarg, NIL, 0); + break; + + case 'i' : incomingonly++; + break; + + case 'o' : outgoingonly++; + break; + + case 'n' : numbers++; + break; + + case 'd' : delentries++; + + case 't' : strcpy(timestring, optarg); + if (!get_term(timestring,&begintime,&endtime,delentries)) + { + sprintf(tmp_string, wrongdate, timestring); + print_string(tmp_string,ERROUT); + return 1; + } + timearea++; + break; + + case 'v' : verbose++; + break; + + case 'f' : strcpy(fnbuff, optarg); + lfnam = fnbuff; + break; + + case 'p' : if (!phonenumberonly) set_msnlist(optarg); + phonenumberonly++; + break; + + case 'N' : use_new_config = 0; + break; + + case 'V' : print_version(myname); + exit(0); + + case '?' : sprintf(tmp_string, usage, argv[0], argv[0], options); + print_string(tmp_string,ERROUT); + return(1); + } /* switch */ + + if (readconfig(myname) != 0) + return 1; + + if (delentries) + if(begintime) + { + sprintf(tmp_string, wrongdate2, timestring); + print_string(tmp_string,ERROUT); + return 1; + } + else + { + sprintf(tmpfile,"/tmp/isdnrep%d",getpid()); + + if ((ftmp = fopen(tmpfile, "w")) == (FILE *)NULL) + { + sprintf(tmp_string, msg1, tmpfile, strerror(errno)); + print_string(tmp_string,ERROUT); + return(1); + } + } + + if (!timearea) { /* from darf nicht gesetzt werden, wenn alle Telefonate angezeigt werden sollen */ + time(&now); + /* aktuelle Zeit wird gesetzt */ + tm = localtime(&now); + /* Zeit von 1970 nach Struktur */ + tm->tm_sec = tm->tm_min = tm->tm_hour = 0; + from = mktime(tm); + /* Struktur nach Zeit von 1970 */ + /* from hat den aktuellen Tag 0.00 Uhr */ + } /* if */ + + if ((fi = fopen(lfnam, "r")) != (FILE *)NULL){ + + memset(zones, 0, sizeof(zones)); + + *start = 0; + + while (fgets(s, BUFSIZ, fi)) { + strcpy(string,s); + + if ((*s != '#') && (p = strchr(s, '|'))) { + /* hier wird das erste Trennzeichen gesucht */ + + cur_call.eh = notforus = 0; + cur_call.dir = -1; + cur_call.cause = -1; + /* Zeigt die Gespraechsrichtung an: rein oder raus */ + cur_call.ibytes = cur_call.obytes = 0L; + cur_call.version = 0.0; + cur_call.si = cur_call.si1 = 0; + + if ((p1 = p2 = strchr(p + 1, '|'))) { + do { + *p1-- = 0; /* p1 ist Zaehler fuer Anrufer */ + } while (isspace(*p1)); + + strcpy(cur_call.num[0], p + 1); + /* num[0] enthaelt die Anrufernummer */ + + p = p2 + 1; + + if ((p1 = p2 = strchr(p, '|'))) { + + do { + *p1-- = 0; + } while (isspace(*p1)); + + strcpy(cur_call.num[1], p); + /* num[1] enthaelt die angerufende Nummer */ + + p = p2 + 1; + + cur_call.duration = (double)atoi(p); + /* Gespraechsdauer auf sek. */ + + if ((p1 = p2 = strchr(p, '|'))) { + p = p2 + 1; + cur_call.duration = atoi(p) / 100.0; + /* Gespraechsdauer auf 100stel sek. */ + + if ((p1 = p2 = strchr(p, '|'))) { + p = p2 + 1; + cur_call.t = atol(p); + /* t ist Zeit seit 1970 von Gespraechsende ? */ + if ((p1 = p2 = strchr(p, '|'))) { /* Gebuehrenimpuls */ + p = p2 + 1; + cur_call.eh = atoi(p); + /* Verbrauchte Einheiten (-1 ist keine Angabe ?) */ + + if ((p1 = p2 = strchr(p, '|'))) { /* I/O */ + p = p2 + 1; + cur_call.dir = (*p == 'I') ? DIALIN : DIALOUT; + if ((p1 = p2 = strchr(p, '|'))) { /* Cause */ + p = p2 + 1; + cur_call.cause = atoi(p); + + if ((p1 = p2 = strchr(p, '|'))) { /* ibytes */ + p = p2 + 1; + cur_call.ibytes = atol(p); + + if ((p1 = p2 = strchr(p, '|'))) { /* obytes */ + p = p2 + 1; + cur_call.obytes = atol(p); + + if ((p1 = p2 = strchr(p, '|'))) { /* Version */ + p = p2 + 1; + cur_call.version = atof(p); + + if ((p1 = p2 = strchr(p, '|'))) { /* SI */ + p = p2 + 1; + cur_call.si = atoi(p); + + if ((p1 = p2 = strchr(p, '|'))) { /* SI11 */ + p = p2 + 1; + cur_call.si1 = atoi(p); + + if ((p1 = p2 = strchr(p, '|'))) { /* currency_factor */ + p = p2 + 1; + cur_call.currency_factor = atoi(p); + + if ((p1 = p2 = strchr(p, '|'))) { /* currency */ + p = p2 + 1; + strncpy(cur_call.currency, p, 3); + + if ((p1 = p2 = strchr(p, '|'))) { /* pay */ + p = p2 + 1; + cur_call.pay = atof(p); + } /* if */ + } /* if */ + } /* if */ + } /* if */ + } /* if */ + } /* if */ + } /* if */ + } /* if */ + } /* if */ + } /* if */ + } /* if */ + else + { + cur_call.dir = DIALOUT; + } + } + else + cur_call.t = atom(s); + /* Umrechnung des ersten Teilstring in Zeit von 1970 */ + } + else + cur_call.t = atom(s); + /* Umrechnung des ersten Teilstring in Zeit von 1970 */ + + if (!begintime) + begintime = cur_call.t; + + if (timearea) + { + if (delentries) + if (cur_call.t > endtime) + fputs(string,ftmp); + else + continue; + + if (cur_call.t < begintime || cur_call.t > endtime) + continue; + } + else + if (cur_call.t < from) + continue; /* Einlesen des naechsten Telefonats */ + + if (!verbose && cur_call.duration == 0) + continue; + + if (phonenumberonly) + + if (!show_msn(&cur_call)) +/* if (!show_msn(cur_call.num[cur_call.dir==DIALOUT?CALLING:CALLED])) */ + continue; + + if (incomingonly && cur_call.dir == DIALOUT) + continue; + + if (outgoingonly && cur_call.dir == DIALIN) + continue; + + tm = localtime(&(cur_call.t)); + /* Zeit von 1970 nach Struktur */ + day = tm->tm_mday; + month = tm->tm_mon; + + Tarif96 = tm->tm_year > 95; + + /* Ab Juli '96 gibt's noch mal eine Senkung in den Zonen 3 und 4 + genaue Preise sind jedoch noch nicht bekannt. FIX-ME */ + + Tarif962 = Tarif96 && (tm->tm_mon > 5); + + if (!currency_factor) +#ifdef ISDN_NL + einheit = 0.0011; /* cost of one second local tariff + during office hours */ +#elif defined(ISDN_CH) + einheit = 0.01; +#else + einheit = Tarif96 ? 0.12 : 0.23; +#endif + else + einheit = currency_factor; + + if (cur_call.duration > 172800.0) /* laenger als 2 Tage? Das KANN nicht sein! */ + cur_call.duration = 0; + + + for (n = CALLING; n <= CALLED; n++) { + + nx[n] = -1; + hit = 0; + + if (!*(cur_call.num[n])) { + if (!numbers) + { + cur_call.num[n][0] = C_UNKNOWN; + cur_call.num[n][1] = '\0'; + } + /* Wenn keine Nummer, dann Name "UNKNOWN" */ + + hit++; + } + else { + /* In der folg. Schleife werden Nummern durch Namen ersetzt */ + cc = 0; + + for (j = 0; ((j < 2) && !cc); j++) { + for (i = 0; i < knowns; i++) { + + if (*cur_call.num[n] != '0') { + + /* Alte Syntax der "isdn.log" : Ohne vorlaufene "0" */ + cc = ((known[i]->si == cur_call.si) || j) && + !match(known[i]->num+1, cur_call.num[n], LOG_VERSION_1); + + if (!cc) { + + /* Ganz alte Syntax der "isdn.log" : Ohne Vorwahl */ + cc = ((known[i]->si == cur_call.si) || j) && + !n_match(known[i]->num, cur_call.num[n], LOG_VERSION_1); + } /* if */ + } + else if (*(cur_call.num[n] + 1) != '0') { /* pre 2.6 Syntax : ohne int. Vorwahl */ + cc = ((known[i]->si == cur_call.si) || j) && + !n_match(known[i]->num, cur_call.num[n], LOG_VERSION_2); + } + else + cc = ((known[i]->si == cur_call.si) || j) && + !n_match(known[i]->num, cur_call.num[n], LOG_VERSION_3); + + if (cc) { + + + if (!numbers) + strcpy(cur_call.num[n], known[i]->who); + + + nx[n] = i; + + known[i]->usage[cur_call.dir]++; + /* Gesamte Anrufe auf gleiche Nummern werden gezeahlt */ + known[i]->dur[cur_call.dir] += cur_call.duration; + /* Gesamte Gespraechsdauer auf gleiche Nummern wird gezeahlt */ + + hit++; + break; + } /* if */ + + } /* for */ + } /* for */ + + /* In der naechsten Schleife werden die unbekannten Nummern + registriert */ + if (!hit) { + for (i = 0; i < unknowns; i++) + if (!strcmp(unknown[i].num, cur_call.num[n])) { + hit++; + break; + } /* if */ + + strcpy(unknown[i].num, cur_call.num[n]); + unknown[i].called = !n; + unknown[i].connect[unknown[i].connects] = cur_call.t; + + /* ACHTUNG: MAXCONNECTS und MAXUNKNOWN sollten unbedingt groesser sein ! */ + if (unknown[i].connects + 1 < MAXCONNECTS) + unknown[i].connects++; + else + { + sprintf(tmp_string, "%s: WARNING: Too many unknown connection's from %s\n", argv[0], unknown[i].num); + print_string(tmp_string,ERROUT); + } + + if (!hit) { + if (unknowns < MAXUNKNOWN) + unknowns++; + else + { + sprintf(tmp_string, "%s: WARNING: Too many unknown number's\n", argv[0]); + print_string(tmp_string,ERROUT); + } + } /* if */ + + } /* if */ + } /* else */ + } /* for */ + + + strcpy(s1, ctime(&cur_call.t)); + + if ((p = strchr(s1, '\n'))) + *p = 0; + + if (day != lday) { + if (lday == -1) { + time(&now); + sprintf(tmp_string,"I S D N Connection Report - %s", ctime(&now)); + print_string(tmp_string,STDOUT); + } + else { + strich(1); + print_sum_calls(&day_sum,0); + + if (day_com_sum.eh) + { + print_sum_calls(&day_com_sum,1); + + clear_sum(&tmp_sum); + add_sum_calls(&tmp_sum,&day_sum); + add_sum_calls(&tmp_sum,&day_com_sum); + strich(1); + print_sum_calls(&tmp_sum,0); + } + else + print_string("\n",STDOUT); + + add_sum_calls(&all_sum,&day_sum); + clear_sum(&day_sum); + + add_sum_calls(&all_com_sum,&day_com_sum); + clear_sum(&day_com_sum); + } /* if */ + + *(s1 + 10) = 0; + sprintf(tmp_string,"\n\n%s %s\n", s1, s1 + 20); + print_string(tmp_string,STDOUT); + lday = day; + + if (!*start) + { + sprintf(start, "%s %s", s1, s1 + 20); + sprintf(stop, "%s %s", s1, s1 + 20); + } + else + sprintf(stop, "%s %s", s1, s1 + 20); + + } /* if */ + + + *(s1 + 19) = 0; + + sprintf(tmp_string," %s %s", + s1 + 11, + double2clock(cur_call.duration)); + print_string(tmp_string,STDOUT); + + if (cur_call.dir) + { + sprintf(tmp_string," %14s <- %-14s", + cur_call.num[CALLED], cur_call.num[CALLING]); + print_string(tmp_string,STDOUT); + } + else + { + sprintf(tmp_string," %14s -> %-14s", + cur_call.num[CALLING], cur_call.num[CALLED]); + print_string(tmp_string,STDOUT); + } + + computed = 0; + +#if 0 + if (compute && !currency_factor && + !cur_call.dir && ((cur_call.eh == -1) || + (!cur_call.eh && cur_call.duration && cur_call.cause == -1))) { /* DIALOUT, keine AOCE Meldung */ +#else + go = 0; + + if ((cur_call.eh == -1) && !cur_call.dir) { /* Rauswahl, Gebuehr unbekannt */ + if (nx[1] == -1) { /* Gegner unbekannt! */ + if (compute) { + zone = compute; /* in "-c x" Zone vermuten */ + go = 1; + } + else { /* mit 0 DM berechnen */ + cur_call.eh = 0; + go = 0; + } /* else */ + } + else { + go = 1; + zone = known[nx[1]]->zone; + } /* else */ + } /* if */ + + if (go) { +#endif + t1 = cur_call.t; + t2 = cur_call.t + cur_call.duration; + + cur_call.eh = takt = 0; + computed = 1; + + while (t1 < t2) { + if (Tarif96) + takt = cheap96((time_t)t1, zone, &zeit); + else + takt = cheap((time_t)t1, zone); + + if (!takt) { + sprintf(tmp_string, "%s: OOPS! Abbruch: Zeittakt==0 ???\n", argv[0]); + print_string(tmp_string,ERROUT); + break; + } /* if */ + + cur_call.eh++; + t1 += takt; + + } /* while */ + } /* if */ + + if (cur_call.duration || (cur_call.eh > 0)) { + add_one_call(computed?&day_com_sum:&day_sum,&cur_call,einheit); + + if (cur_call.dir) { + if (nx[CALLING] == -1) { + restiusage++; + + if (cur_call.duration > 0) + restidur += cur_call.duration; + } /* if */ + } + else { + + if (nx[CALLED] == -1) { + resteh += cur_call.eh; + restdm += cur_call.dm; + restusage++; + + if (cur_call.duration > 0) + restdur += cur_call.duration; + } + else { + known[nx[CALLED]]->eh += cur_call.eh; + known[nx[CALLED]]->dm += cur_call.dm; + + zones[known[nx[CALLED]]->zone] += cur_call.eh; + zones_dm[known[nx[CALLED]]->zone] += cur_call.dm; + + if (cur_call.duration > 0) + zones_dur[known[nx[CALLED]]->zone] += cur_call.duration; + + zones_usage[known[nx[CALLED]]->zone]++; + } /* if */ + + sprintf(tmp_string," %s", + print_currency(cur_call.eh,cur_call.dm,4)); + print_string(tmp_string,STDOUT); + + if (computed) + print_string(" *",STDOUT); + } /* else */ + } + else { + if (cur_call.cause != -1) + { + sprintf(tmp_string," %s", qmsg(TYPE_CAUSE, VERSION_EDSS1, cur_call.cause)); + print_string(tmp_string,STDOUT); + day_sum.err++; + } + } /* else */ + + sprintf(tmp_string, " %*s", cur_call.dir ? 21 : 0, ""); + print_string(tmp_string, STDOUT); + + if (cur_call.ibytes) { + sprintf(tmp_string, " I=%s kB", double2str((double)cur_call.ibytes / 1024.0, 10, 2, 0)); + print_string(tmp_string, STDOUT); + } /* if */ + + if (cur_call.obytes) { + sprintf(tmp_string, " O=%s kB", double2str((double)cur_call.obytes / 1024.0, 10, 2, 0)); + print_string(tmp_string, STDOUT); + } /* if */ + + print_string("\n",STDOUT); + } /* if */ + } /* if */ + } /* if */ + } /* while */ + + fclose(fi); + + if (delentries) /* Erzeugt neue verkuerzte Datei */ + lday = -1; + + if (lday != -1) { + + if (timearea) { + strich(1); + print_sum_calls(&day_sum,0); + + if (day_com_sum.eh) + { + print_sum_calls(&day_com_sum,1); + + clear_sum(&tmp_sum); + add_sum_calls(&tmp_sum,&day_sum); + add_sum_calls(&tmp_sum,&day_com_sum); + strich(1); + print_sum_calls(&tmp_sum,0); + } + else + print_string("\n",STDOUT); + } /* if */ + + add_sum_calls(&all_sum,&day_sum); + add_sum_calls(&all_com_sum,&day_com_sum); + + strich(2); + print_sum_calls(&all_sum,0); + + if (all_com_sum.eh) + { + print_sum_calls(&all_com_sum,1); + + clear_sum(&tmp_sum); + add_sum_calls(&tmp_sum,&all_sum); + add_sum_calls(&tmp_sum,&all_com_sum); + strich(2); + print_sum_calls(&tmp_sum,0); + } + else + print_string("\n",STDOUT); + + if (!incomingonly) + { + if (timearea) + { + sprintf(tmp_string,"\nDIALOUT Summary for %s .. %s\n", start, stop); + print_string(tmp_string,STDOUT); + } + else + { + sprintf(tmp_string,"\nDIALOUT Summary for %s\n", start); + print_string(tmp_string,STDOUT); + } + + strich(3); + + for (i = mymsns; i < knowns; i++) { + if (known[i]->usage[DIALOUT]) { + sprintf(tmp_string,"%-14s %4d call(s) %s %s\n", + !numbers?known[i]->who:known[i]->num, + known[i]->usage[DIALOUT], + double2clock(known[i]->dur[DIALOUT]), + print_currency(known[i]->eh,known[i]->dm,7)); + print_string(tmp_string,STDOUT); + } /* if */ + } /* for */ + + if (restusage) { + sprintf(tmp_string,"%-14s %4d call(s) %s %s\n", + S_UNKNOWN, + restusage, + double2clock(restdur), + print_currency(resteh,restdm,7)); + print_string(tmp_string,STDOUT); + } /* if */ + + print_string("\n",STDOUT); + } + + if (!outgoingonly) + { + if (timearea) + { + sprintf(tmp_string,"\nDIALIN Summary for %s .. %s\n", start, stop); + print_string(tmp_string,STDOUT); + } + else + { + sprintf(tmp_string,"\nDIALIN Summary for %s\n", start); + print_string(tmp_string,STDOUT); + } + + strich(3); + + for (i = mymsns; i < knowns; i++) { + if (known[i]->usage[DIALIN]) { + sprintf(tmp_string,"%-14s %4d call(s) %s\n", + !numbers?known[i]->who:known[i]->num, + known[i]->usage[DIALIN], + double2clock(known[i]->dur[CALLED])); + print_string(tmp_string,STDOUT); + } /* if */ + } /* for */ + + if (restiusage) { + sprintf(tmp_string,"%-14s %4d call(s) %s\n", + S_UNKNOWN, + restiusage, + double2clock(restidur)); + print_string(tmp_string,STDOUT); + } /* if */ + + print_string("\n\n",STDOUT); + } + + for (i = 1; i < MAXZONES; i++) + if (zones[i]) { + + p = ""; + + switch (i) { + case 1 : p = "City"; break; + case 2 : p = "Region 50"; break; + case 3 : p = "Region 200"; break; + case 4 : p = "Fernzone"; break; + } /* switch */ + + sprintf(tmp_string,"Zone %d : %-15s %4d call(s) %s %s\n", i, p, + zones_usage[i], + double2clock(zones_dur[i]), + print_currency(zones[i],zones_dm[i],7)); + print_string(tmp_string,STDOUT); + } /* if */ + + if (resteh) + { + sprintf(tmp_string,"Zone x : %-15s %4d call(s) %s %s\n", S_UNKNOWN, + restusage, + double2clock(restdur), +#ifdef ISDN_NL + print_currency(resteh, resteh * einheit + restusage * 0.0825,7)); +#else + print_currency(resteh, resteh * einheit, 7)); +#endif + print_string(tmp_string,STDOUT); + } + + if (unknowns) { + print_string("\n\nUnknown caller(s)\n",STDOUT); + strich(3); + + for (i = 0; i < unknowns; i++) { + + sprintf(tmp_string,"%s %-14s ", unknown[i].called ? "called by" : " calling", unknown[i].num); + print_string(tmp_string,STDOUT); + + for (k = 0; k < unknown[i].connects; k++) { + strcpy(s1, ctime(&unknown[i].connect[k])); + + if ((p = strchr(s1, '\n'))) + *p = 0; + + *(s1 + 19) = 0; + + if (k && (k + 1) % 2) { + print_string("\n\t\t\t ",STDOUT); + } /* if */ + + sprintf(tmp_string,"%s%s", k & 1 ? ", " : "", s1 + 4); + print_string(tmp_string,STDOUT); + } /* for */ + + print_string("\n",STDOUT); + } /* for */ + } /* if */ + } /* if */ + } + else { + sprintf(tmp_string, msg1, argv[0], lfnam, strerror(errno)); + print_string(tmp_string,ERROUT); + return(1); + } /* else */ + + + if (delentries) /* Erzeugt neue verkuerzte Datei */ + { + fclose(ftmp); + + if ((ftmp = fopen(tmpfile, "r")) == (FILE *)NULL) + { + sprintf(tmp_string, msg1, tmpfile, strerror(errno)); + print_string(tmp_string,ERROUT); + return(1); + } + if ((fi = fopen(lfnam, "w")) == (FILE *)NULL) + { + sprintf(tmp_string, msg1, lfnam, strerror(errno)); + print_string(tmp_string,ERROUT); + return(1); + } + + while (fgets(s, BUFSIZ, ftmp)) + fputs(s,fi); + + fclose(fi); + fclose(ftmp); + + unlink(tmpfile); + } + + return(0); +} /* main */ + +/*****************************************************************************/ + +static int get_term (char *String, time_t *Begin, time_t *End,int delentries) +{ + time_t now; + time_t Date[2]; + int Cnt; + char DateStr[2][256] = {"",""}; + + + time(&now); + + if (String[0] == '-') + strcpy(DateStr[1],String+1); + else + if (String[strlen(String)-1] == '-') + { + strcpy(DateStr[0],String); + DateStr[0][strlen(String)-1] ='\0'; + } + else + if (strchr(String,'-')) + { + if (sscanf(String,"%[/.0-9]-%[/.0-9]",DateStr[0],DateStr[1]) != 2) + return 0; + } + else + { + strcpy(DateStr[0],String); + strcpy(DateStr[1],String); + } + + for (Cnt = 0; Cnt < 2; Cnt++) + { + if (strchr(DateStr[Cnt],'/')) + Date[Cnt] = get_month(DateStr[Cnt],delentries?0:Cnt); + else + Date[Cnt] = get_time(DateStr[Cnt],delentries?0:Cnt); + } + + *Begin = DateStr[0][0] == '\0' ? 0 : Date[0]; + *End = DateStr[1][0] == '\0' ? now : Date[1]; + + return 1; +} + +/*****************************************************************************/ + +static time_t get_month(char *String, int TimeStatus) +{ + time_t now; + int Cnt = 0; + struct tm *TimeStruct; + int Args[3]; + int ArgCnt; + + + time(&now); + TimeStruct = localtime(&now); + TimeStruct->tm_sec = 0; + TimeStruct->tm_min = 0; + TimeStruct->tm_hour= 0; + TimeStruct->tm_mday= 1; + TimeStruct->tm_isdst= -1; + + ArgCnt = sscanf(String,"%d/%d/%d",&(Args[0]),&(Args[1]),&(Args[2])); + + switch (ArgCnt) + { + case 3: + TimeStruct->tm_mday = Args[0]; + Cnt++; + case 2: + if (Args[Cnt+1] > 99) + TimeStruct->tm_year = ((Args[Cnt+1] / 100) - 19) * 100 + (Args[Cnt+1]%100); + else + TimeStruct->tm_year = Args[Cnt+1]; + case 1: + TimeStruct->tm_mon = Args[Cnt]; + break; + default: + return 0; + } + + if (TimeStatus == END_TIME) + { + if (ArgCnt == 3) /* Wenn Tag angegeben ist */ + { + TimeStruct->tm_mday++; + TimeStruct->tm_mon--; + } + } + else + TimeStruct->tm_mon--; + + return mktime(TimeStruct); +} + +/*****************************************************************************/ + +static time_t get_time(char *String, int TimeStatus) +{ + time_t now; + int Len = 0; + int Year; + char *Ptr; + struct tm *TimeStruct; + + + time(&now); + TimeStruct = localtime(&now); + TimeStruct->tm_sec = 0; + TimeStruct->tm_min = 0; + TimeStruct->tm_hour= 0; + TimeStruct->tm_isdst= -1; + + switch (strlen(String)) + { + case 0: + return 0; + case 1: + case 2: + TimeStruct->tm_mday = atoi(String); + break; + default: + Len = strlen(String); + + if ((Ptr = strchr(String,'.')) != NULL) + { + TimeStruct->tm_sec = atoi(Ptr+1); + Len -= strlen(Ptr); + } + + if (Len % 2) + return 0; + + if (sscanf(String,"%2d%2d%2d%2d%d", + &(TimeStruct->tm_mon), + &(TimeStruct->tm_mday), + &(TimeStruct->tm_hour), + &(TimeStruct->tm_min), + &Year ) > 4) + if (Year > 99) + TimeStruct->tm_year = ((Year / 100) - 19) * 100 + (Year%100); + else + TimeStruct->tm_year = Year; + + TimeStruct->tm_mon--; + break; + } + + if (TimeStatus == END_TIME) + if (TimeStruct->tm_sec == 0 && + TimeStruct->tm_min == 0 && + TimeStruct->tm_hour== 0 ) + TimeStruct->tm_mday++; + else + if (TimeStruct->tm_sec == 0 && + TimeStruct->tm_min == 0 ) + TimeStruct->tm_hour++; + else + if (TimeStruct->tm_sec == 0 ) + TimeStruct->tm_min++; + else + TimeStruct->tm_sec++; + + return mktime(TimeStruct); +} + +/*****************************************************************************/ + +static int set_msnlist(char *String) +{ + int Cnt; + int Value = 1; + char tmp_string[256]; + char *Ptr = String; + + + if (ShowMSN) + return 0; + + while((Ptr = strchr(Ptr,',')) != NULL) + { + Ptr++; + Value++; + } + + ShowMSN = (char**) calloc(Value+1,sizeof(char*)); + for(Cnt = 0; Cnt < Value; Cnt++) + ShowMSN[Cnt] = (char*) calloc(NUMSIZE,sizeof(char)); + + if (!ShowMSN) + { + sprintf(tmp_string, nomemory); + print_string(tmp_string,ERROUT); + exit(1); + } + + if (*String == 'n') + { + ++String; + invertnumbers++; + } + + Cnt = 0; + + while(String) + { + + if (*String == 'm') + { + Value = atoi(++String); + + if (Value > 0 && Value <= mymsns) + { + strcpy(ShowMSN[Cnt],known[Value-1]->num); + Cnt++; + } + else + { + sprintf(tmp_string,"Invalid MSN %d!\n",Cnt); + print_string(tmp_string,ERROUT); + } + } + else + sscanf(String,"%[^,],",ShowMSN[Cnt++]); + + String = strchr(String,','); + if (String) String++; + } + + return 0; +} + +/*****************************************************************************/ + +static int show_msn(one_call *cur_call) +{ + int Cnt; + + for(Cnt = 0; ShowMSN[Cnt] != NULL; Cnt++) + if (!num_match(ShowMSN[Cnt], cur_call->num[0]) || + !num_match(ShowMSN[Cnt] , cur_call->num[1])) + return !invertnumbers; + else + if (!strcmp(ShowMSN[Cnt],"0")) + return !invertnumbers; + + return invertnumbers; +} + +/*****************************************************************************/ + +static int print_string(char *String, int outdir) +{ + if (outdir == ERROUT) + return fprintf(stderr,"%s",String); + else + return printf("%s",String); +} + +/*****************************************************************************/ + +static char *print_currency(int units, double money, int Format) +{ + static char RetCode[256]; + + + if (!currency_factor) + sprintf(RetCode,"%*d EH %s DM",Format,units,double2str(money,8,2,0)); + else + sprintf(RetCode,"%.*s %s %s",Format," ", + double2str(money,8,2,0),currency); + + return RetCode; +} + +/*****************************************************************************/ + +static int print_sum_calls(sum_calls *s, int computed) +{ + static char String[256]; + + if (!computed) + sprintf(String,"%3d IN=%s, %3d OUT=%s, %3d failed %s I=%s kB O=%s kB\n", + s->in, + double2clock(s->din), + s->out, + double2clock(s->dout), + s->err, + print_currency(s->eh,s->dm,7), + double2str((double)s->ibytes / 1024.0, 10, 2, 0), + double2str((double)s->obytes / 1024.0, 10, 2, 0)); + else + sprintf(String," %3d OUT=%s, %s *\n", + s->out, + double2clock(s->dout), + print_currency(s->eh,s->dm,7)); + + return print_string(String,STDOUT); +} + +/*****************************************************************************/ + +static int add_one_call(sum_calls *s1, one_call *s2, double units) +{ + if (s2->dir == DIALIN) + { + s1->in++; + s1->din += s2->duration > 0?s2->duration:0; + } + else + { + s2->dm = s2->eh * units; + + s1->out++; + s1->dout += s2->duration > 0?s2->duration:0; + s1->eh += s2->eh; + s1->dm += s2->dm; + } + + s1->ibytes += s2->ibytes; + s1->obytes += s2->obytes; +#ifdef ISDN_NL + s1->dm += 0.0825; /* add call setup charge */ + s2->dm += 0.0825; +#endif + return 0; +} + +/*****************************************************************************/ + +static int clear_sum(sum_calls *s1) +{ + s1->in = 0; + s1->out = 0; + s1->eh = 0; + s1->err = 0; + s1->din = 0; + s1->dout = 0; + s1->dm = 0; + s1->ibytes = 0L; + s1->obytes = 0L; + + return 0; +} + +/*****************************************************************************/ + +static int add_sum_calls(sum_calls *s1, sum_calls *s2) +{ + s1->in += s2->in; + s1->out += s2->out; + s1->eh += s2->eh; + s1->err += s2->err; + s1->din += s2->din; + s1->dout += s2->dout; + s1->dm += s2->dm; + s1->ibytes += s2->ibytes; + s1->obytes += s2->obytes; + return 0; +} + +/*****************************************************************************/ + +static void strich(int type) +{ + switch (type) { + case 1 : print_string("----------------------------------------------------------------------------------------\n", STDOUT); + break; + + case 2 : print_string("========================================================================================\n", STDOUT); + break; + + case 3 : print_string("------------------------------------------------------------\n", STDOUT); + break; + } /* switch */ +} /* strich */ + +/*****************************************************************************/ + +static int n_match(char *Pattern, char* Number, int version) +{ + int RetCode = -1; + char s[SHORT_STRING_SIZE]; + char p[SHORT_STRING_SIZE]; + + switch(version) + { + case LOG_VERSION_1: if ((RetCode = match(Pattern, Number,0)) != 0 && + !strncmp(Pattern,S_AREA_PREFIX,strlen(S_AREA_PREFIX))) + { + sprintf(s,"*%s%s",myarea/*+strlen(S_AREA_PREFIX)*/,Pattern); + RetCode = match(s,Number,0); + } + break; + case LOG_VERSION_2: strcpy(s,expand_number(Number)); + strcpy(p,expand_number(Pattern)); + RetCode = num_match(p,s); + break; + case LOG_VERSION_3: RetCode = num_match(Pattern,Number); + break; + default : sprintf(s,"Unknown Version of logfile entries!\n"); + print_string(s,ERROUT); + break; + } + + return RetCode; +} + +/*****************************************************************************/ + diff --git a/isdnlog/isdnrep/isdnrep.h b/isdnlog/isdnrep/isdnrep.h new file mode 100644 index 00000000..d61e878c --- /dev/null +++ b/isdnlog/isdnrep/isdnrep.h @@ -0,0 +1,41 @@ +/* $Id: isdnrep.h,v 1.1 1997/03/16 20:59:08 luethje Exp $ + * + * ISDN accounting for isdn4linux. + * + * 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. + * + */ + +#ifndef _ISDNREP_H_ +#define _ISDNREP_H_ + + +#define PUBLIC extern +#include + +#ifdef _ISDNREP_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN double cheap96(time_t when, int zone, int *zeit); +_EXTERN double cheap(time_t when, int zone); + +#undef _EXTERN + +#endif /* _ISDNREP_H_ */ diff --git a/isdnlog/samples/isdnlog.conf.sample.1 b/isdnlog/samples/isdnlog.conf.sample.1 new file mode 100644 index 00000000..0605ee40 --- /dev/null +++ b/isdnlog/samples/isdnlog.conf.sample.1 @@ -0,0 +1,22 @@ +# Konkretes Beispiel fuer eine "isdnlog.conf" +# +# Eine genaue Beschreibung dazu siehe "README", Kapitel 4.2.6 +# +MYPREFIX = 0815 +PLAYER = /usr/bin/auplay +SOUNDS = /usr/sounds + +START = O R L = $PLAYER ${SOUNDS}/unknown_ring.au,,8-14,16-22;\ + IOA = $PLAYER ${SOUNDS}/pay.au,,8-14,16-22;\ + IOC U = /usr/bin/who_is_it $2 $3;\ + IOH = $PLAYER ${SOUNDS}/hangup.au,,8-14,16-22;\ + IORAH = $PLAYER ${SOUNDS}/silent.au,,14-16,22-8; + +4711 MSN\#1 1 - I RK = $PLAYER ${SOUNDS}/msn1_ring.au,5,8-14,16-22;\ + - IOA = $PLAYER ${SOUNDS}/msn1_pay.au,,8-14,16-22; +4712 MSN\#2 1 - I RK = $PLAYER ${SOUNDS}/msn2_ring.au,5,8-14,16-22; +4713 MSN\#3 1 - I RK = $PLAYER ${SOUNDS}/msn3_ring.au,5,8-14,16-22; + +*40441777 My_Provider 4 isdn0 OIR = $PLAYER ${SOUNDS}/provider_ring.au;\ + OICU = /usr/bin/get.mails.from.provider,300;\ + OICU = /usr/bin/get.news.from.provider,1800; diff --git a/isdnlog/samples/isdnlog.users.sample.1 b/isdnlog/samples/isdnlog.users.sample.1 new file mode 100644 index 00000000..46fa0624 --- /dev/null +++ b/isdnlog/samples/isdnlog.users.sample.1 @@ -0,0 +1,12 @@ +############################################################################### +# +# Generated by isdnlog 2.3.1 on Tue Apr 02 01:02:38 1996 +# +############################################################################### + +# File: /etc/isdnlog/isdnlog.users + +# The empty section "world" means, that everybody from everywhere can connect +# to your isdnlog. Everybody gets all rights. Be careful with this section! + +[world] diff --git a/isdnlog/samples/isdnlog.users.sample.2 b/isdnlog/samples/isdnlog.users.sample.2 new file mode 100644 index 00000000..b9ae0f49 --- /dev/null +++ b/isdnlog/samples/isdnlog.users.sample.2 @@ -0,0 +1,28 @@ +############################################################################### +# +# Generated by isdnlog 2.3.1 on Tue Apr 02 01:02:38 1996 +# +############################################################################### + +# File: /etc/isdnlog/isdnlog.users + +# The following two lines allow the user "hans" to connect only +# from "machine1.from.nowhere", and the user "lilo" only from +# "machine4.at.home" + +hans@machine1.from.nowhere MSN=*; PROTOCOL +lilo@machine4.at.home MSN=4711 + +# The section below, allow the users "fred" and "root" to access to the isdnlog +# from both machines (machine1.at.home, machine2.at.home). + +[ my_first_entry ] +root ALL +@machine2.at.home +fred MSN=8150?,4711; PROTOCOL +@machine3.at.home + +[ my_second_entry ] +root MSN=* +peter ADDRESSBOOK +@linux1.from.nowhere diff --git a/isdnlog/samples/reload b/isdnlog/samples/reload new file mode 100755 index 00000000..520904a6 --- /dev/null +++ b/isdnlog/samples/reload @@ -0,0 +1,4 @@ +#!/bin/sh +/sbin/rmmod hisax +/sbin/modprobe hisax io=1,2,12,0xd0000,0xd80 HiSax_id=bri1 +/sbin/telesctrl bri1 1 4 diff --git a/isdnlog/samples/stop b/isdnlog/samples/stop new file mode 100644 index 00000000..e61374bd --- /dev/null +++ b/isdnlog/samples/stop @@ -0,0 +1,37 @@ +#!/bin/sh + +# very simple reload-example for the new chargemax feature of isdnlog +# this is called by isdnlog every time we get a AOCD and chargesum of +# active device is greater then CHARGEMAX. +# there are three parameter available: +# +# first ($1) is chargesum-CHARGEMAX +# second ($2) is ALIAS as defined in ISDNLOG.CONF +# third ($3) is total chargesum for active device + +case "$1" in +'0,00') + echo "WARNING, charge-limit set by CHARGEMAX is reached!" >> /dev/console + echo "$2 is talking to much!" >> /dev/console + /bin/aplay /usr/sounds/attention.au + ;; + +'0,12') + echo "WARNING, $2 got charge-overflow == $1, total chargesum == $3" >> /dev/console + echo "next chargeint will cause i4l to stop" >> /dev/console + /bin/aplay /usr/sounds/earthdestruction.au + ;; + +'0,24') + echo "reload got charge-overflow == $1, now i4l will be stopped!" >> /dev/console + /sbin/init.d/i4l stop + ;; + +'0,36') + echo "aeh, still alive?! so we'll do a reboot!!" >> /dev/console + /bin/aplay /usr/sounds/crash.au + /sbin/reboot + ;; +esac + +echo "got charge_ov=$1 dev=$2 scharge=$3 " >> /dev/console diff --git a/isdnlog/tools/dbmalloc.h b/isdnlog/tools/dbmalloc.h new file mode 100644 index 00000000..f28d12a6 --- /dev/null +++ b/isdnlog/tools/dbmalloc.h @@ -0,0 +1,692 @@ +/* + * (c) Copyright 1990, 1991, 1992 Conor P. Cahill (cpcahil@virtech.vti.com) + * + * This software may be distributed freely as long as the following conditions + * are met: + * * the distribution, or any derivative thereof, may not be + * included as part of a commercial product + * * full source code is provided including this copyright + * * there is no charge for the software itself (there may be + * a minimal charge for the copying or distribution effort) + * * this copyright notice is not modified or removed from any + * source file + */ +/* + * $Id: dbmalloc.h,v 1.1 1997/03/16 20:59:19 luethje Exp $ + */ + +#ifndef _DEBUG_MALLOC_INC +#define _DEBUG_MALLOC_INC 1 + +/* + * __need_size_t is checked by Gnu's stddef.h + */ +#define __need_size_t +#include +#undef __need_size_t + +#ifdef force_cproto_to_use_defines + +/* + * these are just here because cproto used the c-preprocessor to generate + * the prototypes and if they were left as #defines the prototypes.h file + * would have the contents of the define, not the define itself + */ + +typedef void DATATYPE; +typedef size_t SIZETYPE; +typedef void VOIDTYPE; +typedef void MEMDATA; +typedef size_t MEMSIZE; +typedef int BCOPYSIZE; +typedef size_t STRSIZE; +typedef void FREETYPE; +typedef void EXITTYPE; + +#ifdef WRTSIZE +#undef WRTSIZE +#endif +typedef unsigned int WRTSIZE; + +/* + * for now, define CONST as const. A sed script in the makefile will change + * this back to CONST in the prototypes.h file. + */ +#define CONST const + +#else /* force_cproto_to_use_defines */ + +/* + * The following entries are automatically added by the Configure script. + * If they are not correct for your system, then Configure is not handling + * your system correctly. Please report this to the author along with + * a description of your system and the correct values + */ + +#if (__GNUC__ == 2) && __STDC__ + +#define VOIDTYPE void +#define CONST const +#define EXITTYPE void +#define DATATYPE void +#define SIZETYPE size_t +#define FREETYPE void +#define MEMDATA void +#define MEMSIZE size_t +#define BCOPYSIZE int +#define MEMCMPTYPE unsigned char +#define STRSIZE size_t +#define STRCMPTYPE unsigned char + +#else /* (__GNUC__ == 2) && __STDC__ */ + + +#if (__GNUC__ == 2) + +#define VOIDTYPE void +#define CONST +#define EXITTYPE void +#define DATATYPE void +#define SIZETYPE size_t +#define FREETYPE void +#define MEMDATA void +#define MEMSIZE size_t +#define BCOPYSIZE int +#define MEMCMPTYPE unsigned char +#define STRSIZE size_t +#define STRCMPTYPE unsigned char + +#else /* (__GNUC__ == 2) */ + + +#if (__GNUC__ == 2) && __STDC__ && __cplusplus + +#define VOIDTYPE void +#define CONST const +#define EXITTYPE void +#define DATATYPE void +#define SIZETYPE size_t +#define FREETYPE void +#define MEMDATA void +#define MEMSIZE size_t +#define BCOPYSIZE int +#define MEMCMPTYPE unsigned char +#define STRSIZE size_t +#define STRCMPTYPE unsigned char + +#else /* (__GNUC__ == 2) && __STDC__ && __cplusplus */ + + +#if (__GNUC__ == 2) && __STDC__ + +#define VOIDTYPE void +#define CONST const +#define EXITTYPE void +#define DATATYPE void +#define SIZETYPE size_t +#define FREETYPE void +#define MEMDATA void +#define MEMSIZE size_t +#define BCOPYSIZE int +#define MEMCMPTYPE unsigned char +#define STRSIZE size_t +#define STRCMPTYPE unsigned char + +#endif /* (__GNUC__ == 2) && __STDC__ */ + + +#endif /* (__GNUC__ == 2) && __STDC__ && __cplusplus */ + + +#endif /* (__GNUC__ == 2) */ + + +#endif /* (__GNUC__ == 2) && __STDC__ */ + +/* + * END of automatic configuration stuff. + */ + +/* + * if DATATYPE is not defined, then the configure script must have had a + * problem, or was used with a different compiler. So we have to stop + * here and get the user to fix the problem. + */ +#ifndef DATATYPE + /* + * the following string should cause a comilation error and get the + * user to look at this stuff to find out what is wrong. + */ + "This file is not configured correctly for this system. Run configure + and check its results" + char * malloc(); /* DON'T REMOVE THIS LINE if you get a compiler error + here it is because the malloc.h file is not + configured correctly See the readme/problems + files for more info */ + +#endif /* DATATYPE */ + +#endif /* force_cproto_to_use_defines */ + +#define VOIDCAST (VOIDTYPE) + +/* + * since we redefine much of the stuff that is #defined in string.h and + * memory.h, we should do what we can to make sure that they don't get + * included after us. This is typically accomplished by a special symbol + * (similar to _DEBUG_MALLOC_INC defined above) that is #defined when the + * file is included. Since we don't want the file to be included we will + * #define the symbol ourselves. These will typically have to change from + * one system to another. I have put in several standard mechanisms used to + * support this mechanism, so hopefully you won't have to modify this file. + */ +#ifndef _H_STRING +#define _H_STRING 1 +#endif +#ifndef __STRING_H +#define __STRING_H 1 +#endif +#ifndef _STRING_H_ +#define _STRING_H_ 1 +#endif +#ifndef _STRING_H +#define _STRING_H 1 +#endif +#ifndef _STRING_INCLUDED +#define _STRING_INCLUDED 1 +#endif +#ifndef __string_h +#define __string_h 1 +#endif +#ifndef _string_h +#define _string_h 1 +#endif +#ifndef __string_h__ +#define __string_h__ 1 +#endif +#ifndef _strings_h +#define _strings_h 1 +#endif +#ifndef __strings_h +#define __strings_h 1 +#endif +#ifndef __strings_h__ +#define __strings_h__ 1 +#endif +#ifndef _H_MEMORY +#define _H_MEMORY 1 +#endif +#ifndef __MEMORY_H +#define __MEMORY_H 1 +#endif +#ifndef _MEMORY_H_ +#define _MEMORY_H_ 1 +#endif +#ifndef _MEMORY_H +#define _MEMORY_H 1 +#endif +#ifndef _MEMORY_INCLUDED +#define _MEMORY_INCLUDED 1 +#endif +#ifndef __memory_h +#define __memory_h 1 +#endif +#ifndef _memory_h +#define _memory_h 1 +#endif +#ifndef __memory_h__ +#define __memory_h__ 1 +#endif +#ifndef _STDLIB_H +#define _STDLIB_H 1 +#endif + +/* + * for NCR, we need to disable their in-line expansion of the str* routines + */ +#define ISTRING 1 + +/* + * Malloc warning/fatal error handler defines... + */ +#define M_HANDLE_DUMP 0x80 /* 128 */ +#define M_HANDLE_IGNORE 0 +#define M_HANDLE_ABORT 1 +#define M_HANDLE_EXIT 2 +#define M_HANDLE_CORE 3 + +/* + * Mallopt commands and defaults + * + * the first four settings are ignored by the debugging dbmallopt, but are + * here to maintain compatibility with the system malloc.h. + */ +#define M_MXFAST 1 /* ignored by mallopt */ +#define M_NLBLKS 2 /* ignored by mallopt */ +#define M_GRAIN 3 /* ignored by mallopt */ +#define M_KEEP 4 /* ignored by mallopt */ +#define MALLOC_WARN 100 /* set malloc warning handling */ +#define MALLOC_FATAL 101 /* set malloc fatal handling */ +#define MALLOC_ERRFILE 102 /* specify malloc error file */ +#define MALLOC_CKCHAIN 103 /* turn on chain checking */ +#define MALLOC_FILLAREA 104 /* turn off area filling */ +#define MALLOC_LOWFRAG 105 /* use best fit allocation mech */ +#define MALLOC_CKDATA 106 /* turn off/on data checking */ +#define MALLOC_REUSE 107 /* turn off/on freed seg reuse */ +#define MALLOC_SHOWLINKS 108 /* turn off/on adjacent link disp */ +#define MALLOC_DETAIL 109 /* turn off/on detail output */ +#define MALLOC_FREEMARK 110 /* warn about freeing marked segs*/ +#define MALLOC_ZERO 111 /* warn about zero len allocs */ + +union dbmalloptarg +{ + int i; + char * str; +}; + +/* + * disable the standard mallopt function + */ +#define mallopt(a,b) (0) + +/* + * Malloc warning/fatal error codes + */ +#define M_CODE_CHAIN_BROKE 1 /* malloc chain is broken */ +#define M_CODE_NO_END 2 /* chain end != endptr */ +#define M_CODE_BAD_PTR 3 /* pointer not in malloc area */ +#define M_CODE_BAD_MAGIC 4 /* bad magic number in header */ +#define M_CODE_BAD_CONNECT 5 /* chain poingers corrupt */ +#define M_CODE_OVERRUN 6 /* data overrun in malloc seg */ +#define M_CODE_REUSE 7 /* reuse of freed area */ +#define M_CODE_NOT_INUSE 8 /* pointer is not in use */ +#define M_CODE_NOMORE_MEM 9 /* no more memory available */ +#define M_CODE_OUTOF_BOUNDS 10 /* gone beyound bounds */ +#define M_CODE_FREELIST_BAD 11 /* inuse segment on freelist */ +#define M_CODE_NOBOUND 12 /* can't calculate boundry */ +#define M_CODE_STK_NOCUR 13 /* no current element on stack */ +#define M_CODE_STK_BADFUNC 14 /* current func doesn't match */ +#define M_CODE_UNDERRUN 15 /* data underrun in malloc seg */ +#define M_CODE_FREEMARK 16 /* free of marked segment */ +#define M_CODE_ZERO_ALLOC 17 /* zero length allocation */ + +#ifndef __STDCARGS +#if __STDC__ || __cplusplus +#define __STDCARGS(a) a +#else +#define __STDCARGS(a) () +#endif +#endif + +#if __cplusplus +extern "C" { +#endif + +VOIDTYPE malloc_dump __STDCARGS((int)); +VOIDTYPE malloc_list __STDCARGS((int,unsigned long, unsigned long)); +int dbmallopt __STDCARGS((int, union dbmalloptarg *)); +DATATYPE * debug_calloc __STDCARGS((CONST char *,int,SIZETYPE,SIZETYPE)); +FREETYPE debug_cfree __STDCARGS((CONST char *, int, DATATYPE *)); +FREETYPE debug_free __STDCARGS((CONST char *, int, DATATYPE *)); +DATATYPE * debug_malloc __STDCARGS((CONST char *,int, SIZETYPE)); +DATATYPE * debug_realloc __STDCARGS((CONST char *,int, + DATATYPE *,SIZETYPE)); +VOIDTYPE DBmalloc_mark __STDCARGS((CONST char *,int, DATATYPE *)); +unsigned long DBmalloc_inuse __STDCARGS((CONST char *,int, + unsigned long *)); +int DBmalloc_chain_check __STDCARGS((CONST char *,int,int)); +SIZETYPE DBmalloc_size __STDCARGS((CONST char *,int,CONST DATATYPE *)); +DATATYPE * DBmemalign __STDCARGS((CONST char *, int,SIZETYPE, SIZETYPE)); +void StackEnter __STDCARGS((CONST char *, CONST char *, int)); +void StackLeave __STDCARGS((CONST char *, CONST char *, int)); + +/* + * X allocation related prototypes + */ +char * debug_XtMalloc __STDCARGS((CONST char *, int, unsigned int)); +char * debug_XtRealloc __STDCARGS((CONST char *, int, + char *, unsigned int)); +char * debug_XtCalloc __STDCARGS((CONST char *, int, + unsigned int, unsigned int)); +void debug_XtFree __STDCARGS((CONST char *, int, char *)); +void * debug_XtBCopy __STDCARGS((CONST char *, int, char *, + char *, int)); +extern void (*XtAllocErrorHandler) __STDCARGS((CONST char *)); + +/* + * memory(3) related prototypes + */ +MEMDATA * DBmemccpy __STDCARGS((CONST char *file, int line, + MEMDATA *ptr1, CONST MEMDATA *ptr2, + int ch, MEMSIZE len)); +MEMDATA * DBmemchr __STDCARGS((CONST char *file, int line, + CONST MEMDATA *ptr1, int ch, + MEMSIZE len)); +MEMDATA * DBmemmove __STDCARGS((CONST char *file, int line, + MEMDATA *ptr1, CONST MEMDATA *ptr2, + MEMSIZE len)); +MEMDATA * DBmemcpy __STDCARGS((CONST char *file, int line, + MEMDATA *ptr1, CONST MEMDATA *ptr2, + MEMSIZE len)); +int DBmemcmp __STDCARGS((CONST char *file, int line, + CONST MEMDATA *ptr1, + CONST MEMDATA *ptr2, MEMSIZE len)); +MEMDATA * DBmemset __STDCARGS((CONST char *file, int line, + MEMDATA *ptr1, int ch, MEMSIZE len)); +VOIDTYPE DBbcopy __STDCARGS((CONST char *file, int line, + CONST MEMDATA *ptr2, MEMDATA *ptr1, + BCOPYSIZE len)); +VOIDTYPE DBbzero __STDCARGS((CONST char *file, int line, + MEMDATA *ptr1, BCOPYSIZE len)); +int DBbcmp __STDCARGS((CONST char *file, int line, + CONST MEMDATA *ptr2, + CONST MEMDATA *ptr1, BCOPYSIZE len)); + +/* + * string(3) related prototypes + */ +char * DBstrcat __STDCARGS((CONST char *file,int line, char *str1, + CONST char *str2)); +char * DBstrdup __STDCARGS((CONST char *file, int line, + CONST char *str1)); +char * DBstrncat __STDCARGS((CONST char *file, int line, char *str1, + CONST char *str2, STRSIZE len)); +int DBstrcmp __STDCARGS((CONST char *file, int line, + CONST char *str1, CONST char *str2)); +int DBstrncmp __STDCARGS((CONST char *file, int line, + CONST char *str1, CONST char *str2, + STRSIZE len)); +int DBstricmp __STDCARGS((CONST char *file, int line, + CONST char *str1, CONST char *str2)); +int DBstrincmp __STDCARGS((CONST char *file, int line, + CONST char *str1, CONST char *str2, + STRSIZE len)); +char * DBstrcpy __STDCARGS((CONST char *file, int line, char *str1, + CONST char *str2)); +char * DBstrncpy __STDCARGS((CONST char *file, int line, char *str1, + CONST char *str2, STRSIZE len)); +STRSIZE DBstrlen __STDCARGS((CONST char *file, int line, + CONST char *str1)); +char * DBstrchr __STDCARGS((CONST char *file, int line, + CONST char *str1, int c)); +char * DBstrrchr __STDCARGS((CONST char *file, int line, + CONST char *str1, int c)); +char * DBindex __STDCARGS((CONST char *file, int line, + CONST char *str1, int c)); +char * DBrindex __STDCARGS((CONST char *file, int line, + CONST char *str1, int c)); +char * DBstrpbrk __STDCARGS((CONST char *file, int line, + CONST char *str1, CONST char *str2)); +STRSIZE DBstrspn __STDCARGS((CONST char *file, int line, + CONST char *str1, CONST char *str2)); +STRSIZE DBstrcspn __STDCARGS((CONST char *file, int line, + CONST char *str1, CONST char *str2)); +char * DBstrstr __STDCARGS((CONST char *file, int line, + CONST char *str1, CONST char *str2)); +char * DBstrtok __STDCARGS((CONST char *file, int line, char *str1, + CONST char *str2)); + +#if __cplusplus +}; +#endif + +/* + * Macro which enables logging of the file and line number for each allocation + * so that it is easier to determine where the offending malloc comes from. + * + * NOTE that only code re-compiled with this include file will have this + * additional info. Calls from libraries that have not been recompiled will + * just have a null string for this info. + */ +#ifndef IN_MALLOC_CODE + +/* + * allocation functions + */ +#ifdef malloc +#undef malloc +#endif +#ifdef realloc +#undef realloc +#endif +#ifdef calloc +#undef calloc +#endif +#ifdef cfree +#undef cfree +#endif +#ifdef free +#undef free +#endif +#define malloc(len) debug_malloc( __FILE__,__LINE__, (len)) +#define realloc(ptr,len) debug_realloc(__FILE__,__LINE__, (ptr), (len)) +#define calloc(numelem,size) debug_calloc(__FILE__,__LINE__,(numelem),(size)) +#define cfree(ptr) debug_cfree(__FILE__,__LINE__,(ptr)) +#define free(ptr) debug_free(__FILE__,__LINE__,(ptr)) +#define malloc_chain_check(do) DBmalloc_chain_check(__FILE__,__LINE__,(do)) +#define malloc_mark(ptr) DBmalloc_mark(__FILE__,__LINE__,(ptr)) +#define malloc_inuse(histptr) DBmalloc_inuse(__FILE__,__LINE__,(histptr)) +#define malloc_size(ptr) DBmalloc_size(__FILE__,__LINE__,(ptr)) +#define memalign(align,size) DBmemalign(__FILE__,__LINE__,(align),(size)) + +/* + * X allocation routines + */ +#define XtCalloc(_num,_size) debug_XtCalloc(__FILE__,__LINE__,_num,_size) +#define XtMalloc(_size) debug_XtMalloc(__FILE__,__LINE__,_size) +#define XtRealloc(_ptr,_size) debug_XtRealloc(__FILE__,__LINE__,_ptr,_size) +#define XtFree(_ptr) debug_XtFree(__FILE__,__LINE__,_ptr) +#define _XtBCopy(ptr1,ptr2,len) debug_XtBcopy(__FILE__,__LINE__,ptr1,ptr2,len) + +/* + * Other allocation functions + */ +#define _malloc(_size) debug_malloc(__FILE__,__LINE__,_size) +#define _realloc(_ptr,_size) debug_realloc(__FILE__,__LINE__,_ptr,_size) +#define _calloc(_num,_size) debug_calloc(__FILE__,__LINE__,_num,_size) +#define _free(_ptr) debug_free(__FILE__,__LINE__,_ptr) + +/* + * memory(3) related functions + */ +#ifdef bcopy +#undef bcopy +#endif +#ifdef bzero +#undef bzero +#endif +#ifdef bcmp +#undef bcmp +#endif +#define memccpy(ptr1,ptr2,ch,len) DBmemccpy(__FILE__,__LINE__,ptr1,ptr2,ch,len) +#define memchr(ptr1,ch,len) DBmemchr(__FILE__,__LINE__,ptr1,ch,len) +#define memmove(ptr1,ptr2,len) DBmemmove(__FILE__,__LINE__,ptr1, ptr2, len) +#define memcpy(ptr1,ptr2,len) DBmemcpy(__FILE__, __LINE__, ptr1, ptr2, len) +#define memcmp(ptr1,ptr2,len) DBmemcmp(__FILE__,__LINE__,ptr1, ptr2, len) +#define memset(ptr1,ch,len) DBmemset(__FILE__,__LINE__,ptr1, ch, len) +#define bcopy(ptr2,ptr1,len) DBbcopy(__FILE__,__LINE__,ptr2,ptr1,len) +#define bzero(ptr1,len) DBbzero(__FILE__,__LINE__,ptr1,len) +#define bcmp(ptr2,ptr1,len) DBbcmp(__FILE__, __LINE__, ptr2, ptr1, len) + +#define _bcopy(ptr2,ptr1,len) DBbcopy(__FILE__,__LINE__,ptr2,ptr1,len) +#define _bzero(ptr1,len) DBbzero(__FILE__,__LINE__,ptr1,len) +#define _bcmp(ptr2,ptr1,len) DBbcmp(__FILE__,__LINE__,ptr2,ptr1,len) +#define __dg_bcopy(ptr2,ptr1,len) DBbcopy(__FILE__,__LINE__,ptr2,ptr1,len) +#define __dg_bzero(ptr1,len) DBbzero(__FILE__,__LINE__,ptr1,len) +#define __dg_bcmp(ptr2,ptr1,len) DBbcmp(__FILE__,__LINE__,ptr2,ptr1,len) + +/* + * string(3) related functions + */ +#ifdef index +#undef index +#endif +#ifdef rindex +#undef rindex +#endif +#ifdef strchr +#undef strchr +#endif +#ifdef strcmp +#undef strcmp +#endif +#ifdef strcpy +#undef strcpy +#endif +#ifdef strrchr +#undef strrchr +#endif +#define index(str1,c) DBindex(__FILE__, __LINE__, str1, c) +#define rindex(str1,c) DBrindex(__FILE__, __LINE__, str1, c) +#define strcat(str1,str2) DBstrcat(__FILE__,__LINE__,str1,str2) +#define strchr(str1,c) DBstrchr(__FILE__, __LINE__, str1,c) +#define strcmp(str1,str2) DBstrcmp(__FILE__, __LINE__, str1, str2) +#define strcpy(str1,str2) DBstrcpy(__FILE__, __LINE__, str1, str2) +#define strcspn(str1,str2) DBstrcspn(__FILE__, __LINE__, str1,str2) +#define strdup(str1) DBstrdup(__FILE__, __LINE__, str1) +#define stricmp(str1,str2) DBstricmp(__FILE__, __LINE__, str1, str2) +#define strincmp(str1,str2,len) DBstrincmp(__FILE__, __LINE__, str1,str2,len) +#define strlen(str1) DBstrlen(__FILE__, __LINE__, str1) +#define strncat(str1,str2,len) DBstrncat(__FILE__, __LINE__, str1,str2,len) +#define strncpy(str1,str2,len) DBstrncpy(__FILE__,__LINE__,str1,str2,len) +#define strncmp(str1,str2,len) DBstrncmp(__FILE__, __LINE__, str1,str2,len) +#define strpbrk(str1,str2) DBstrpbrk(__FILE__, __LINE__, str1,str2) +#define strrchr(str1,c) DBstrrchr(__FILE__,__LINE__,str1,c) +#define strspn(str1,str2) DBstrspn(__FILE__, __LINE__, str1,str2) +#define strstr(str1,str2) DBstrstr(__FILE__, __LINE__, str1, str2) +#define strtok(str1,str2) DBstrtok(__FILE__, __LINE__, str1, str2) + +/* + * malloc stack related functions + */ +#define malloc_enter(func) StackEnter(func,__FILE__,__LINE__) +#define malloc_leave(func) StackLeave(func,__FILE__,__LINE__) + +#endif /* IN_MALLOC_CODE */ + +#endif /* _DEBUG_MALLOC_INC */ + +/* + * $Log: dbmalloc.h,v $ + * Revision 1.1 1997/03/16 20:59:19 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 1.38 1992/08/22 16:27:13 cpcahil + * final changes for pl14 + * + * Revision 1.37 1992/08/18 11:42:00 cpcahil + * added more #defs to preclude memory/string.h inclusion + * + * Revision 1.36 1992/07/12 15:30:58 cpcahil + * Merged in Jonathan I Kamens' changes + * + * Revision 1.35 1992/07/03 00:03:25 cpcahil + * more fixes for pl13, several suggestons from Rich Salz. + * + * Revision 1.34 1992/07/02 15:35:52 cpcahil + * misc cleanups for PL13 + * + * Revision 1.33 1992/07/02 13:49:54 cpcahil + * added support for new malloc_size function and additional tests to testerr + * + * Revision 1.32 1992/06/30 13:06:39 cpcahil + * added support for aligned allocations + * + * Revision 1.31 1992/06/22 23:40:10 cpcahil + * many fixes for working on small int systems + * + * Revision 1.30 1992/05/06 04:53:29 cpcahil + * performance enhancments + * + * Revision 1.29 1992/04/22 18:17:32 cpcahil + * added support for Xt Alloc functions, linted code + * + * Revision 1.28 1992/04/13 19:08:18 cpcahil + * fixed case insensitive stuff + * + * Revision 1.27 1992/04/13 18:41:18 cpcahil + * added case insensitive string comparison routines + * + * Revision 1.26 1992/04/13 17:26:25 cpcahil + * minor portability changes + * + * Revision 1.25 1992/04/13 14:13:18 cpcahil + * cleanup of log message. + * + * Revision 1.24 1992/04/13 03:09:14 cpcahil + * lots of changes. + * + * Revision 1.23 1992/03/01 12:42:38 cpcahil + * added support for managing freed areas and fixed doublword bndr problems + * + * Revision 1.22 1992/02/07 15:51:07 cpcahil + * mods for sun4 + * + * Revision 1.21 1992/01/29 01:35:32 cpcahil + * added sgi definition. + * + * Revision 1.20 1992/01/28 21:42:25 cpcahil + * changes for the ibmRS6000 + * + * Revision 1.19 1992/01/28 18:05:37 cpcahil + * misc fixes for patch 7 + * + * Revision 1.18 1992/01/22 16:21:35 cpcahil + * added code to prevent inclusions of string.h and memory.h after malloc.h + * was included. + * + * Revision 1.17 1992/01/10 17:26:46 cpcahil + * fixed prototypes use of void. + * + * Revision 1.16 1992/01/10 16:53:39 cpcahil + * added more info on sizetype and datatype. added support for overriding + * use of void type. + * + * Revision 1.15 1992/01/09 17:19:11 cpcahil + * put the close brace in the correct position. + * + * Revision 1.14 1992/01/09 17:12:36 cpcahil + * added code to support inclusion in C++ modules + * + * Revision 1.13 1991/12/31 21:31:26 cpcahil + * changes for patch 6. See CHANGES file for more info + * + * Revision 1.12 1991/12/26 22:31:29 cpcahil + * added check to make sure file is not included twice. + * + * Revision 1.11 1991/12/06 17:58:46 cpcahil + * added cfree() for compatibility with some wierd systems + * + * Revision 1.10 91/12/06 08:54:18 cpcahil + * cleanup of __STDC__ usage and addition of CHANGES file + * + * Revision 1.9 91/12/04 09:23:40 cpcahil + * several performance enhancements including addition of free list + * + * Revision 1.8 91/12/02 19:10:11 cpcahil + * changes for patch release 5 + * + * Revision 1.7 91/11/25 14:42:00 cpcahil + * Final changes in preparation for patch 4 release + * + * Revision 1.6 91/11/24 00:49:28 cpcahil + * first cut at patch 4 + * + * Revision 1.5 91/11/20 11:54:10 cpcahil + * interim checkin + * + * Revision 1.4 90/08/29 22:23:38 cpcahil + * fixed mallopt to use a union as an argument. + * + * Revision 1.3 90/05/11 11:04:10 cpcahil + * took out some extraneous lines + * + * Revision 1.2 90/05/11 00:13:09 cpcahil + * added copyright statment + * + * Revision 1.1 90/02/23 07:09:03 cpcahil + * Initial revision + * + */ diff --git a/isdnlog/tools/isdnconf.c b/isdnlog/tools/isdnconf.c new file mode 100644 index 00000000..babd062b --- /dev/null +++ b/isdnlog/tools/isdnconf.c @@ -0,0 +1,1631 @@ +/* $Id: isdnconf.c,v 1.1 1997/03/16 20:59:22 luethje Exp $ + * + * ISDN accounting for isdn4linux. (Utilities) + * + * 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. + * + */ + +/****************************************************************************/ + + +#define PUBLIC /**/ +#define _ISDNCONF_C_ + +/****************************************************************************/ + +#include "tools.h" + +/****************************************************************************/ + +static char ***Environment = NULL; +static char *OlabelPtr = NULL; +static char *IlabelPtr = NULL; + +/****************************************************************************/ + +static char *NextItem(char *Line, int komma); +static char*NextOption(char** Options, char* Delim); +static void Append(char **Target, char*Source); +static int SetFlags(KNOWN *FlagPtr, char *flags); +static int IsVariable(char *string); +static int Set_Globals(section *SPtr); +static info_args** Set_Flags(section *SPtr, int *Flags); +static int Get_Events(char* Flags); +static int Set_Numbers(section *SPtr, char *Section, int msn); +static int Set_known_Size(int msn); +static section* writeentry(section *SPtr, int Index); +static int readconfigfile(char *_myname); +static int _readconfig(char *_myname); +static int readoldconfig(char *myname); +static section* writeinfoargs(section *SPtr, info_args *infoarg); +static void appendflag(char*str1, char*str2); +static char *writeflags(int flag); +static section* writevariables(section *SPtr); +static section* writeglobal(section *SPtr); +static int SetEnv(char ****EnvPtr, char *name, char *value); +static int GetNextEnv(char ***EnvPtr, char **name, char **value); +static int ClearEnv(char ****EnvPtr); +static int Set_ILabel(char *value); +static int Set_OLabel(char *value); + +/****************************************************************************/ + +static char *NextItem(char *Line, int komma) +{ + register char *p; + register char *Ptr = Line; + + + while (*Line && (*Line != ' ') && (*Line != '\t')) + Line++; + + p = Line; + + while ((*Line == ' ') || (*Line == '\t')) + Line++; + + *p = 0; + + p = Line; + + while((Ptr = Check_Quote(Ptr, komma ? "\\$@;#" : S_QUOTES, QUOTE_DELETE)) != NULL); + + return(Line); +} /* NextItem */ + +/******************************************************************************/ + +static char*NextOption(char** Options, char* Delim) +{ + char *RetCode = NULL; + char *Ptr = *Options; + int Len; + + *Delim = '\0'; + + if (Ptr == NULL) + return NULL; + + if ((Ptr = Check_Quote(Ptr,";,",QUOTE_DELETE)) == NULL) + Ptr = ""; + + if (*Ptr == ',' || *Ptr == ';' || *Ptr == '\0') + { + *Delim = *Ptr; + + if (Ptr != *Options) + { + Len = Ptr-(*Options); + RetCode = (char*) calloc(Len+1, sizeof(char)); + strncpy(RetCode,*Options,Len); + } + + if (*Ptr == ',') + { + *Options = Ptr+1; + } + else + { + while(!isalpha(*Ptr) && *Ptr != '\0') + Ptr++; + + if (*Ptr == '\0') + *Options = NULL; + else + *Options = Ptr; + } + } + + return RetCode; +} + +/******************************************************************************/ + +static void Append(char **Target, char*Source) +{ + if (*Target == NULL) + { + *Target = Source; + return; + } + + if (Source == NULL) + return; + + *Target = (char*) realloc(*Target, sizeof(char)*(strlen(*Target)+strlen(Source)+2)); + strcat(*Target,","); + strcat(*Target,Source); +} + +/******************************************************************************/ + +static int SetFlags(KNOWN *FlagPtr, char *flags) +{ + auto char Delim = '\0'; + auto char *Ptr; + auto int NumArgs = 0; + auto int flag = 0; + + while (*flags == ' ' || *flags == '\t') + flags++; + + FlagPtr->infoargs = NULL; + FlagPtr->flags = 0; + + while (flags && *flags) { + flag = 0; + + while(isalpha(*flags) || isspace(*flags)) + { + switch (toupper(*flags++)) { + case 'I' : flag |= RING_INCOMING; break; + case 'O' : flag |= RING_OUTGOING; break; + case 'R' : flag |= RING_RING ; break; + case 'C' : flag |= RING_CONNECT ; break; + case 'B' : flag |= RING_BUSY ; break; + case 'A' : flag |= RING_AOCD ; break; + case 'E' : flag |= RING_ERROR ; break; + case 'H' : flag |= RING_HANGUP ; break; + case 'K' : flag |= RING_KILL ; break; + case 'L' : flag |= RING_LOOP ; break; + case 'S' : flag |= RING_SPEAK ; break; + case 'P' : flag |= RING_PROVIDER; break; + case 'U' : flag |= RING_UNIQUE ; break; + case ' ' : break; + case '\t': break; + + default : _print_msg( "%s: WARNING: Unknown flag ``%c'' in file \"%s\" line %d, ignored\n", Myname, *(flags-1), OLDCONFFILE, ln); + break; + } /* switch */ + } + + if (flag != 0) + { + if(*flags == '=') + { + flags++; + FlagPtr->flags |= flag; + FlagPtr->infoargs = (info_args**) realloc(FlagPtr->infoargs, sizeof(info_args*) * (NumArgs+2)); + FlagPtr->infoargs[NumArgs] = (info_args*) calloc(1, sizeof(info_args)); + + FlagPtr->infoargs[NumArgs]->flag = flag; + FlagPtr->infoargs[NumArgs]->infoarg = NextOption(&flags,&Delim); + + if (Delim == ',') + { + if ((Ptr = NextOption(&flags,&Delim)) != NULL) + { + FlagPtr->infoargs[NumArgs]->interval= atoi(Ptr); + free(Ptr); + } + } + + if (Delim == ',') + do + Append(&(FlagPtr->infoargs[NumArgs]->time), + NextOption(&flags,&Delim)); + while(Delim == ','); + + if (Delim != ';') + { + _print_msg( "%s: WARNING: Syntax-Error in file \"%s\" line %d, ignored (\";\" expected, but found \"%c\")\n", Myname, OLDCONFFILE, ln, Delim); + flags = NULL; + } + + FlagPtr->infoargs[++NumArgs] = NULL; + } + else + { + _print_msg( "%s: WARNING: Syntax-Error in file \"%s\" line %d, ignored (\"=\" expected, but found \"%c\")\n", Myname, OLDCONFFILE, ln, *flags); + flags = NULL; + } + } + } /* while */ + + return 0; +} + +/******************************************************************************/ + +static int IsVariable(char *string) +{ + char s1[SHORT_STRING_SIZE] = "", + s2[LONG_STRING_SIZE] = ""; + + if (sscanf(string,"%[a-zA-Z0-9] = %[^\n]",s1,s2) == 2) + { + if (SetEnv(&Environment,s1,s2) == 0) + return 1; + + _print_msg( "%s: WARNING: Error in file \"%s\" line %d: Can not set variable (%s)!\n", Myname, OLDCONFFILE, ln, strerror(errno)); + } + + return 0; +} + +/****************************************************************************/ + +int writeconfig(char *_myname) +{ + int i; + auto char s[BUFSIZ]; + auto section *SPtr = NULL; + + + if ((SPtr = writevariables(SPtr)) == NULL) + { + free_section(SPtr); + return -1; + } + + if ((SPtr = writeglobal(SPtr)) == NULL) + { + free_section(SPtr); + return -1; + } + + sprintf(s, "%s%c%s", confdir(), C_SLASH, CONFFILE); + write_file(SPtr,s,_myname,VERSION); + + free_section(SPtr); + SPtr = NULL; + + for (i = 0; i < knowns; i++) + { + if ((SPtr = writeentry(SPtr,i)) == NULL) + { + free_section(SPtr); + return -1; + } + } + + sprintf(s, "%s%c%s", confdir(), C_SLASH, CALLERIDFILE); + write_file(SPtr,s,_myname,VERSION); + + free_section(SPtr); + + return 0; +} + +/****************************************************************************/ + +static void appendflag(char*str1, char*str2) +{ + char delim[2]; + + delim[0] = C_FLAG_DELIM; + delim[1] = '\0'; + + if (str1[0] != '\0') + strcat(str1,delim); + + strcat(str1,str2); +} + +/****************************************************************************/ + +static char *writeflags(int flag) +{ + static char string[BUFSIZ]; + + string[0] = '\0'; + + if (flag & RING_INCOMING) + appendflag(string,"I"); + if (flag & RING_OUTGOING) + appendflag(string,"O"); + if (flag & RING_RING) + appendflag(string,"R"); + if (flag & RING_CONNECT) + appendflag(string,"C"); + if (flag & RING_BUSY) + appendflag(string,"B"); + if (flag & RING_AOCD) + appendflag(string,"A"); + if (flag & RING_ERROR) + appendflag(string,"E"); + if (flag & RING_HANGUP) + appendflag(string,"H"); + if (flag & RING_KILL) + appendflag(string,"K"); + if (flag & RING_LOOP) + appendflag(string,"L"); + if (flag & RING_SPEAK) + appendflag(string,"S"); + if (flag & RING_PROVIDER) + appendflag(string,"P"); + if (flag & RING_UNIQUE) + appendflag(string,"U"); + + return string; +} + +/****************************************************************************/ + +static section* writeinfoargs(section *SPtr, info_args *infoarg) +{ + section *Ptr; + auto char s[BUFSIZ]; + auto char s1[BUFSIZ]; + + strcpy(s, CONF_SEC_FLAG); + if ((Ptr = Set_Section(&SPtr,s,C_OVERWRITE | C_WARN | C_NOT_UNIQUE)) == NULL) + { + _print_msg("Can not set section `%s'!\n",CONF_SEC_FLAG); + free_section(SPtr); + return NULL; + } + + sprintf(s1,"%d",infoarg->flag); + strcpy(s, CONF_ENT_FLAGS); + if (Set_Entry(Ptr,NULL,s,writeflags(infoarg->flag),C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_FLAGS); + free_section(SPtr); + return NULL; + } + + strcpy(s, CONF_ENT_PROG); + if (Set_Entry(Ptr,NULL,s,infoarg->infoarg,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_PROG); + free_section(SPtr); + return NULL; + } + + if (infoarg->user != NULL) + { + strcpy(s, CONF_ENT_USER); + if (Set_Entry(Ptr,NULL,s,infoarg->user,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_USER); + free_section(SPtr); + return NULL; + } + } + + if (infoarg->group != NULL) + { + strcpy(s, CONF_ENT_GROUP); + if (Set_Entry(Ptr,NULL,s,infoarg->group,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_GROUP); + free_section(SPtr); + return NULL; + } + } + + if (infoarg->interval != 0) + { + sprintf(s1,"%d",infoarg->interval); + strcpy(s, CONF_ENT_INTVAL); + if (Set_Entry(Ptr,NULL,s,s1,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_INTVAL); + free_section(SPtr); + return NULL; + } + } + + if (infoarg->time != NULL) + { + strcpy(s, CONF_ENT_TIME); + if (Set_Entry(Ptr,NULL,s,infoarg->time,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_TIME); + free_section(SPtr); + return NULL; + } + } + + return SPtr; +} + +/****************************************************************************/ + +static section* writevariables(section *SPtr) +{ + char *name; + char *value; + auto char s[BUFSIZ]; + section *Ptr; + + + strcpy(s, CONF_SEC_VAR); + if ((Ptr = Set_Section(&SPtr,s,C_OVERWRITE | C_WARN)) == NULL) + { + _print_msg("Can not set section `%s'!\n",CONF_SEC_VAR); + free_section(SPtr); + return NULL; + } + + if (GetNextEnv(Environment,&name,&value) == 0) + do + { + if (Set_Entry(Ptr,NULL,name,value,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",name); + free_section(SPtr); + return NULL; + } + } + while(GetNextEnv(NULL,&name,&value) == 0); + + return SPtr; +} + +/****************************************************************************/ + +static section* writeglobal(section *SPtr) +{ + auto char s[BUFSIZ]; + auto char s1[BUFSIZ]; + int IIndex = 0; + section *Ptr; + section *SubPtr = NULL; + + + strcpy(s, CONF_SEC_GLOBAL); + if ((Ptr = Set_Section(&SPtr,s,C_OVERWRITE | C_WARN)) == NULL) + { + _print_msg("Can not set section `%s'!\n",CONF_SEC_GLOBAL); + free_section(SPtr); + return NULL; + } + + if (mycountry != NULL && mycountry[0] != '\0') + { + strcpy(s, CONF_ENT_COUNTRY); + if (Set_Entry(Ptr,NULL,s,mycountry,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_COUNTRY); + free_section(SPtr); + return NULL; + } + } + + if (myarea != NULL && myarea[0] != '\0') + { + strcpy(s, CONF_ENT_AREA); + if (Set_Entry(Ptr,NULL,s,myarea,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_AREA); + free_section(SPtr); + return NULL; + } + } + + strcpy(s, CONF_SEC_ISDNLOG); + if ((Ptr = Set_Section(&SPtr,s,C_OVERWRITE | C_WARN)) == NULL) + { + _print_msg("Can not set section `%s'!\n",CONF_SEC_ISDNLOG); + free_section(SPtr); + return NULL; + } + + if (reloadcmd != NULL) + { + strcpy(s, CONF_ENT_RELOAD); + if (Set_Entry(Ptr,NULL,s,reloadcmd,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_RELOAD); + free_section(SPtr); + return NULL; + } + } + + if (stopcmd != NULL) + { + strcpy(s, CONF_ENT_STOP); + if (Set_Entry(Ptr,NULL,s,stopcmd,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_STOP); + free_section(SPtr); + return NULL; + } + } + + if (rebootcmd != NULL) + { + strcpy(s, CONF_ENT_REBOOT); + if (Set_Entry(Ptr,NULL,s,rebootcmd,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_REBOOT); + free_section(SPtr); + return NULL; + } + } + + if (chargemax != 0) + { + strcpy(s, CONF_ENT_CHARGE); + sprintf(s1, "%.2f",chargemax); + if (Set_Entry(Ptr,NULL,s,s1,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_CHARGE); + free_section(SPtr); + return NULL; + } + } + + if (connectmax != 0) + { + strcpy(s, CONF_ENT_CONNECT); + sprintf(s1, "%.10g,%d",connectmax,connectmaxmode); + if (Set_Entry(Ptr,NULL,s,s1,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_CONNECT); + free_section(SPtr); + return NULL; + } + } + + if (bytemax != 0) + { + strcpy(s, CONF_ENT_BYTE); + sprintf(s1, "%.10g,%d",bytemax,bytemaxmode); + if (Set_Entry(Ptr,NULL,s,s1,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_BYTE); + free_section(SPtr); + return NULL; + } + } + + if (currency != NULL && currency_factor != 0) + { + strcpy(s, CONF_ENT_CURR); + sprintf(s1, "%.2f,%s",currency_factor,currency); + if (Set_Entry(Ptr,NULL,s,s1,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_CURR); + free_section(SPtr); + return NULL; + } + } + + if (IlabelPtr != NULL) + { + strcpy(s, CONF_ENT_ILABEL); + if (Set_Entry(Ptr,NULL,s,IlabelPtr,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_ILABEL); + free_section(SPtr); + return NULL; + } + } + + if (OlabelPtr != NULL) + { + strcpy(s, CONF_ENT_OLABEL); + if (Set_Entry(Ptr,NULL,s,OlabelPtr,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_OLABEL); + free_section(SPtr); + return NULL; + } + } + + IIndex = 0; + + if (start_procs.infoargs != NULL && start_procs.infoargs[0] != NULL) + { + while (start_procs.infoargs[IIndex] != NULL) + { + if ((SubPtr = writeinfoargs(SubPtr,start_procs.infoargs[IIndex])) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_SEC_START); + free_section(SPtr); + return NULL; + } + + IIndex++; + } + + strcpy(s, CONF_SEC_START); + + if (Set_SubSection(Ptr,s,SubPtr,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_SEC_START); + free_section(SPtr); + return NULL; + } + } + + return SPtr; +} + +/****************************************************************************/ + +static section* writeentry(section *SPtr, int Index) +{ + section *Ptr; + int IIndex = 0; + section *SubPtr = NULL; + auto char s[BUFSIZ]; + auto char s1[BUFSIZ]; + + + if (Index < mymsns) + strcpy(s,CONF_SEC_MSN); + else + strcpy(s,CONF_SEC_NUM); + + if ((Ptr = Set_Section(&SPtr,s,C_OVERWRITE | C_WARN | C_NOT_UNIQUE)) == NULL) + { + _print_msg("Can not set section `%s'!\n",CONF_SEC_NUM); + free_section(SPtr); + return NULL; + } + + strcpy(s, CONF_ENT_NUM); + if (Set_Entry(Ptr,NULL,s,known[Index]->num,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_NUM); + free_section(SPtr); + return NULL; + } + + if (known[Index]->si != 0) + { + strcpy(s, CONF_ENT_SI); + sprintf(s1,"%d",known[Index]->si); + if (Set_Entry(Ptr,NULL,s,s1,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_SI); + free_section(SPtr); + return NULL; + } + } + + strcpy(s, CONF_ENT_ALIAS); + if (Set_Entry(Ptr,NULL,s,known[Index]->who,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_ALIAS); + free_section(SPtr); + return NULL; + } + + if (strcmp(known[Index]->interface,"-") != 0 && known[Index]->interface[0] != '\0') + { + strcpy(s, CONF_ENT_INTFAC); + if (Set_Entry(Ptr,NULL,s,known[Index]->interface,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_INTFAC); + free_section(SPtr); + return NULL; + } + } + + strcpy(s, CONF_ENT_ZONE); + sprintf(s1,"%d",known[Index]->zone); + if (Set_Entry(Ptr,NULL,s,s1,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_ENT_ZONE); + free_section(SPtr); + return NULL; + } + + IIndex = 0; + + if (known[Index]->infoargs != NULL && known[Index]->infoargs[0] != NULL) + { + while (known[Index]->infoargs[IIndex] != NULL) + { + if ((SubPtr = writeinfoargs(SubPtr,known[Index]->infoargs[IIndex])) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_SEC_START); + free_section(SPtr); + return NULL; + } + + IIndex++; + } + + strcpy(s, CONF_SEC_START); + + if (Set_SubSection(Ptr,s,SubPtr,C_OVERWRITE | C_WARN) == NULL) + { + _print_msg("Can not set entry `%s'!\n",CONF_SEC_START); + free_section(SPtr); + return NULL; + } + } + + return SPtr; +} + +/****************************************************************************/ + +void setDefaults() +{ + if (currency == NULL) { + +#if defined(ISDN_NL) + currency = "NLG"; +#elif defined(ISDN_CH) + currency = "FR."; +#else + currency = " DM"; +#endif + + } /* if */ + + if (currency_factor == 0.0) { + +#if defined(ISDN_NL) + currency_factor = 0.15; +#elif defined(ISDN_CH) + currency_factor = 0.01; +#else + currency_factor = 0.12; +#endif + + } /* if */ + + currency_mode = AOC_UNITS; +} /* setDefaults */ + +/****************************************************************************/ + +int readconfig(char *_myname) +{ + register int cc; + + + if (!(cc = readconfigfile(_myname))) + setDefaults(); + + return(cc); +} /* readconfig */ + +/****************************************************************************/ + +static int readconfigfile(char *_myname) +{ + auto char file1[BUFSIZ]; + auto char file2[BUFSIZ]; + struct stat buf1, buf2; + int ret1, ret2; + + + if (use_new_config) { + sprintf(file1, "%s%c%s", confdir(), C_SLASH, CONFFILE); + ret1 = stat(file1,&buf1); + + sprintf(file2, "%s%c%s", confdir(), C_SLASH, OLDCONFFILE); + ret2 = stat(file2,&buf2); + + if (ret1 == 0) + { + if (access(file1,R_OK) == 0) + { + if (ret2 == 0 && access(file2,R_OK) == 0) + { + if (buf1.st_mtime >= buf2.st_mtime) + { + return _readconfig(_myname); + } + else + { + if (readoldconfig(_myname) == 0) + return writeconfig(_myname); + else + { + _print_msg("Can not read file %s!\n",file2); + return -1; + } + } + } + else + { + return _readconfig(_myname); + } + } + else + { + _print_msg("Can not read file %s!\n",file1); + return -1; + } + } + else + { + if (ret2 == 0 && access(file2,R_OK) == 0) + { + if (readoldconfig(_myname) == 0) + return writeconfig(_myname); + else + { + _print_msg("Can not read file %s!\n",file2); + return -1; + } + } + else + { + _print_msg("Can not read file %s!\n",file2); + return -1; + } + } + + return 0; + } + else + return(readoldconfig(_myname)); +} + +/****************************************************************************/ + +section *read_isdnconf(section **_conf_dat) +{ + read_conffiles(_conf_dat,NULL); + + return *_conf_dat; +} + +/****************************************************************************/ + +static int _readconfig(char *_myname) +{ + auto section *SPtr; + auto int i; + int cur_msn = 0; + + + Myname = _myname; + mymsns = 0; + mycountry = ""; + myarea = ""; + currency = NULL; + chargemax = 0.0; + connectmax = 0; + connectmaxmode = 0; + bytemax = 0; + bytemaxmode = 0; + knowns = retnum = 0; + known = NULL; + reloadcmd = RELOADCMD; + stopcmd = STOPCMD; + rebootcmd = REBOOTCMD; + start_procs.infoargs = NULL; + start_procs.flags = 0; + conf_dat = NULL; + + + ClearEnv(&Environment); + + if ((SPtr = read_isdnconf(&conf_dat)) == NULL) + return -1; + + Set_Globals(conf_dat); + + while (SPtr != NULL) + { + if (!strcmp(SPtr->name,CONF_SEC_MSN)) + Set_Numbers(SPtr,SPtr->name,cur_msn++); + else + if (!strcmp(SPtr->name,CONF_SEC_NUM)) + Set_Numbers(SPtr,SPtr->name,NO_MSN); + + SPtr = SPtr->next; + } + + for (i = 0; i < mymsns; i++) + if (known[i]->num == NULL) + { + _print_msg("Error: MSN number %d is not set!\n",i+1); + return -1; + } + + return 0; +} + +/****************************************************************************/ + +static int Set_Globals(section *SPtr) +{ + auto section *Ptr; + auto entry *CEPtr; + + + if ((Ptr = Get_Section(SPtr,CONF_SEC_GLOBAL)) != NULL) + { + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_AREA)) != NULL && CEPtr->value != NULL) + myarea = CEPtr->value; + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_COUNTRY)) != NULL && CEPtr->value != NULL) + mycountry = CEPtr->value; + } + else + _print_msg("%s: WARNING: There is no section `%s'!\n", Myname, CONF_SEC_GLOBAL); + + if ((Ptr = Get_Section(SPtr,CONF_SEC_ISDNLOG)) != NULL) + { + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_ILABEL)) != NULL) + Set_ILabel(CEPtr->value); + else + Set_ILabel(NULL); + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_OLABEL)) != NULL) + Set_OLabel(CEPtr->value); + else + Set_OLabel(NULL); + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_START)) != NULL) + start_procs.infoargs = Set_Flags(CEPtr->subsection,&(start_procs.flags)); + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_RELOAD)) != NULL) + reloadcmd = CEPtr->value; + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_STOP)) != NULL) + stopcmd = CEPtr->value; + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_REBOOT)) != NULL) + rebootcmd = CEPtr->value; + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_CHARGE)) != NULL) + chargemax = strtod(CEPtr->value,NULL); + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_CONNECT)) != NULL) + { + if (sscanf(CEPtr->value,"%lg,%d", &connectmax, &connectmaxmode) != 2) + _print_msg("%s: WARNING: Syntax error in `%s' in Line %d, ignored\n", Myname, CONF_ENT_CONNECT, ln); + } + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_BYTE)) != NULL) + { + if (sscanf(CEPtr->value,"%lg,%d", &bytemax, &bytemaxmode) != 2) + _print_msg("%s: WARNING: Syntax error in `%s' in Line %d, ignored\n", Myname, CONF_ENT_CONNECT, ln); + } + + if ((CEPtr = Get_Entry(Ptr->entries,CONF_ENT_CURR)) != NULL) + { + currency_factor = atof(CEPtr->value); + + if ((currency = strchr(CEPtr->value, ',')) == NULL) + _print_msg("%s: WARNING: Syntax error in `%s' in Line %d, ignored\n", Myname, CONF_ENT_CURR, ln); + } + } + else + _print_msg("%s: WARNING: There is no section `%s'!\n", Myname, CONF_SEC_ISDNLOG); + + if (mycountry == NULL && mycountry[0] == '\0') { + _print_msg("%s: WARNING: Variable `%s' is not set!\n", Myname, CONF_ENT_COUNTRY); + mycountry = ""; + } + + if (myarea == NULL && myarea[0] == '\0') + { + _print_msg("%s: WARNING: Variable `%s' is not set!\n", Myname, CONF_ENT_AREA); + myarea = ""; + } + + if (chargemax == 0) + { + _print_msg("%s: WARNING: Variable `%s' is not set, \nperforming no action when chargemax-overflow\n", Myname, CONF_ENT_CHARGE); + } + + return 0; +} + +/****************************************************************************/ + +static info_args** Set_Flags(section *SPtr, int *Flags) +{ + static int NumArgs; + info_args** RetCode = NULL; + entry* EPtr; + int Flag; + + + if (SPtr == NULL) + { + NumArgs = 0; + return NULL; + } + + RetCode = Set_Flags(SPtr->next,Flags); + + RetCode = realloc(RetCode, sizeof(info_args*) * (NumArgs+2)); + RetCode[NumArgs] = (info_args*) calloc(1, sizeof(info_args)); + + EPtr = SPtr->entries; + + while (EPtr != NULL) + { + if (!strcmp(EPtr->name,CONF_ENT_FLAGS)) + { + if ((Flag = Get_Events(EPtr->value)) < 0) + _print_msg("Error: Invalid value of variable `%s'!\n",EPtr->name); + else + { + RetCode[NumArgs]->flag = Flag; + *Flags |= Flag; + } + } + else + if (!strcmp(EPtr->name,CONF_ENT_PROG)) + { + RetCode[NumArgs]->infoarg = EPtr->value; + } + else + if (!strcmp(EPtr->name,CONF_ENT_USER)) + { + RetCode[NumArgs]->user = EPtr->value; + } + else + if (!strcmp(EPtr->name,CONF_ENT_GROUP)) + { + RetCode[NumArgs]->group = EPtr->value; + } + else + if (!strcmp(EPtr->name,CONF_ENT_INTVAL)) + { + if (EPtr->value != NULL) + RetCode[NumArgs]->interval = atoi(EPtr->value); + } + else + if (!strcmp(EPtr->name,CONF_ENT_TIME)) + { + RetCode[NumArgs]->time = EPtr->value; + } + else + _print_msg("Error: Invalid variable `%s'!\n",EPtr->name); + + EPtr = EPtr->next; + } + + + RetCode[++NumArgs] = NULL; + + return RetCode; +} + +/****************************************************************************/ + +static int Get_Events(char* Flags) +{ + int flag = 0, Index = 0; + + + while (*Flags != '\0') + { + while (isspace(*Flags) || *Flags == C_FLAG_DELIM) Flags++; + + if (*Flags != '\0') + { + switch (toupper(*Flags)) + { + case 'I' : flag |= RING_INCOMING; break; + case 'O' : flag |= RING_OUTGOING; break; + case 'R' : flag |= RING_RING ; break; + case 'C' : flag |= RING_CONNECT ; break; + case 'B' : flag |= RING_BUSY ; break; + case 'A' : flag |= RING_AOCD ; break; + case 'E' : flag |= RING_ERROR ; break; + case 'H' : flag |= RING_HANGUP ; break; + case 'K' : flag |= RING_KILL ; break; + case 'L' : flag |= RING_LOOP ; break; + case 'S' : flag |= RING_SPEAK ; break; + case 'P' : flag |= RING_PROVIDER; break; + case 'U' : flag |= RING_UNIQUE ; break; + + default : _print_msg( "%s: WARNING: Unknown flag `%c' in file \"%s\" line %d, ignored\n", Myname, *Flags, CONFFILE, ln); + break; + } /* switch */ + + Flags++; + } + + Index++; + } + + return flag; +} + +/****************************************************************************/ + +static int Set_Numbers(section *SPtr, char *Section, int msn) +{ + auto entry *CEPtr; + auto char *num = 0, *who = 0; + auto int Index; + + + if ((CEPtr = Get_Entry(SPtr->entries,CONF_ENT_NUM)) != NULL) + num = CEPtr->value; + else + { + _print_msg("%s: ERROR: There is no variable `%s' in section '%s'!\n", Myname, CONF_ENT_NUM, Section); + num = S_UNKNOWN; + } + + if ((CEPtr = Get_Entry(SPtr->entries,CONF_ENT_ALIAS)) != NULL) + who = CEPtr->value; + else + { + _print_msg("%s: ERROR: There is no variable `%s' in section '%s'!\n", Myname, CONF_ENT_ALIAS, Section); + who = S_UNKNOWN; + } + + if (*num && *who) { + + if ((Index = Set_known_Size(msn)) >= 0) { + + known[Index]->num = num; + known[Index]->who = who; + known[Index]->day = -1; + known[Index]->charge = 0.0; + known[Index]->rcharge = 0.0; + known[Index]->scharge = 0.0; + + known[Index]->month = -1; + known[Index]->online = 0.0; + known[Index]->sonline = 0.0; + + known[Index]->bytes = 0.0; + known[Index]->sbytes = 0.0; + + if ((CEPtr = Get_Entry(SPtr->entries,CONF_ENT_ZONE)) != NULL) + known[Index]->zone = atoi(CEPtr->value); + else + { + if (msn < 0) + { + _print_msg("%s: WARNING: There is no variable `%s' for number '%s'!\n", Myname, CONF_ENT_ZONE, num); + known[Index]->zone = 4; + } + else + known[Index]->zone = 1; + } + + if ((CEPtr = Get_Entry(SPtr->entries,CONF_ENT_INTFAC)) != NULL) + known[Index]->interface = CEPtr->value; + else + known[Index]->interface = "-"; + + if ((CEPtr = Get_Entry(SPtr->entries,CONF_ENT_SI)) != NULL) + known[Index]->si = strtol(CEPtr->value, NIL, 0); + else + known[Index]->si = 0; + + if ((CEPtr = Get_Entry(SPtr->entries,CONF_ENT_START)) != NULL) + known[Index]->infoargs = Set_Flags(CEPtr->subsection,&(known[Index]->flags)); + else + known[Index]->infoargs = NULL; + } + else + { + _print_msg("%s: ERROR: Can not allocate memory!\n", Myname); + return -1; + } + + if (msn >= 0) + known[Index]->zone = 1; + } + + return 0; +} + +/****************************************************************************/ + +static int Set_known_Size(int msn) +{ + int Index; + KNOWN **Ptr; + + if (knowns == 0) + mymsns = 0; + + if (msn < 0) + { + if ((known = (KNOWN **) realloc(known, sizeof(KNOWN *) * (knowns + 1))) == NULL) + return -1; + + knowns++; + } + else + if (mymsns <= msn) + { + int NewKnowns = msn+knowns-mymsns+1; + + if ((Ptr = (KNOWN **) calloc(NewKnowns, sizeof(KNOWN *))) == NULL) + return -1; + + if (known != NULL) + { + memcpy(Ptr,known,sizeof(KNOWN*) * (mymsns)); + memcpy(&(Ptr[msn+1]),&(known[mymsns]),sizeof(KNOWN*) * (knowns-mymsns)); + free(known); + } + + known = Ptr; + knowns= NewKnowns; + mymsns = msn+1; + } + + if (msn < 0) + Index = knowns - 1; + else + Index = msn; + + if ((known[Index] = (KNOWN *) calloc(1,sizeof(KNOWN))) == NULL) + return -1; + + return Index; +} + +/****************************************************************************/ + +static int readoldconfig(char *myname) +{ + register char *p; + register int i; + auto int start_ln = 0; + auto FILE *f; + auto char s[BUFSIZ]; + auto char *num, *who, *zone, *flags, *interface; + auto char *Ptr; + + ln = 0; + + mymsns = 3; + mycountry = ""; + myarea = ""; + currency = NULL; + chargemax = 0.0; + connectmax = 0.0; + bytemax = 0.0; + connectmaxmode = 0; + bytemaxmode = 0; + knowns = retnum = 0; + known = (KNOWN **)NULL; + start_procs.infoargs = NULL; + start_procs.flags = 0; + + + sprintf(s, "%s%c%s", confdir(), C_SLASH, OLDCONFFILE); + + if ((f = fopen(s, "r")) != (FILE *)NULL) { + + while (FGets(s, BUFSIZ, f, &ln) != NULL) { + if ((*s != '\0') && (*s != '\n')) { + + if ((p = strchr(s, '\n'))) { + *p = 0; + + while (*--p == ' ') + *p = 0; + } /* if */ + + if (!IsVariable(s)) + { + num = s; + who = NextItem(num, 1); + zone = NextItem(who, 0); + interface = NextItem(zone, 0); + flags = NextItem(interface, 0); + + if (*num && *who) { + known = realloc(known, sizeof(KNOWN *) * (knowns + 1)); + + if ((known[knowns] = (KNOWN *)malloc(sizeof(KNOWN)))) { + + if ((p = strchr(num, ','))) { /* MSN,SI */ + known[knowns]->si = atoi(p + 1); + *p = 0; + } + else + known[knowns]->si = 0; + + known[knowns]->num = strdup(num); + known[knowns]->who = strdup(who); + known[knowns]->zone = atoi(zone); + known[knowns]->interface = strdup(interface); + known[knowns]->flags = 0; + + SetFlags(known[knowns], flags); + + known[knowns]->dur[CALLING] = known[knowns]->dur[CALLED] = 0.0; + known[knowns]->eh = 0; + known[knowns]->usage[DIALOUT] = known[knowns]->usage[DIALIN] = 0; + known[knowns]->dm = 0.0; + + known[knowns]->day = -1; + known[knowns]->charge = 0.0; + known[knowns]->rcharge = 0.0; + known[knowns]->scharge = 0.0; + + known[knowns]->month = -1; + known[knowns]->online = 0.0; + known[knowns]->sonline = 0.0; + + known[knowns]->bytes = 0.0; + known[knowns]->sbytes = 0.0; + + knowns++; + } + else { + _print_msg("%s: WARNING: Out of memory in Line %d\n", myname, ln); + break; + } /* else */ + } + else { + _print_msg("%s: WARNING: Syntax error in Line %d, ignored\n", myname, ln); + /* break; */ + } /* else */ + } /* else */ + else + if (start_ln == 0 && getenv(VAR_START) != NULL) + start_ln = ln; + + } /* if */ + + } /* while */ + + fclose(f); + + if ((Ptr = getenv(VAR_MYMSNS)) == NULL) { + _print_msg("%s: WARNING: Variable `%s' is not set, now is 3!\n", myname, VAR_MYMSNS); + mymsns = 3; + } + else + mymsns = atoi(Ptr); + + if ((myarea = getenv(VAR_MYAREA)) == NULL) + _print_msg("%s: WARNING: Variable `%s' is not set!\n", myname, VAR_MYAREA); + + if ((mycountry = getenv(VAR_MYCOUNTRY)) == NULL) + _print_msg("%s: WARNING: Variable `%s' is not set!\n", myname, VAR_MYCOUNTRY); + + if ((Ptr = getenv(VAR_CURRENCY)) != NULL) { + currency_factor = atof(Ptr); + + if ((currency = strchr(Ptr, ',')) == NULL) + _print_msg("%s: WARNING: Syntax error in `CURRENCY' in Line %d, ignored\n", myname, ln); + else + currency++; + } + + if ((Ptr = getenv(VAR_CHARGEMAX)) == NULL) + _print_msg("%s: WARNING: Variable `%s' is not set, \nperforming no action when chargemax-overflow\n", myname, VAR_CHARGEMAX); + else + chargemax = strtod(Ptr, NULL); + + if ((Ptr = getenv(VAR_CONNECTMAX)) == NULL) + _print_msg("%s: WARNING: Variable `%s' is not set, \nperforming no action when connectmax-overflow\n", myname, VAR_CONNECTMAX); + else { + if (sscanf(Ptr, "%lg,%d", &connectmax, &connectmaxmode) != 2) + _print_msg("%s: WARNING: Syntax error in `%s' in Line %d, ignored\n", Myname, VAR_CONNECTMAX, ln); + } /* else */ + + if ((Ptr = getenv(VAR_BYTEMAX)) == NULL) + _print_msg("%s: WARNING: Variable `%s' is not set, \nperforming no action when connectmax-overflow\n", myname, VAR_BYTEMAX); + else { + if (sscanf(Ptr, "%lg,%d", &bytemax, &bytemaxmode) != 2) + _print_msg("%s: WARNING: Syntax error in `%s' in Line %d, ignored\n", Myname, VAR_BYTEMAX, ln); + } /* else */ + + if ((Ptr = getenv(VAR_START)) != NULL) { + ln = start_ln; + SetFlags(&start_procs, Ptr); + } + + Set_ILabel(getenv(VAR_ILABEL)); + Set_OLabel(getenv(VAR_OLABEL)); + +/* Wenn eine unbekannte Varible kommt, stuerzt isdnlog einfach ab ;-) !!!!*/ + if ((mycountry != NULL && mycountry[0] == '\0') && + (myarea != NULL && myarea[0] == '\0') ) + { + for (i = 0; i < mymsns; i++) { + if (known != NULL && known[i]->num != NULL) { + sprintf(s, "%s%s%s", mycountry, myarea, known[i]->num); + free(known[i]->num); + known[i]->num = strdup(s); + } + else + { + _print_msg("%s: ERROR: There are only %d MSN's, expected %d!\n",myname, i, mymsns); + return -1; + } + } /* for */ + } /* if */ + } + else + { + _print_msg("%s: WARNING: Can't open ``%s''\n", myname, s); + return -1; + } + + return 0; +} /* readconfig */ + +/****************************************************************************/ + +void discardconfig(void) +{ + register int i,j; + + free_section(conf_dat); + ClearEnv(&Environment); + + for (i = 0; i < knowns; i++) { + /* Unnoetig mit neuer readconfig + free(known[i]->num); + free(known[i]->who); + free(known[i]->interface); + */ + + for (j = 0; known[i]->infoargs != NULL && known[i]->infoargs[j] != NULL; j++) { + /* Unnoetig mit neuer readconfig + free(known[i]->infoargs[j]->time); + free(known[i]->infoargs[j]->infoarg); + */ + free(known[i]->infoargs[j]); + } + + free(known[i]->infoargs); + free(known[i]); + } /* for */ + + free(known); + + currency = NULL; + mycountry = ""; + myarea = ""; + + if (start_procs.infoargs != NULL) + { + int j; + for (j = 0; start_procs.infoargs != NULL && start_procs.infoargs[j] != NULL; j++) { + /* Unnoetig mit neuer readconfig + free(start_procs.infoargs[j]->time); + free(start_procs.infoargs[j]->infoarg); + */ + free(start_procs.infoargs[j]); + } + free(start_procs.infoargs); + } + +} /* discardconfig */ + +/****************************************************************************/ + +static int SetEnv(char ****EnvPtr, char *name, char *value) +{ + int elem = 2; + char ***CurEnvPtr = NULL; + + + if (setenv(name,value,1) != 0) + return -1; + + if (!strcmp(name,CONF_ENT_AREA) || !strcmp(name,CONF_ENT_CURR) || + !strcmp(name,CONF_ENT_START) || !strcmp(name,CONF_ENT_ILABEL) || + !strcmp(name,CONF_ENT_OLABEL) || !strcmp(name,VAR_MYMSNS) || + !strcmp(name,CONF_ENT_COUNTRY) || !strcmp(name,CONF_ENT_CHARGE) || + !strcmp(name,CONF_ENT_RELOAD) || !strcmp(name,CONF_ENT_STOP) || + !strcmp(name,CONF_ENT_REBOOT) || !strcmp(name,CONF_ENT_CONNECT)|| + !strcmp(name,CONF_ENT_AREA) || !strcmp(name,CONF_ENT_CONNECT)|| + !strcmp(name,CONF_ENT_BYTE) ) + return 0; + + CurEnvPtr = *EnvPtr; + + if (CurEnvPtr != NULL) + while(*CurEnvPtr != NULL) + { + elem++; + CurEnvPtr++; + } + + CurEnvPtr = NULL; + + if ((*EnvPtr = (char***) realloc(*EnvPtr,sizeof(char**)*elem)) == NULL) + return -1; + + (*EnvPtr)[elem-1] = NULL; + + if (((*EnvPtr)[elem-2] = (char**) calloc(2,sizeof(char*))) == NULL) + return -1; + + if (((*EnvPtr)[elem-2][0] = strdup(name)) == NULL) + return -1; + + if (((*EnvPtr)[elem-2][1] = strdup(value)) == NULL) + return -1; + + return 0; +} + +/****************************************************************************/ + +static int GetNextEnv(char ***EnvPtr, char **name, char **value) +{ + static char ***CurEnvPtr = NULL; + + + if (EnvPtr != NULL) + CurEnvPtr = EnvPtr; + else + { + if (CurEnvPtr == NULL || CurEnvPtr[0] == NULL) + return -1; + else + CurEnvPtr++; + } + + + if (CurEnvPtr[0] == NULL || CurEnvPtr[0][0] == NULL || CurEnvPtr[0][1] == NULL) + return -1; + + *name = CurEnvPtr[0][0]; + *value = CurEnvPtr[0][1]; + + return 0; +} + +/****************************************************************************/ + +static int ClearEnv(char ****EnvPtr) +{ + char ***CurEnvPtr = NULL; + CurEnvPtr = *EnvPtr; + + if (CurEnvPtr == NULL) + return 0; + + while(CurEnvPtr[0] != NULL) + { + free(CurEnvPtr[0][0]); + free(CurEnvPtr[0][1]); + free(CurEnvPtr[0]); + CurEnvPtr++; + } + + free(*EnvPtr); + *EnvPtr = CurEnvPtr = NULL; + + return 0; +} + +/****************************************************************************/ + +static int Set_ILabel(char *value) +{ + if ((IlabelPtr = value) == NULL) + IlabelPtr = "%b %e %T %ICall to tei %t from %N2 on %n2"; + + sprintf(ilabel, "%%s%s %%s%%s", IlabelPtr); + + return 0; +} + +/****************************************************************************/ + +static int Set_OLabel(char *value) +{ + if ((OlabelPtr = value) == NULL) + OlabelPtr = "%b %e %T %Itei %t calling %N2 with %n2"; + + sprintf(olabel, "%%s%s %%s%%s", OlabelPtr); + + return 0; +} + +/****************************************************************************/ diff --git a/isdnlog/tools/tools.c b/isdnlog/tools/tools.c new file mode 100644 index 00000000..a2e3b0ff --- /dev/null +++ b/isdnlog/tools/tools.c @@ -0,0 +1,850 @@ +/* $Id: tools.c,v 1.1 1997/03/16 20:59:24 luethje Exp $ + * + * ISDN accounting for isdn4linux. (Utilities) + * + * 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: tools.c,v $ + * Revision 1.1 1997/03/16 20:59:24 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.26 1997/01/19 22:23:43 akool + * Weitere well-known number's hinzugefuegt + * + * Revision 2.6.24 1997/01/15 19:13:43 akool + * neue AreaCode Lib 0.99 integriert + * + * Revision 2.6.20 1997/01/05 20:06:43 akool + * atom() erkennt nun "non isdnlog" "/tmp/isdnctrl0" Output's + * + * Revision 2.6.19 1997/01/05 19:39:43 akool + * LIBAREA Support added + * + * Revision 2.40 1996/06/16 10:06:43 akool + * double2byte(), time2str() added + * + * Revision 2.3.26 1996/05/05 12:09:16 akool + * known.interface added + * + * Revision 2.3.15 1996/04/22 21:10:16 akool + * + * Revision 2.3.4 1996/04/05 11:12:16 sl + * confdir() + * + * Revision 2.2.5 1996/03/25 19:41:16 akool + * 1TR6 causes implemented + * + * Revision 2.23 1996/03/14 20:29:16 akool + * Neue Routine i2a() + * + * Revision 2.17 1996/02/25 19:14:16 akool + * Soft-Error in atom() abgefangen + * + * Revision 2.06 1996/02/07 18:49:16 akool + * AVON-Handling implementiert + * + * Revision 2.01 1996/01/20 12:11:16 akool + * Um Einlesen der neuen isdnlog.conf Felder erweitert + * discardconfig() implementiert + * + * Revision 2.00 1996/01/10 20:11:16 akool + * + */ + +/****************************************************************************/ + + +#define PUBLIC /**/ +#define _TOOLS_C_ + +/****************************************************************************/ + +#include "tools.h" + +/****************************************************************************/ + +/*static char *cclass(register char *p, register int sub);*/ + +/****************************************************************************/ + +char Months[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +/****************************************************************************/ + +static char proto[] = " 0,000000000"; +static int cnf; + +/****************************************************************************/ + +void set_print_fct_for_tools(int (*new_print_msg)(const char *, ...)) +{ + _print_msg = new_print_msg; + set_print_fct_for_lib(_print_msg); +} + +/****************************************************************************/ + +time_t atom(register char *p) +{ + register char *p1 = p; + auto struct tm tm; + + +#ifdef DEBUG_1 + if (strlen(p) < 20) { + _print_msg(PRT_DEBUG_GENERAL, " DEBUG> Huch? atom(``%s'')\n", p); + return((time_t)0); + } /* if */ +#endif + + tm.tm_mon = 0; + + while ((tm.tm_mon < 12) && memcmp(p1, Months[tm.tm_mon], 3)) tm.tm_mon++; + + if (tm.tm_mon == 12) + return((time_t)-1); + + p1 += 4; + p = p1 + 2; + + *p = 0; + + day = tm.tm_mday = atoi(p1); + + p1 += 3; + p = p1 + 2; + *p = 0; + tm.tm_hour = atoi(p1); + + p1 = ++p; + p += 2; + *p = 0; + tm.tm_min = atoi(p1); + + p1 = ++p; + p += 2; + *p = 0; + tm.tm_sec = atoi(p1); + + p1 = ++p; + p += 4; + *p = 0; + + tm.tm_year = atoi(p1 + 2); + +#ifdef DEBUG_1 + if (tm.tm_year < 1995) { + _print_msg(PRT_DEBUG_GENERAL, " DEBUG> Huch? atom(): year=%d\n", tm.tm_year); + return((time_t)0); + } /* if */ +#endif + + tm.tm_wday = tm.tm_yday; + tm.tm_isdst = -1; + + return(mktime(&tm)); +} /* atom */ + +/****************************************************************************/ + +char *num2nam(char *num, int si) +{ + register int i, n; + + + if (*num) { + for (n = 0; n < 2; n++) { + for (i = 0; i < knowns; i++) { + if (((known[i]->si == si) || n) && (!num_match(known[i]->num, num))) { + if (++retnum == MAXRET) + retnum = 0; + + cnf = i; + return(strcpy(retstr[retnum], known[i]->who)); + } /* if */ + } /* for */ + } /* for */ + } /* if */ + + cnf = -1; + return(""); +} /* num2nam */ + +/****************************************************************************/ + +#ifdef _GNU_SOURCE +char *double2str(double n, int l, int d, int flags) +{ + if (++retnum == MAXRET) + retnum = 0; + + sprintf(retstr[retnum], "%*.*f", l, d, n); + return(retstr[retnum]); +} /* double2str */ +#else +char *double2str(double n, int l, int d, int flags) +{ + register char *p, *ps, *pd, *px; + auto int decpt, sign, dec, dp; + auto char buf[BUFSIZ]; + + + if (++retnum == MAXRET) + retnum = 0; + + p = retstr[retnum] + l + 1; + *p = 0; + + dec = d ? d : -1; + dp = l - dec; + + *buf = '0'; + memcpy(buf + 1, ecvt(n, DIGITS, &decpt, &sign), DIGITS); + + ps = buf; + px = ps + decpt + d; + + if (px >= buf) { + int rfound = 0; + pd = px + 1; + + if (*pd > '4') { + pd++; + rfound++; + } /* if */ + + if (rfound) { + while (pd > px) + if (*pd >= '5') { + pd--; + while (*pd == '9') + *pd-- = '0'; + *pd += 1; + } + else + pd--; + } /* if */ + + if (*buf == '1') + decpt++; + else + ps++; + + if ((dp < 2 + sign) || ((decpt ? decpt : 1) + sign) >= dp) { + memset(retstr[retnum] + 1, '*', *retstr[retnum] = l); + return(retstr[retnum] + 1); + } /* if */ + + } /* if */ + + memcpy(retstr[retnum] + 1, proto + 21 - l + dec, *retstr[retnum] = l); + + if (!((decpt < 0) && ((dec + decpt) <= 0))) { + pd = retstr[retnum] + dp - decpt; + + if (sign) { + if (decpt > 0) + *(pd - 1) = '-'; + else + *(retstr[retnum] + dp - 2) = '-'; + } /* if */ + + while (decpt-- > 0) + *pd++ = *ps++; + + pd++; /* skip comma */ + + while (d-- > 0) + *pd++ = *ps++; + } /* if */ + + if (flags & DEB) { + p = retstr[retnum] + 1; + + while (*p == ' ') + p++; + + return(p); + } /* if */ + + return(retstr[retnum] + 1); + +} /* double2str */ +#endif + +/****************************************************************************/ + +char *double2byte(double bytes) +{ + static char mode[4] = " KMG"; + register int m = 0; + + + if (++retnum == MAXRET) + retnum = 0; + + while (bytes > 999.9) { + bytes /= 1024.0; + m++; + } /* while */ + + sprintf(retstr[retnum], "%s%cb", double2str(bytes, 5, 1, 0), mode[m]); + + return(retstr[retnum]); +} /* double2byte */ + +/****************************************************************************/ + +char *time2str(time_t sec) +{ + static char mode[3] = "smh"; + register int m = 0; + auto double s = (double)sec; + + + if (++retnum == MAXRET) + retnum = 0; + + while (s > 59.9) { + s /= 60.0; + m++; + } /* while */ + + sprintf(retstr[retnum], "%s%c", double2str(s, 4, 1, 0), mode[m]); + + return(retstr[retnum]); +} /* time2str */ + +/****************************************************************************/ + +char *double2clock(double n) +{ + auto int x, h, m, s; + + + if (++retnum == MAXRET) + retnum = 0; + + + if (n <= 0.0) + sprintf(retstr[retnum], " "); + else { +#if 0 + x = floor(n); +#else + x = (int)n; +#endif + + h = (int)(x / 60 / 60); + x %= 60 * 60; + m = (int)(x / 60); + s = (int)(x % 60); + +#if 0 + sprintf(retstr[retnum], "%2d:%02d:%02d.%02d", h, m, s, + (int)((n - x) * 100)); +#else + sprintf(retstr[retnum], "%2d:%02d:%02d", h, m, s); +#endif + } /* else */ + + return(retstr[retnum]); +} /* double2clock */ + +/****************************************************************************/ + +char *vnum(int chan, int who) +{ + register int l = strlen(call[chan].num[who]), got = 0; + register int flag = C_NO_WARN | C_NO_EXPAND; + auto char *ptr; + auto int ll; + auto int prefix = strlen(S_COUNTRY_PREFIX); + + + if (++retnum == MAXRET) + retnum = 0; + + *call[chan].vorwahl[who] = + *call[chan].rufnummer[who] = + *call[chan].alias[who] = + *call[chan].area[who] = 0; + call[chan].confentry[who] = -1; + + if (!l) { /* keine Meldung von der Vst (Calling party number fehlt) */ + sprintf(retstr[retnum], "%c", C_UNKNOWN); + return(retstr[retnum]); + } /* if */ + + strcpy(call[chan].alias[who], num2nam(call[chan].num[who], call[chan].si1)); + + if (cnf > -1) { /* Alias gefunden! */ + call[chan].confentry[who] = cnf; + strcpy(retstr[retnum], call[chan].alias[who]); + } /* if */ + +#ifdef Q931 + if (q931dmp) + flag |= C_NO_ERROR; +#endif + + if ((ptr = get_areacode(call[chan].num[who], &ll, flag)) != 0) { + strcpy(call[chan].area[who], ptr); + l = ll; + got++; + } /* if */ + + /* Die folgenden Zeilen basieren nur auf eine Annahme, das ein Laendercode + aus zwei Ziffern besteht!!!!!!! */ + + if (l > 1) { + strncpy(call[chan].areacode[who], call[chan].num[who], 2 + prefix); + strncpy(call[chan].vorwahl[who], call[chan].num[who] + 2 + prefix, l - 2 - prefix); + strcpy(call[chan].rufnummer[who], call[chan].num[who] + l); + } /* if */ + + if (cnf > -1) + strcpy(retstr[retnum], call[chan].alias[who]); + else if (l > 1) + sprintf(retstr[retnum], "%s %s/%s, %s", + call[chan].areacode[who], + call[chan].vorwahl[who], + call[chan].rufnummer[who], + call[chan].area[who]); + else + strcpy(retstr[retnum], call[chan].num[who]); + + return(retstr[retnum]); +} /* vnum */ + +/****************************************************************************/ + +char *i2a(int n, int l, int base) +{ + static char Digits[] = "0123456789abcdef"; + register char *p; + register int dot = 0; + + + if (++retnum == MAXRET) + retnum = 0; + + p = retstr[retnum] + RETSIZE - 1; + *p = 0; + + while (n || (l > 0)) { + if (n) { + *--p = Digits[n % base]; + n /= base; + } + else + *--p = '0'; + + l--; + + dot++; + + if (!(dot % 8)) + *--p = ' '; + else if (!(dot % 4)) + *--p = '.'; + } /* while */ + + return(((*p == ' ') || (*p == '.')) ? p + 1 : p); +} /* i2a */ + +/****************************************************************************/ + +static char *itoa(register unsigned int num, register char *p, register int radix, int dots) +{ + register int i, j = 0; + register char *q = p + MAXDIG; + + + do { + i = (int)(num % radix); + i += '0'; + + if (i > '9') + i += 'A' - '0' - 10; + + *--q = i; + + if (dots) + if (!(++j % 3)) + *--q = '.'; + + } while ((num = num / radix)); + + if (*q == '.') + q++; + + i = p + MAXDIG - q; + + do + *p++ = *q++; + while (--i); + + return(p); +} /* itoa */ + +/****************************************************************************/ + +static char *ltoa(register unsigned long num, register char *p, register int radix, int dots) +{ + register int i, j = 0; + register char *q = p + MAXDIG; + + + do { + i = (int)(num % radix); + i += '0'; + + if (i > '9') + i += 'A' - '0' - 10; + + *--q = i; + + if (dots) + if (!(++j % 3)) + *--q = '.'; + + } while ((num = num / radix)); + + if (*q == '.') + q++; + + i = p + MAXDIG - q; + + do + *p++ = *q++; + while (--i); + + return(p); +} /* ltoa */ + +/****************************************************************************/ + +int iprintf(char *obuf, int chan, register char *fmt, ...) +{ + register char *p, *s; + register int c, i, who; + register short int width, ndigit; + register int ndfnd, ljust, zfill, lflag; + register long l; + register char *op = obuf; +#if 0 + auto int decpt, sign; +#endif + auto char buf[MAXDIG + 1]; /* +1 for sign */ + static char nul[] = "(null)"; + auto va_list ap; + + + va_start(ap, fmt); + + for (;;) { + c = *fmt++; + + if (!c) { + va_end(ap); + + *op = 0; + + return((int)(op - obuf)); + } /* if */ + + if (c != '%') { + *op++ = c; + continue; + } /* if */ + + p = s = buf; + + ljust = 0; + + if (*fmt == '-') { + fmt++; + ljust++; + } /* if */ + + zfill = ' '; + + if (*fmt == '0') { + fmt++; + zfill = '0'; + } /* if */ + + for (width = 0;;) { + c = *fmt++; + + if (isdigit(c)) + c -= '0'; + else if (c == '*') + c = GETARG(int); + else + break; + + width *= 10; + width += c; + } /* for */ + + ndfnd = ndigit = 0; + + if (c == '.') { + for (;;) { + c = *fmt++; + + if (isdigit(c)) + c -= '0'; + else if (c == '*') + c = GETARG(int); + else + break; + + ndigit *= 10; + ndigit += c; + ndfnd++; + } /* for */ + } /* if */ + + lflag = 0; + + if (tolower(c) == 'l') { + lflag++; + + if (*fmt) + c = *fmt++; + } /* if */ + + who = OTHER; + + switch (c) { + case 'X' : lflag++; + case 'x' : c = 16; + goto oxu; + + case 'U' : lflag++; + case 'u' : c = 10; + goto oxu; + + case 'O' : lflag++; + case 'o' : c = 8; +oxu: + if (lflag) + p = ltoa((unsigned long)GETARG(long), p, c, 0); + else + p = itoa((unsigned int)GETARG(int), p, c, 0); + break; + + case 'D' : lflag++; + case 'd' : if (lflag) { + if ((l = GETARG(long)) < 0) { + *p++ = '-'; + l = -l; + } /* if */ + + p = ltoa((unsigned long)l, p, 10, 0); + } + else { + if ((i = GETARG(int)) < 0) { + *p++ = '-'; + i = -i; + } /* if */ + + p = itoa((unsigned int)i, p, 10, 0); + } /* else */ + break; +#if 0 + case 'e' : if (!ndfnd) + ndigit = 6; + + ndigit++; + p = ecvt(GETARG(double), ndigit, &decpt, &sign) + ndigit; + break; + + case 'f' : if (!ndfnd) + ndigit = 6; + p = fcvt(GETARG(double), ndigit, &decpt, &sign) + ndigit; + break; + + case 'g' : if (!ndfnd) + ndigit = 6; + p = gcvt(GETARG(double), ndigit, p) + ndigit; + break; +#endif + + case 'c' : zfill = ' '; + *p++ = GETARG(int); + break; + + case 's' : zfill = ' '; + + if ((s = GETARG(char *)) == NULL) + s = nul; + + if (!ndigit) + ndigit = 32767; + + for (p = s; *p && --ndigit >= 0; p++); + + break; + + case 'k' : p = itoa(call[chan].card, p, 10, 0); + break; + + case 't' : p = itoa(call[chan].tei, p, 10, 0); + break; + + case 'C' : p = itoa(call[chan].cref, p, 10, 0); + break; + + case 'B' : p = itoa(chan, p, 10, 0); + break; + + case 'n' : who = ME; + case 'N' : if (!ndigit) + ndigit = 32767; + + if (*fmt) { + switch (*fmt++) { + case '0' : s = call[chan].onum[who]; break; + case '1' : s = call[chan].num[who]; break; + case '2' : s = call[chan].vnum[who]; break; + case '3' : s = call[chan].vorwahl[who]; break; + case '4' : s = call[chan].rufnummer[who]; break; + case '5' : s = call[chan].alias[who]; break; + case '6' : s = call[chan].area[who]; break; + default : s = nul; break; + } /* switch */ + + p = s + strlen(s); + } /* if */ + break; + + case 'I' : switch (chan) { + case 0 : s = ""; p = s; break; + case 1 : s = " "; p = s + 2; break; + default : s = "* "; p = s + 2; break; + } /* switch */ + break; + + case 'a' : s = idate; p = s + 3; + break; + + case 'b' : s = idate + 3; p = s + 3; + break; + + case 'e' : s = idate + 6; p = s + 2; + break; + + case 'T' : s = idate + 8; p = s + 8; + break; + + default : *p++ = c; + break; + } /* switch */ + + i = p - s; + + if ((width -= i) < 0) + width = 0; + + if (!ljust) + width = -width; + + if (width < 0) { + if ((*s == '-') && (zfill == '0')) { + *op++ = *s++; + i--; + } /* if */ + + do + *op++ = zfill; + while (++width); + } /* if */ + + while (--i >= 0) + *op++ = *s++; + + while (width) { + *op++ = zfill; + width--; + } /* while */ + } /* for */ + +} /* iprintf */ + +/****************************************************************************/ + +int print_version(char *myname) +{ + _print_msg("%s Version %s, Copyright (C) 1995, 1996, 1997 Andreas Kool\n",myname,VERSION); + _print_msg("%s comes with ABSOLUTELY NO WARRANTY; for details see COPYING.\n", myname); + _print_msg("This is free software, and you are welcome to redistribute it\n"); + _print_msg("under certain conditions; see COPYING for details.\n"); + return 0; +} + +/****************************************************************************/ + +char *t2tz(int zeit) +{ + switch (zeit) { + case 0 : return("Vormittag"); break; + case 1 : return("Nachmittag"); break; + case 2 : return("Freizeit"); break; + case 3 : return("Mondschein"); break; + case 4 : return("Nacht"); break; + case 5 : return("Standard"); break; + case 6 : return("Spartarif"); break; + case 7 : return("City Weekend"); break; + case 8 : return("City Plus"); break; + case 9 : return("Feiertag"); break; + default : return(""); break; + } /* switch */ +} /* t2tz */ + +/****************************************************************************/ + +char *z2s(int zone) +{ + switch (zone) { + case 1 : return("City"); break; + case 2 : return("R50"); break; + case 3 : return("R200"); break; + case 4 : return("Fern"); break; + case 5 : return("EuroC"); break; + case 6 : return("Vis1"); break; + case 7 : return("Vis2"); break; + case 8 : return("Vis3"); break; + case 9 : return("Welt1"); break; + case 10 : return("Welt2"); break; + case 11 : return("Welt3"); break; + case 12 : return("T-Online"); break; + case 13 : return("KONF"); break; + case 14 : return("Inmar"); break; + case 15 : return("C-Box"); break; + case 16 : return("T-Box"); break; + default : return(""); break; + } /* switch */ +} /* z2s */ + +/****************************************************************************/ diff --git a/isdnlog/tools/tools.h b/isdnlog/tools/tools.h new file mode 100644 index 00000000..ed5188c4 --- /dev/null +++ b/isdnlog/tools/tools.h @@ -0,0 +1,609 @@ +/* $Id: tools.h,v 1.1 1997/03/16 20:59:25 luethje Exp $ + * + * ISDN accounting for isdn4linux. + * + * 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: tools.h,v $ + * Revision 1.1 1997/03/16 20:59:25 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.25 1997/01/17 23:30:43 akool + * City Weekend Tarif implemented (Thanks to Oliver Schoett ) + * + * Revision 2.6.20 1997/01/05 20:05:43 akool + * neue "AreaCode" Release implemented + * + * Revision 2.6.15 1997/01/02 19:51:43 akool + * CHARGEMAX erweitert + * CONNECTMAX implementiert + * + * Revision 2.40 1996/06/19 17:45:43 akool + * double2byte(), time2str() added + * + * Revision 2.3.26 1996/05/05 12:07:43 akool + * known.interface added + * + * Revision 2.3.23 1996/04/28 12:16:43 akool + * confdir() + * + * Revision 2.2.5 1996/03/25 19:17:43 akool + * 1TR6 causes implemented + * + * Revision 2.23 1996/03/24 12:11:43 akool + * Explicit decl. of basename() - new "unistd.h" dont have one + * + * Revision 2.15 1996/02/21 20:14:43 akool + * + * Revision 2.12 1996/02/13 20:08:43 root + * Nu geht's (oder?) + * + * Revision 2.12 1996/02/13 20:08:43 root + * Nu geht's (oder?) + * + * Revision 1.2 1996/02/13 20:05:28 root + * so nun gehts + * + * Revision 1.1 1996/02/13 14:28:14 root + * Initial revision + * + * Revision 2.05 1995/02/11 17:10:16 akool + * + */ + +/****************************************************************************/ + +#ifndef _TOOLS_H_ +#define _TOOLS_H_ + +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef linux +#include +#include +#else +#include +#endif +#ifdef DBMALLOC +#include "dbmalloc.h" +#endif + +/****************************************************************************/ + +#include "policy.h" +#include "libisdn.h" + +/****************************************************************************/ + +#ifndef OLDCONFFILE +# define OLDCONFFILE "isdnlog.conf" +#endif + +#ifndef RELOADCMD +# define RELOADCMD "reload" +#endif + +#ifndef STOPCMD +# define STOPCMD "stop" +#endif + +#ifndef REBOOTCMD +# define REBOOTCMD "/sbin/reboot" +#endif + +/****************************************************************************/ + +#undef min +#undef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define abs(x) (((x) < 0) ? -(x) : (x)) + +/****************************************************************************/ + +#define MAXDIG 128 +#define GETARG(typ) va_arg(ap, typ) + +/****************************************************************************/ + +#define NIL (char **)NULL + +/****************************************************************************/ + +#define NUMSIZE 20 +#define FNSIZE 64 +#define RETSIZE 128 +#define MAXRET 5 +#define MAXZONES 6 +#define MAXCHAN 7 +#define MAXCARDS 2 + +#define DIGITS 17 +#define DEB 1 + +#define MAXUNKNOWN 50 +#define MAXCONNECTS 50 + +/****************************************************************************/ + +#define CALLING 0 +#define CALLED 1 +#define DATETIME 2 + +/****************************************************************************/ + +#define DIALOUT 0 +#define DIALIN 1 + +/****************************************************************************/ + +#define ALERTING 0x01 +#define CALL_PROCEEDING 0x02 +#define SETUP 0x05 +#define SETUP_ACKNOWLEDGE 0x0d +#define SUSPEND 0x25 +#define SUSPEND_ACKNOWLEDGE 0x2d +#define RESUME 0x26 +#define RESUME_ACKNOWLEDGE 0x2e +#define CONNECT 0x07 +#define CONNECT_ACKNOWLEDGE 0x0f +#define FACILITY 0x62 +#define NOTIFY 0x6e +#define STATUS 0x7d +#define MAKEL_ACKNOWLEDGE 0x28 +#define MAKEL_RESUME_ACK 0x33 +#define DISCONNECT 0x45 +#define RELEASE 0x4d +#define RELEASE_COMPLETE 0x5a +#define INFORMATION 0x7b +#define AOCD_1TR6 0x6d + +/****************************************************************************/ + +#define AOC_UNITS 0 +#define AOC_AMOUNT 1 + +/****************************************************************************/ + +#define RING_INCOMING 1 +#define RING_OUTGOING 2 +#define RING_RING 4 +#define RING_CONNECT 8 +#define RING_BUSY 16 +#define RING_AOCD 32 +#define RING_ERROR 64 +#define RING_HANGUP 128 +#define RING_KILL 256 +#define RING_SPEAK 512 +#define RING_PROVIDER 1024 +#define RING_LOOP 2048 +#define RING_UNIQUE 4096 +#define RING_INTERVAL 8192 + +/****************************************************************************/ + +#define STATE_RING 1 /* "Telefonklingeln" ... jemand ruft an, oder man selbst ruft raus */ +#define STATE_CONNECT 2 /* Verbindung */ +#define STATE_HANGUP 3 /* Verbindung beendet */ +#define STATE_AOCD 100 /* Gebuehrenimpuls _waehrend_ der Verbindung */ +#define STATE_CAUSE 101 /* Aussergewoehnliche Cause-Meldungen von der VSt */ +#define STATE_TIME 102 /* Uhrzeit-Meldung von der VSt */ +#define STATE_BYTE 103 /* Durchsatz-Meldung von Frank (Byte/s/B-Kanal) */ +#define STATE_HUPTIMEOUT 104 /* Wechsel des hangup-Timer's */ + +/****************************************************************************/ + +#define AOC_OTHER -999999L + +/****************************************************************************/ + +#define QCMASK 0377 +#define QUOTE 0200 +#define QMASK (QCMASK &~QUOTE) +#define NOT '!' + +#define AVON "avon" +#define INFO "/dev/isdninfo" + +#define BIGBUFSIZ 2048 + +/****************************************************************************/ + +#define VAR_START "START" +#define VAR_MYMSNS "MYMSNS" +#define VAR_MYCOUNTRY "MYAREA" +#define VAR_MYAREA "MYPREFIX" +#define VAR_CURRENCY "CURRENCY" +#define VAR_ILABEL "ILABEL" +#define VAR_OLABEL "OLABEL" +#define VAR_CHARGEMAX "CHARGEMAX" +#define VAR_CONNECTMAX "CONNECTMAX" +#define VAR_BYTEMAX "BYTEMAX" + +/****************************************************************************/ + +#define VERSION_UNKNOWN 0 +#define VERSION_EDSS1 1 +#define VERSION_1TR6 2 + +#define DEF_NUM_MSN 3 + +/****************************************************************************/ + +#define OTHER (call[chan].dialin ? CALLING : CALLED) +#define ME (call[chan].dialin ? CALLED : CALLING) +#define _OTHER(call) (call->dialin ? CALLING : CALLED) +#define _ME(call) (call->dialin ? CALLED : CALLING) + +/****************************************************************************/ + +#define SHORT_STRING_SIZE 256 +#define LONG_STRING_SIZE 1024 +#define BUF_SIZE 4096 + +/****************************************************************************/ + +/* Keywords for parameter file */ + +#define CONF_SEC_OPT "OPTIONS" +#define CONF_ENT_DEV "DEVICE" +#define CONF_ENT_LOG "LOG" +#define CONF_ENT_FLUSH "FLUSH" +#define CONF_ENT_PORT "PORT" +#define CONF_ENT_STDOUT "STDOUT" +#define CONF_ENT_SYSLOG "SYSLOG" +#define CONF_ENT_XISDN "XISDN" +#define CONF_ENT_TIME "TIME" +#define CONF_ENT_CON "CONSOLE" +#define CONF_ENT_START "START" +#define CONF_ENT_THRU "THRUPUT" +#define CONF_ENT_DAEMON "DAEMON" +#define CONF_ENT_PIPE "PIPE" +#define CONF_ENT_BI "BILINGUAL" +#define CONF_ENT_MON "MONITOR" +#define CONF_ENT_HANGUP "HANGUP" +#define CONF_ENT_CALLS "CALLS" +#define CONF_ENT_XLOG "XLOG" +#define CONF_ENT_NL "NEWLINE" +#define CONF_ENT_WIDTH "WIDTH" +#define CONF_ENT_WD "WATCHDOG" +#define CONF_ENT_CW "CITYWEEKEND" +#define CONF_ENT_AMT "AMT" +#define CONF_ENT_DUAL "DUAL" +#define CONF_ENT_Q931 "Q931DUMP" + +/****************************************************************************/ + +/* Keywords for isdn.conf */ + +#define CONF_SEC_ISDNLOG "ISDNLOG" +#define CONF_ENT_CHARGE "CHARGEMAX" +#define CONF_ENT_CONNECT "CONNECTMAX" +#define CONF_ENT_BYTE "BYTEMAX" +#define CONF_ENT_CURR "CURRENCY" +#define CONF_ENT_ILABEL "ILABEL" +#define CONF_ENT_OLABEL "OLABEL" +#define CONF_ENT_RELOAD "RELOADCMD" +#define CONF_ENT_STOP "STOPCMD" +#define CONF_ENT_REBOOT "REBOOTCMD" + +#define CONF_SEC_START "START" +#define CONF_SEC_FLAG "FLAG" +#define CONF_ENT_FLAGS "FLAGS" +#define CONF_ENT_PROG "PROGRAM" +#define CONF_ENT_USER "USER" +#define CONF_ENT_GROUP "GROUP" +#define CONF_ENT_INTVAL "INTERVAL" +#define CONF_ENT_TIME "TIME" + +/****************************************************************************/ + +#define NO_MSN -1 + +#define C_FLAG_DELIM '|' + +/****************************************************************************/ + +#define C_UNKNOWN '?' +#define S_UNKNOWN "UNKNOWN" + +/****************************************************************************/ + +#define S_QUOTES "\\$@;,#" + +/****************************************************************************/ + +#define TYPE_STRING 0 +#define TYPE_MESSAGE 1 +#define TYPE_ELEMENT 2 +#define TYPE_CAUSE 3 +#define TYPE_SERVICE 4 + +/****************************************************************************/ + +typedef struct { + int state; + int cref; + int tei; + int dialin; + int cause; + int aoce; + int traffic; + int channel; + int dialog; + int bearer; + int si1; /* Service Indicator entsprechend i4l convention */ + int si11; /* if (si1 == 1) :: 0 = Telefon analog / 1 = Telefon digital */ + char onum[2][NUMSIZE]; + int screening; + char num[2][NUMSIZE]; + char vnum[2][256]; + char id[32]; + char usage[16]; + int confentry[2]; + time_t time; + time_t connect; + time_t t_duration; + time_t disconnect; + clock_t duration; + int cur_event; + long ibytes; + long obytes; + long libytes; + long lobytes; + double ibps; + double obps; + char areacode[2][NUMSIZE]; + char vorwahl[2][NUMSIZE]; + char rufnummer[2][NUMSIZE]; + char alias[2][NUMSIZE]; + char area[2][128]; + char money[64]; + char currency[32]; + char msg[128]; + int stat; + int version; + int bchan; + double tick; + int chargeint; + int huptimeout; + char service[32]; + double pay; + char digits[NUMSIZE]; + int oc3; + int takteChargeInt; + int aoc; + int card; +} CALL; + +/****************************************************************************/ + +typedef struct { + int flag; + char *time; + char *infoarg; + int interval; + char *user; + char *group; +/* char *service; */ +} info_args; + +/****************************************************************************/ + +typedef struct { + char *num; + char *who; + int zone; + int flags; + int si; + char *interface; + info_args **infoargs; + /* above from "isdnlog.conf" */ + int usage[2]; + double dur[2]; + int eh; + double dm; + double charge; + double rcharge; + double scharge; + int day; + int month; + double online; + double sonline; + double bytes; + double sbytes; +} KNOWN; + +/****************************************************************************/ + +typedef struct { + int in; + int out; + int eh; + int err; + double din; + double dout; + double dm; + long ibytes; + long obytes; +} sum_calls; + +/****************************************************************************/ + +typedef struct { + int eh; + int cause; + time_t t; + int dir; + double duration; + double dm; + char num[2][NUMSIZE]; + long ibytes; + long obytes; + double version; + int si; + int si1; + double currency_factor; + char currency[32]; + double pay; +} one_call; + +/****************************************************************************/ + +typedef struct { + unsigned long i; + unsigned long o; +} IO; + +/****************************************************************************/ + +typedef struct { + char id[20]; + int ch; + int dr; + int u; + int f; + char n[20]; +} IFO; + +/****************************************************************************/ + +PUBLIC KNOWN start_procs; +PUBLIC KNOWN **known; +PUBLIC int mymsns; +PUBLIC int knowns; +PUBLIC int currency_mode; +PUBLIC double currency_factor; +PUBLIC double chargemax; +PUBLIC double connectmax; +PUBLIC double bytemax; +PUBLIC int connectmaxmode; +PUBLIC int bytemaxmode; +PUBLIC char *currency; +PUBLIC int day; +PUBLIC int month; +PUBLIC int retnum; +PUBLIC int ln; +PUBLIC char retstr[MAXRET + 1][RETSIZE]; +PUBLIC char Months[][4]; +PUBLIC time_t cur_time; +PUBLIC section *conf_dat; +PUBLIC char ilabel[256]; +PUBLIC char olabel[256]; +PUBLIC char idate[256]; +PUBLIC CALL call[MAXCHAN]; +PUBLIC int use_new_config; +#ifdef Q931 +PUBLIC int q931dmp; +#endif +PUBLIC int CityWeekend; +PUBLIC int dual; +PUBLIC char mlabel[BUFSIZ]; +PUBLIC char amtsholung[NUMSIZE]; + +/****************************************************************************/ + +extern int optind, errno; +extern char *optarg; + +/****************************************************************************/ + +#ifdef _TOOLS_C_ +#define _EXTERN + +_EXTERN char* reloadcmd = RELOADCMD; +_EXTERN char* stopcmd = STOPCMD; +_EXTERN char* rebootcmd = REBOOTCMD; +_EXTERN int (*_print_msg)(const char *, ...) = printf; + +#else +#define _EXTERN extern + +_EXTERN char* reloadcmd; +_EXTERN char* stopcmd; +_EXTERN char* rebootcmd; +_EXTERN int (*_print_msg)(const char *, ...); + +#endif + +_EXTERN void set_print_fct_for_tools(int (*new_print_msg)(const char *, ...)); +_EXTERN int print_version(char *myname); +_EXTERN time_t atom(register char *p); +_EXTERN char *num2nam(char *num, int si); +_EXTERN char *double2str(double n, int l, int d, int flags); +_EXTERN char *double2byte(double bytes); +_EXTERN char *time2str(time_t sec); +_EXTERN char *double2clock(double n); +_EXTERN char *vnum(int chan, int who); +_EXTERN char *i2a(int n, int l, int base); +_EXTERN int iprintf(char *obuf, int chan, register char *fmt, ...); +_EXTERN char *qmsg(int type, int version, int val); +_EXTERN char *Myname; + +#undef _EXTERN + +/****************************************************************************/ + +#ifdef _ISDNCONF_C_ +#define _EXTERN +#else +#define _EXTERN extern +#endif + +_EXTERN int readconfig(char *myname); +_EXTERN void setDefaults(void); +_EXTERN void discardconfig(void); +_EXTERN char *t2tz(int zeit); +_EXTERN char *z2s(int zone); +_EXTERN section *read_isdnconf(section **_conf_dat); + +#undef _EXTERN + +/****************************************************************************/ + +#endif /* _TOOLS_H_ */ +