isdn4k-utils/isdnlog/isdnlog/server.c

733 lines
18 KiB
C

/* $Id: server.c,v 1.2 1997/04/03 22:34:51 luethje Exp $
*
* 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.
*
* $Log: server.c,v $
* Revision 1.2 1997/04/03 22:34:51 luethje
* splitt the files callerid.conf and ~/.isdn.
*
*/
/****************************************************************************/
#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;
}
/****************************************************************************/