/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2005 by Alexander Barton (alex@barton.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
#include "portab.h"
-static char UNUSED id[] = "$Id: client.c,v 1.78 2005/03/19 18:43:48 fw Exp $";
+static char UNUSED id[] = "$Id: client.c,v 1.97 2007/11/21 12:16:36 alex Exp $";
#include "imp.h"
#include <assert.h>
#include <strings.h>
#include <netdb.h>
+#include "defines.h"
#include "conn.h"
#include "exp.h"
#define GETID_LEN (CLIENT_NICK_LEN-1) + 1 + (CLIENT_USER_LEN-1) + 1 + (CLIENT_HOST_LEN-1) + 1
-LOCAL CLIENT *This_Server, *My_Clients;
-LOCAL char GetID_Buffer[GETID_LEN];
+static CLIENT *This_Server, *My_Clients;
+static char GetID_Buffer[GETID_LEN];
+static WHOWAS My_Whowas[MAX_WHOWAS];
+static int Last_Whowas = -1;
-LOCAL long Count PARAMS(( CLIENT_TYPE Type ));
-LOCAL long MyCount PARAMS(( CLIENT_TYPE Type ));
-LOCAL CLIENT *New_Client_Struct PARAMS(( void ));
-LOCAL void Generate_MyToken PARAMS(( CLIENT *Client ));
-LOCAL void Adjust_Counters PARAMS(( CLIENT *Client ));
+static unsigned long Count PARAMS(( CLIENT_TYPE Type ));
+static unsigned long MyCount PARAMS(( CLIENT_TYPE Type ));
-#ifndef Client_DestroyNow
-GLOBAL void Client_DestroyNow PARAMS((CLIENT *Client ));
-#endif
+static CLIENT *New_Client_Struct PARAMS(( void ));
+static void Generate_MyToken PARAMS(( CLIENT *Client ));
+static void Adjust_Counters PARAMS(( CLIENT *Client ));
+
+static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer,
+ CLIENT *TopServer, int Type, char *ID, char *User, char *Hostname,
+ char *Info, int Hops, int Token, char *Modes, bool Idented));
long Max_Users = 0, My_Max_Users = 0;
This_Server->hops = 0;
gethostname( This_Server->host, CLIENT_HOST_LEN );
- h = gethostbyname( This_Server->host );
- if( h ) strlcpy( This_Server->host, h->h_name, sizeof( This_Server->host ));
-
+ if (!Conf_NoDNS) {
+ h = gethostbyname( This_Server->host );
+ if (h) strlcpy(This_Server->host, h->h_name, sizeof(This_Server->host));
+ }
Client_SetID( This_Server, Conf_ServerName );
Client_SetInfo( This_Server, Conf_ServerInfo );
My_Clients = This_Server;
+
+ memset( &My_Whowas, 0, sizeof( My_Whowas ));
} /* Client_Init */
} /* Client_ThisServer */
+/**
+ * Initialize new local client; wrapper function for Init_New_Client().
+ * @return New CLIENT structure.
+ */
GLOBAL CLIENT *
-Client_NewLocal( CONN_ID Idx, char *Hostname, int Type, bool Idented )
+Client_NewLocal(CONN_ID Idx, char *Hostname, int Type, bool Idented)
{
- /* Neuen lokalen Client erzeugen: Wrapper-Funktion fuer Client_New(). */
- return Client_New( Idx, This_Server, NULL, Type, NULL, NULL, Hostname, NULL, 0, 0, NULL, Idented );
+ return Init_New_Client(Idx, This_Server, NULL, Type, NULL, NULL,
+ Hostname, NULL, 0, 0, NULL, Idented);
} /* Client_NewLocal */
+/**
+ * Initialize new remote server; wrapper function for Init_New_Client().
+ * @return New CLIENT structure.
+ */
GLOBAL CLIENT *
-Client_NewRemoteServer( CLIENT *Introducer, char *Hostname, CLIENT *TopServer, int Hops, int Token, char *Info, bool Idented )
+Client_NewRemoteServer(CLIENT *Introducer, char *Hostname, CLIENT *TopServer,
+ int Hops, int Token, char *Info, bool Idented)
{
- /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
- return Client_New( NONE, Introducer, TopServer, CLIENT_SERVER, Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented );
+ return Init_New_Client(NONE, Introducer, TopServer, CLIENT_SERVER,
+ Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented);
} /* Client_NewRemoteServer */
+/**
+ * Initialize new remote client; wrapper function for Init_New_Client().
+ * @return New CLIENT structure.
+ */
GLOBAL CLIENT *
-Client_NewRemoteUser( CLIENT *Introducer, char *Nick, int Hops, char *User, char *Hostname, int Token, char *Modes, char *Info, bool Idented )
+Client_NewRemoteUser(CLIENT *Introducer, char *Nick, int Hops, char *User,
+ char *Hostname, int Token, char *Modes, char *Info, bool Idented)
{
- /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
- return Client_New( NONE, Introducer, NULL, CLIENT_USER, Nick, User, Hostname, Info, Hops, Token, Modes, Idented );
+ return Init_New_Client(NONE, Introducer, NULL, CLIENT_USER, Nick,
+ User, Hostname, Info, Hops, Token, Modes, Idented);
} /* Client_NewRemoteUser */
-GLOBAL CLIENT *
-Client_New( CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer, int Type, char *ID, char *User, char *Hostname, char *Info, int Hops, int Token, char *Modes, bool Idented )
+/**
+ * Initialize new client and set up the given parameters like client type,
+ * user name, host name, introducing server etc. ...
+ * @return New CLIENT structure.
+ */
+static CLIENT *
+Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer,
+ int Type, char *ID, char *User, char *Hostname, char *Info, int Hops,
+ int Token, char *Modes, bool Idented)
{
CLIENT *client;
if( ! client ) return NULL;
/* Initialisieren */
+ client->starttime = time(NULL);
client->conn_id = Idx;
client->introducer = Introducer;
client->topserver = TopServer;
if( Modes ) Client_SetModes( client, Modes );
if( Type == CLIENT_SERVER ) Generate_MyToken( client );
- /* ist der User away? */
- if( strchr( client->modes, 'a' )) strlcpy( client->away, DEFAULT_AWAY_MSG, sizeof( client->away ));
+ if( strchr( client->modes, 'a' ))
+ strlcpy( client->away, DEFAULT_AWAY_MSG, sizeof( client->away ));
/* Verketten */
client->next = (POINTER *)My_Clients;
Adjust_Counters( client );
return client;
-} /* Client_New */
+} /* Init_New_Client */
GLOBAL void
if( ! txt ) txt = "Reason unknown.";
/* Netz-Split-Nachricht vorbereiten (noch nicht optimal) */
- if( Client->type == CLIENT_SERVER ) snprintf( msg, sizeof( msg ), "%s: lost server %s", This_Server->id, Client->id );
+ if( Client->type == CLIENT_SERVER ) {
+ strlcpy(msg, This_Server->id, sizeof (msg));
+ strlcat(msg, " ", sizeof (msg));
+ strlcat(msg, Client->id, sizeof (msg));
+ }
last = NULL;
c = My_Clients;
else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :" );
}
}
+
+ /* Unregister client from channels */
Channel_Quit( c, FwdMsg ? FwdMsg : c->id );
+
+ /* Register client in My_Whowas structure */
+ Client_RegisterWhowas( c );
}
else if( c->type == CLIENT_SERVER )
{
{
if( c->id[0] ) Log( LOG_NOTICE, "Client \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
else Log( LOG_NOTICE, "Client unregistered (connection %d): %s", c->conn_id, txt );
- }
- else
- {
- if( c->id[0] ) Log( LOG_WARNING, "Unregistered unknown client \"%s\": %s", c->id, txt );
- else Log( LOG_WARNING, "Unregistered unknown client: %s", c->id, txt );
+ } else {
+ Log(LOG_WARNING, "Unregistered unknown client \"%s\": %s",
+ c->id[0] ? c->id : "(No Nick)", txt );
}
}
} /* Client_Destroy */
-GLOBAL void
-Client_DestroyNow( CLIENT *Client )
-{
- /* Destroy client structure immediately. This function is only
- * intended for the connection layer to remove client structures
- * of connections that can't be established! */
-
- CLIENT *last, *c;
-
- assert( Client != NULL );
-
- last = NULL;
- c = My_Clients;
- while( c )
- {
- if( c == Client )
- {
- /* Wir haben den Client gefunden: entfernen */
- if( last ) last->next = c->next;
- else My_Clients = (CLIENT *)c->next;
- free( c );
- break;
- }
- last = c;
- c = (CLIENT *)c->next;
- }
-} /* Client_DestroyNow */
-
-
GLOBAL void
Client_SetHostname( CLIENT *Client, char *Hostname )
{
/* Hostname eines Clients setzen */
-
+
assert( Client != NULL );
assert( Hostname != NULL );
-
+
strlcpy( Client->host, Hostname, sizeof( Client->host ));
} /* Client_SetHostname */
assert( Client != NULL );
assert( User != NULL );
-
+
if( Idented ) strlcpy( Client->user, User, sizeof( Client->user ));
else
{
assert( Client != NULL );
assert( Info != NULL );
-
+
strlcpy( Client->info, Info, sizeof( Client->info ));
} /* Client_SetInfo */
assert( Client != NULL );
assert( Pwd != NULL );
-
+
strlcpy( Client->pwd, Pwd, sizeof( Client->pwd ));
} /* Client_SetPassword */
*/
char x[2];
-
+
assert( Client != NULL );
x[0] = Mode; x[1] = '\0';
} /* Client_ModeDel */
-GLOBAL CLIENT *
-Client_GetFromConn( CONN_ID Idx )
-{
- /* return Client-Structure that belongs to the local Connection Idx gehoert.
- * If none is found, return NULL.
- */
-
- CLIENT *c;
-
- assert( Idx >= 0 );
-
- c = My_Clients;
- while( c )
- {
- if( c->conn_id == Idx ) return c;
- c = (CLIENT *)c->next;
- }
- return NULL;
-} /* Client_GetFromConn */
-
-
GLOBAL CLIENT *
Client_Search( char *Nick )
{
assert( Client != NULL );
#ifdef DEBUG
- if( Client->type == CLIENT_USER ) assert( strlen( Client->id ) < CLIENT_NICK_LEN );
+ if(Client->type == CLIENT_USER)
+ assert(strlen(Client->id) < Conf_MaxNickLength);
#endif
if( Client->id[0] ) return Client->id;
Client_User( CLIENT *Client )
{
assert( Client != NULL );
- if( Client->user[0] ) return Client->user;
- else return "~";
+ return Client->user[0] ? Client->user : "~";
} /* Client_User */
Client_NextHop( CLIENT *Client )
{
CLIENT *c;
-
+
assert( Client != NULL );
c = Client;
- while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server )) c = c->introducer;
+ while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server ))
+ c = c->introducer;
+
return c;
} /* Client_NextHop */
* Prefixe benoetigt wird. */
assert( Client != NULL );
-
+
if( Client->type == CLIENT_SERVER ) return Client->id;
snprintf( GetID_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user, Client->host );
GLOBAL bool
Client_CheckNick( CLIENT *Client, char *Nick )
{
- /* Nick ueberpruefen */
-
assert( Client != NULL );
assert( Nick != NULL );
-
- /* Nick ungueltig? */
+
if( ! Client_IsValidNick( Nick ))
{
IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
} /* Client_MyServiceCount */
-GLOBAL long
+GLOBAL unsigned long
Client_MyServerCount( void )
{
CLIENT *c;
- long cnt;
+ unsigned long cnt = 0;
- cnt = 0;
c = My_Clients;
while( c )
{
} /* Client_MyServerCount */
-GLOBAL long
+GLOBAL unsigned long
Client_OperCount( void )
{
CLIENT *c;
- long cnt;
+ unsigned long cnt = 0;
- cnt = 0;
c = My_Clients;
while( c )
{
} /* Client_OperCount */
-GLOBAL long
+GLOBAL unsigned long
Client_UnknownCount( void )
{
CLIENT *c;
- long cnt;
+ unsigned long cnt = 0;
- cnt = 0;
c = My_Clients;
while( c )
{
if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
c = (CLIENT *)c->next;
}
+
return cnt;
} /* Client_UnknownCount */
GLOBAL bool
-Client_IsValidNick( char *Nick )
+Client_IsValidNick( const char *Nick )
{
- /* Ist der Nick gueltig? */
+ const char *ptr;
+ static const char goodchars[] = ";0123456789-";
- char *ptr, goodchars[20];
-
assert( Nick != NULL );
- strcpy( goodchars, ";0123456789-" );
-
if( Nick[0] == '#' ) return false;
if( strchr( goodchars, Nick[0] )) return false;
- if( strlen( Nick ) >= CLIENT_NICK_LEN ) return false;
+ if( strlen( Nick ) >= Conf_MaxNickLength) return false;
ptr = Nick;
while( *ptr )
{
- if(( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return false;
- if(( *ptr > '}' ) && ( ! strchr( goodchars, *ptr ))) return false;
+ if (( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return false;
+ if ( *ptr > '}' ) return false;
ptr++;
}
-
+
return true;
} /* Client_IsValidNick */
-LOCAL long
+/**
+ * Return pointer to "My_Whowas" structure.
+ */
+GLOBAL WHOWAS *
+Client_GetWhowas( void )
+{
+ return My_Whowas;
+} /* Client_GetWhowas */
+
+/**
+ * Return the index of the last used WHOWAS entry.
+ */
+GLOBAL int
+Client_GetLastWhowasIndex( void )
+{
+ return Last_Whowas;
+} /* Client_GetLastWhowasIndex */
+
+
+/**
+ * Get the start time of this client.
+ * The result is the start time in seconds since 1970-01-01, as reported
+ * by the C function time(NULL).
+ */
+GLOBAL time_t
+Client_StartTime(CLIENT *Client)
+{
+ assert( Client != NULL );
+ return Client->starttime;
+} /* Client_Uptime */
+
+
+static unsigned long
Count( CLIENT_TYPE Type )
{
CLIENT *c;
- long cnt;
+ unsigned long cnt = 0;
- cnt = 0;
c = My_Clients;
while( c )
{
} /* Count */
-LOCAL long
+static unsigned long
MyCount( CLIENT_TYPE Type )
{
CLIENT *c;
- long cnt;
+ unsigned long cnt = 0;
- cnt = 0;
c = My_Clients;
while( c )
{
} /* MyCount */
-LOCAL CLIENT *
+static CLIENT *
New_Client_Struct( void )
{
/* Neue CLIENT-Struktur pre-initialisieren */
-
+
CLIENT *c;
-
+
c = (CLIENT *)malloc( sizeof( CLIENT ));
if( ! c )
{
} /* New_Client */
-LOCAL void
+static void
Generate_MyToken( CLIENT *Client )
{
CLIENT *c;
} /* Generate_MyToken */
-LOCAL void
+static void
Adjust_Counters( CLIENT *Client )
{
long count;
assert( Client != NULL );
if( Client->type != CLIENT_USER ) return;
-
+
if( Client->conn_id != NONE )
{
/* Local connection */
} /* Adjust_Counters */
+/**
+ * Register client in My_Whowas structure for further recall by WHOWAS.
+ * Note: Only clients that have been connected at least 30 seconds will be
+ * registered to prevent automated IRC bots to "destroy" a nice server
+ * history database.
+ */
+GLOBAL void
+Client_RegisterWhowas( CLIENT *Client )
+{
+ int slot;
+ time_t now;
+
+ assert( Client != NULL );
+
+ now = time(NULL);
+ /* Don't register clients that were connected less than 30 seconds. */
+ if( now - Client->starttime < 30 )
+ return;
+
+ slot = Last_Whowas + 1;
+ if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
+
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
+#endif
+
+ My_Whowas[slot].time = now;
+ strlcpy( My_Whowas[slot].id, Client_ID( Client ),
+ sizeof( My_Whowas[slot].id ));
+ strlcpy( My_Whowas[slot].user, Client_User( Client ),
+ sizeof( My_Whowas[slot].user ));
+ strlcpy( My_Whowas[slot].host, Client_Hostname( Client ),
+ sizeof( My_Whowas[slot].host ));
+ strlcpy( My_Whowas[slot].info, Client_Info( Client ),
+ sizeof( My_Whowas[slot].info ));
+ strlcpy( My_Whowas[slot].server, Client_ID( Client_Introducer( Client )),
+ sizeof( My_Whowas[slot].server ));
+
+ Last_Whowas = slot;
+} /* Client_RegisterWhowas */
+
+
/* -eof- */