]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/client.c
Client_New() not used outside client.c -> static
[ngircd-alex.git] / src / ngircd / client.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2005 by Alexander Barton (alex@barton.de)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * Please read the file COPYING, README and AUTHORS for more information.
10  *
11  * Client management.
12  */
13
14
15 #define __client_c__
16
17
18 #include "portab.h"
19
20 static char UNUSED id[] = "$Id: client.c,v 1.86 2006/03/10 20:25:29 fw Exp $";
21
22 #include "imp.h"
23 #include <assert.h>
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <netdb.h>
30
31 #include "defines.h"
32 #include "conn.h"
33
34 #include "exp.h"
35 #include "client.h"
36
37 #include <imp.h>
38 #include "ngircd.h"
39 #include "channel.h"
40 #include "resolve.h"
41 #include "conf.h"
42 #include "hash.h"
43 #include "irc-write.h"
44 #include "log.h"
45 #include "messages.h"
46
47 #include <exp.h>
48
49
50 #define GETID_LEN (CLIENT_NICK_LEN-1) + 1 + (CLIENT_USER_LEN-1) + 1 + (CLIENT_HOST_LEN-1) + 1
51
52
53 static CLIENT *This_Server, *My_Clients;
54 static char GetID_Buffer[GETID_LEN];
55
56 static WHOWAS My_Whowas[MAX_WHOWAS];
57 static int Last_Whowas = -1;
58
59
60 static long Count PARAMS(( CLIENT_TYPE Type ));
61 static long MyCount PARAMS(( CLIENT_TYPE Type ));
62
63 static CLIENT *New_Client_Struct PARAMS(( void ));
64 static void Generate_MyToken PARAMS(( CLIENT *Client ));
65 static void Adjust_Counters PARAMS(( CLIENT *Client ));
66
67 #ifndef Client_DestroyNow
68 GLOBAL void Client_DestroyNow PARAMS((CLIENT *Client ));
69 #endif
70
71
72 long Max_Users = 0, My_Max_Users = 0;
73
74
75 GLOBAL void
76 Client_Init( void )
77 {
78         struct hostent *h;
79         
80         This_Server = New_Client_Struct( );
81         if( ! This_Server )
82         {
83                 Log( LOG_EMERG, "Can't allocate client structure for server! Going down." );
84                 Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
85                 exit( 1 );
86         }
87
88         /* Client-Struktur dieses Servers */
89         This_Server->next = NULL;
90         This_Server->type = CLIENT_SERVER;
91         This_Server->conn_id = NONE;
92         This_Server->introducer = This_Server;
93         This_Server->mytoken = 1;
94         This_Server->hops = 0;
95
96         gethostname( This_Server->host, CLIENT_HOST_LEN );
97         h = gethostbyname( This_Server->host );
98         if( h ) strlcpy( This_Server->host, h->h_name, sizeof( This_Server->host ));
99
100         Client_SetID( This_Server, Conf_ServerName );
101         Client_SetInfo( This_Server, Conf_ServerInfo );
102
103         My_Clients = This_Server;
104         
105         memset( &My_Whowas, 0, sizeof( My_Whowas ));
106 } /* Client_Init */
107
108
109 GLOBAL void
110 Client_Exit( void )
111 {
112         CLIENT *c, *next;
113         int cnt;
114
115         if( NGIRCd_SignalRestart ) Client_Destroy( This_Server, "Server going down (restarting).", NULL, false );
116         else Client_Destroy( This_Server, "Server going down.", NULL, false );
117         
118         cnt = 0;
119         c = My_Clients;
120         while( c )
121         {
122                 cnt++;
123                 next = (CLIENT *)c->next;
124                 free( c );
125                 c = next;
126         }
127         if( cnt ) Log( LOG_INFO, "Freed %d client structure%s.", cnt, cnt == 1 ? "" : "s" );
128 } /* Client_Exit */
129
130
131 GLOBAL CLIENT *
132 Client_ThisServer( void )
133 {
134         return This_Server;
135 } /* Client_ThisServer */
136
137
138 GLOBAL CLIENT *
139 Client_NewLocal( CONN_ID Idx, char *Hostname, int Type, bool Idented )
140 {
141         /* Neuen lokalen Client erzeugen: Wrapper-Funktion fuer Client_New(). */
142         return Client_New( Idx, This_Server, NULL, Type, NULL, NULL, Hostname, NULL, 0, 0, NULL, Idented );
143 } /* Client_NewLocal */
144
145
146 GLOBAL CLIENT *
147 Client_NewRemoteServer( CLIENT *Introducer, char *Hostname, CLIENT *TopServer, int Hops, int Token, char *Info, bool Idented )
148 {
149         /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
150         return Client_New( NONE, Introducer, TopServer, CLIENT_SERVER, Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented );
151 } /* Client_NewRemoteServer */
152
153
154 GLOBAL CLIENT *
155 Client_NewRemoteUser( CLIENT *Introducer, char *Nick, int Hops, char *User, char *Hostname, int Token, char *Modes, char *Info, bool Idented )
156 {
157         /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
158         return Client_New( NONE, Introducer, NULL, CLIENT_USER, Nick, User, Hostname, Info, Hops, Token, Modes, Idented );
159 } /* Client_NewRemoteUser */
160
161
162 static CLIENT *
163 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 )
164 {
165         CLIENT *client;
166
167         assert( Idx >= NONE );
168         assert( Introducer != NULL );
169         assert( Hostname != NULL );
170
171         client = New_Client_Struct( );
172         if( ! client ) return NULL;
173
174         /* Initialisieren */
175         client->starttime = time(NULL);
176         client->conn_id = Idx;
177         client->introducer = Introducer;
178         client->topserver = TopServer;
179         client->type = Type;
180         if( ID ) Client_SetID( client, ID );
181         if( User ) Client_SetUser( client, User, Idented );
182         if( Hostname ) Client_SetHostname( client, Hostname );
183         if( Info ) Client_SetInfo( client, Info );
184         client->hops = Hops;
185         client->token = Token;
186         if( Modes ) Client_SetModes( client, Modes );
187         if( Type == CLIENT_SERVER ) Generate_MyToken( client );
188
189         /* ist der User away? */
190         if( strchr( client->modes, 'a' )) strlcpy( client->away, DEFAULT_AWAY_MSG, sizeof( client->away ));
191
192         /* Verketten */
193         client->next = (POINTER *)My_Clients;
194         My_Clients = client;
195
196         /* Adjust counters */
197         Adjust_Counters( client );
198
199         return client;
200 } /* Client_New */
201
202
203 GLOBAL void
204 Client_Destroy( CLIENT *Client, char *LogMsg, char *FwdMsg, bool SendQuit )
205 {
206         /* Client entfernen. */
207         
208         CLIENT *last, *c;
209         char msg[LINE_LEN], *txt;
210
211         assert( Client != NULL );
212
213         if( LogMsg ) txt = LogMsg;
214         else txt = FwdMsg;
215         if( ! txt ) txt = "Reason unknown.";
216
217         /* Netz-Split-Nachricht vorbereiten (noch nicht optimal) */
218         if( Client->type == CLIENT_SERVER ) {
219                 strlcpy(msg, This_Server->id, sizeof (msg));
220                 strlcat(msg, " ", sizeof (msg));
221                 strlcat(msg, Client->id, sizeof (msg));
222         }
223
224         last = NULL;
225         c = My_Clients;
226         while( c )
227         {
228                 if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
229                 {
230                         /* der Client, der geloescht wird ist ein Server. Der Client, den wir gerade
231                          * pruefen, ist ein Child von diesem und muss daher auch entfernt werden */
232                         Client_Destroy( c, NULL, msg, false );
233                         last = NULL;
234                         c = My_Clients;
235                         continue;
236                 }
237                 if( c == Client )
238                 {
239                         /* Wir haben den Client gefunden: entfernen */
240                         if( last ) last->next = c->next;
241                         else My_Clients = (CLIENT *)c->next;
242
243                         if( c->type == CLIENT_USER )
244                         {
245                                 if( c->conn_id != NONE )
246                                 {
247                                         /* Ein lokaler User */
248                                         Log( LOG_NOTICE, "User \"%s\" unregistered (connection %d): %s", Client_Mask( c ), c->conn_id, txt );
249
250                                         if( SendQuit )
251                                         {
252                                                 /* Alle andere Server informieren! */
253                                                 if( FwdMsg ) IRC_WriteStrServersPrefix( NULL, c, "QUIT :%s", FwdMsg );
254                                                 else IRC_WriteStrServersPrefix( NULL, c, "QUIT :" );
255                                         }
256                                 }
257                                 else
258                                 {
259                                         /* Remote User */
260                                         Log( LOG_DEBUG, "User \"%s\" unregistered: %s", Client_Mask( c ), txt );
261
262                                         if( SendQuit )
263                                         {
264                                                 /* Andere Server informieren, ausser denen, die "in
265                                                  * Richtung dem liegen", auf dem der User registriert
266                                                  * ist. Von denen haben wir das QUIT ja wohl bekommen. */
267                                                 if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :%s", FwdMsg );
268                                                 else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :" );
269                                         }
270                                 }
271
272                                 /* Unregister client from channels */
273                                 Channel_Quit( c, FwdMsg ? FwdMsg : c->id );
274                                 
275                                 /* Register client in My_Whowas structure */
276                                 Client_RegisterWhowas( c );
277                         }
278                         else if( c->type == CLIENT_SERVER )
279                         {
280                                 if( c != This_Server )
281                                 {
282                                         if( c->conn_id != NONE ) Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
283                                         else Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" unregistered: %s", c->id, txt );
284                                 }
285
286                                 /* andere Server informieren */
287                                 if( ! NGIRCd_SignalQuit )
288                                 {
289                                         if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
290                                         else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :", c->id );
291                                 }
292                         }
293                         else
294                         {
295                                 if( c->conn_id != NONE )
296                                 {
297                                         if( c->id[0] ) Log( LOG_NOTICE, "Client \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
298                                         else Log( LOG_NOTICE, "Client unregistered (connection %d): %s", c->conn_id, txt );
299                                 }
300                                 else
301                                 {
302                                         if( c->id[0] ) Log( LOG_WARNING, "Unregistered unknown client \"%s\": %s", c->id, txt );
303                                         else Log( LOG_WARNING, "Unregistered unknown client: %s", c->id, txt );
304                                 }
305                         }
306
307                         free( c );
308                         break;
309                 }
310                 last = c;
311                 c = (CLIENT *)c->next;
312         }
313 } /* Client_Destroy */
314
315
316 GLOBAL void
317 Client_DestroyNow( CLIENT *Client )
318 {
319         /* Destroy client structure immediately. This function is only
320          * intended for the connection layer to remove client structures
321          * of connections that can't be established! */
322
323         CLIENT *last, *c;
324
325         assert( Client != NULL );
326
327         last = NULL;
328         c = My_Clients;
329         while( c )
330         {
331                 if( c == Client )
332                 {
333                         /* Wir haben den Client gefunden: entfernen */
334                         if( last ) last->next = c->next;
335                         else My_Clients = (CLIENT *)c->next;
336                         free( c );
337                         break;
338                 }
339                 last = c;
340                 c = (CLIENT *)c->next;
341         }
342 } /* Client_DestroyNow */
343
344
345 GLOBAL void
346 Client_SetHostname( CLIENT *Client, char *Hostname )
347 {
348         /* Hostname eines Clients setzen */
349         
350         assert( Client != NULL );
351         assert( Hostname != NULL );
352         
353         strlcpy( Client->host, Hostname, sizeof( Client->host ));
354 } /* Client_SetHostname */
355
356
357 GLOBAL void
358 Client_SetID( CLIENT *Client, char *ID )
359 {
360         /* Hostname eines Clients setzen, Hash-Wert berechnen */
361
362         assert( Client != NULL );
363         assert( ID != NULL );
364         
365         strlcpy( Client->id, ID, sizeof( Client->id ));
366
367         /* Hash */
368         Client->hash = Hash( Client->id );
369 } /* Client_SetID */
370
371
372 GLOBAL void
373 Client_SetUser( CLIENT *Client, char *User, bool Idented )
374 {
375         /* Username eines Clients setzen */
376
377         assert( Client != NULL );
378         assert( User != NULL );
379         
380         if( Idented ) strlcpy( Client->user, User, sizeof( Client->user ));
381         else
382         {
383                 Client->user[0] = '~';
384                 strlcpy( Client->user + 1, User, sizeof( Client->user ) - 1 );
385         }
386 } /* Client_SetUser */
387
388
389 GLOBAL void
390 Client_SetInfo( CLIENT *Client, char *Info )
391 {
392         /* Hostname eines Clients setzen */
393
394         assert( Client != NULL );
395         assert( Info != NULL );
396         
397         strlcpy( Client->info, Info, sizeof( Client->info ));
398 } /* Client_SetInfo */
399
400
401 GLOBAL void
402 Client_SetModes( CLIENT *Client, char *Modes )
403 {
404         /* Modes eines Clients setzen */
405
406         assert( Client != NULL );
407         assert( Modes != NULL );
408
409         strlcpy( Client->modes, Modes, sizeof( Client->modes ));
410 } /* Client_SetModes */
411
412
413 GLOBAL void
414 Client_SetFlags( CLIENT *Client, char *Flags )
415 {
416         /* Flags eines Clients setzen */
417
418         assert( Client != NULL );
419         assert( Flags != NULL );
420
421         strlcpy( Client->flags, Flags, sizeof( Client->flags ));
422 } /* Client_SetFlags */
423
424
425 GLOBAL void
426 Client_SetPassword( CLIENT *Client, char *Pwd )
427 {
428         /* Von einem Client geliefertes Passwort */
429
430         assert( Client != NULL );
431         assert( Pwd != NULL );
432         
433         strlcpy( Client->pwd, Pwd, sizeof( Client->pwd ));
434 } /* Client_SetPassword */
435
436
437 GLOBAL void
438 Client_SetAway( CLIENT *Client, char *Txt )
439 {
440         /* Set AWAY reason of client */
441
442         assert( Client != NULL );
443         assert( Txt != NULL );
444
445         strlcpy( Client->away, Txt, sizeof( Client->away ));
446         Log( LOG_DEBUG, "User \"%s\" is away: %s", Client_Mask( Client ), Txt );
447 } /* Client_SetAway */
448
449
450 GLOBAL void
451 Client_SetType( CLIENT *Client, int Type )
452 {
453         assert( Client != NULL );
454         Client->type = Type;
455         if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
456         Adjust_Counters( Client );
457 } /* Client_SetType */
458
459
460 GLOBAL void
461 Client_SetHops( CLIENT *Client, int Hops )
462 {
463         assert( Client != NULL );
464         Client->hops = Hops;
465 } /* Client_SetHops */
466
467
468 GLOBAL void
469 Client_SetToken( CLIENT *Client, int Token )
470 {
471         assert( Client != NULL );
472         Client->token = Token;
473 } /* Client_SetToken */
474
475
476 GLOBAL void
477 Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
478 {
479         assert( Client != NULL );
480         assert( Introducer != NULL );
481         Client->introducer = Introducer;
482 } /* Client_SetIntroducer */
483
484
485 GLOBAL void
486 Client_SetOperByMe( CLIENT *Client, bool OperByMe )
487 {
488         assert( Client != NULL );
489         Client->oper_by_me = OperByMe;
490 } /* Client_SetOperByMe */
491
492
493 GLOBAL bool
494 Client_ModeAdd( CLIENT *Client, char Mode )
495 {
496         /* Set Mode.
497          * If Client already alread had Mode, return false.
498          * If the Mode was newly set, return true.
499          */
500
501         char x[2];
502         
503         assert( Client != NULL );
504
505         x[0] = Mode; x[1] = '\0';
506         if( ! strchr( Client->modes, x[0] ))
507         {
508                 /* Client hat den Mode noch nicht -> setzen */
509                 strlcat( Client->modes, x, sizeof( Client->modes ));
510                 return true;
511         }
512         else return false;
513 } /* Client_ModeAdd */
514
515
516 GLOBAL bool
517 Client_ModeDel( CLIENT *Client, char Mode )
518 {
519         /* Delete Mode.
520          * If Mode was removed, return true.
521          * If Client did not have Mode, return false.
522          */
523
524         char x[2], *p;
525
526         assert( Client != NULL );
527
528         x[0] = Mode; x[1] = '\0';
529
530         p = strchr( Client->modes, x[0] );
531         if( ! p ) return false;
532
533         /* Client has Mode -> delete */
534         while( *p )
535         {
536                 *p = *(p + 1);
537                 p++;
538         }
539         return true;
540 } /* Client_ModeDel */
541
542
543 GLOBAL CLIENT *
544 Client_GetFromConn( CONN_ID Idx )
545 {
546         /* return Client-Structure that belongs to the local Connection Idx gehoert.
547          * If none is found, return NULL.
548          */
549
550         CLIENT *c;
551
552         assert( Idx >= 0 );
553         
554         c = My_Clients;
555         while( c )
556         {
557                 if( c->conn_id == Idx ) return c;
558                 c = (CLIENT *)c->next;
559         }
560         return NULL;
561 } /* Client_GetFromConn */
562
563
564 GLOBAL CLIENT *
565 Client_Search( char *Nick )
566 {
567         /* return Client-Structure that has the corresponding Nick.
568          * If none is found, return NULL.
569          */
570
571         char search_id[CLIENT_ID_LEN], *ptr;
572         CLIENT *c = NULL;
573         UINT32 search_hash;
574
575         assert( Nick != NULL );
576
577         /* copy Nick and truncate hostmask if necessary */
578         strlcpy( search_id, Nick, sizeof( search_id ));
579         ptr = strchr( search_id, '!' );
580         if( ptr ) *ptr = '\0';
581
582         search_hash = Hash( search_id );
583
584         c = My_Clients;
585         while( c )
586         {
587                 if( c->hash == search_hash )
588                 {
589                         /* lt. Hash-Wert: Treffer! */
590                         if( strcasecmp( c->id, search_id ) == 0 ) return c;
591                 }
592                 c = (CLIENT *)c->next;
593         }
594         return NULL;
595 } /* Client_Search */
596
597
598 GLOBAL CLIENT *
599 Client_GetFromToken( CLIENT *Client, int Token )
600 {
601         /* Client-Struktur, die den entsprechenden Introducer (=Client)
602          * und das gegebene Token hat, liefern. Wird keine gefunden,
603          * so wird NULL geliefert. */
604
605         CLIENT *c;
606
607         assert( Client != NULL );
608         assert( Token > 0 );
609
610         c = My_Clients;
611         while( c )
612         {
613                 if(( c->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c->token == Token )) return c;
614                 c = (CLIENT *)c->next;
615         }
616         return NULL;
617 } /* Client_GetFromToken */
618
619
620 GLOBAL int
621 Client_Type( CLIENT *Client )
622 {
623         assert( Client != NULL );
624         return Client->type;
625 } /* Client_Type */
626
627
628 GLOBAL CONN_ID
629 Client_Conn( CLIENT *Client )
630 {
631         assert( Client != NULL );
632         return Client->conn_id;
633 } /* Client_Conn */
634
635
636 GLOBAL char *
637 Client_ID( CLIENT *Client )
638 {
639         assert( Client != NULL );
640
641 #ifdef DEBUG
642         if( Client->type == CLIENT_USER ) assert( strlen( Client->id ) < CLIENT_NICK_LEN );
643 #endif
644                                                    
645         if( Client->id[0] ) return Client->id;
646         else return "*";
647 } /* Client_ID */
648
649
650 GLOBAL char *
651 Client_Info( CLIENT *Client )
652 {
653         assert( Client != NULL );
654         return Client->info;
655 } /* Client_Info */
656
657
658 GLOBAL char *
659 Client_User( CLIENT *Client )
660 {
661         assert( Client != NULL );
662         if( Client->user[0] ) return Client->user;
663         else return "~";
664 } /* Client_User */
665
666
667 GLOBAL char *
668 Client_Hostname( CLIENT *Client )
669 {
670         assert( Client != NULL );
671         return Client->host;
672 } /* Client_Hostname */
673
674
675 GLOBAL char *
676 Client_Password( CLIENT *Client )
677 {
678         assert( Client != NULL );
679         return Client->pwd;
680 } /* Client_Password */
681
682
683 GLOBAL char *
684 Client_Modes( CLIENT *Client )
685 {
686         assert( Client != NULL );
687         return Client->modes;
688 } /* Client_Modes */
689
690
691 GLOBAL char *
692 Client_Flags( CLIENT *Client )
693 {
694         assert( Client != NULL );
695         return Client->flags;
696 } /* Client_Flags */
697
698
699 GLOBAL bool
700 Client_OperByMe( CLIENT *Client )
701 {
702         assert( Client != NULL );
703         return Client->oper_by_me;
704 } /* Client_OperByMe */
705
706
707 GLOBAL int
708 Client_Hops( CLIENT *Client )
709 {
710         assert( Client != NULL );
711         return Client->hops;
712 } /* Client_Hops */
713
714
715 GLOBAL int
716 Client_Token( CLIENT *Client )
717 {
718         assert( Client != NULL );
719         return Client->token;
720 } /* Client_Token */
721
722
723 GLOBAL int
724 Client_MyToken( CLIENT *Client )
725 {
726         assert( Client != NULL );
727         return Client->mytoken;
728 } /* Client_MyToken */
729
730
731 GLOBAL CLIENT *
732 Client_NextHop( CLIENT *Client )
733 {
734         CLIENT *c;
735         
736         assert( Client != NULL );
737
738         c = Client;
739         while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server )) c = c->introducer;
740         return c;
741 } /* Client_NextHop */
742
743
744 GLOBAL char *
745 Client_Mask( CLIENT *Client )
746 {
747         /* Client-"ID" liefern, wie sie z.B. fuer
748          * Prefixe benoetigt wird. */
749
750         assert( Client != NULL );
751         
752         if( Client->type == CLIENT_SERVER ) return Client->id;
753
754         snprintf( GetID_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user, Client->host );
755         return GetID_Buffer;
756 } /* Client_Mask */
757
758
759 GLOBAL CLIENT *
760 Client_Introducer( CLIENT *Client )
761 {
762         assert( Client != NULL );
763         return Client->introducer;
764 } /* Client_Introducer */
765
766
767 GLOBAL CLIENT *
768 Client_TopServer( CLIENT *Client )
769 {
770         assert( Client != NULL );
771         return Client->topserver;
772 } /* Client_TopServer */
773
774
775 GLOBAL bool
776 Client_HasMode( CLIENT *Client, char Mode )
777 {
778         assert( Client != NULL );
779         return strchr( Client->modes, Mode ) != NULL;
780 } /* Client_HasMode */
781
782
783 GLOBAL char *
784 Client_Away( CLIENT *Client )
785 {
786         /* AWAY-Text liefern */
787
788         assert( Client != NULL );
789         return Client->away;
790 } /* Client_Away */
791
792
793 GLOBAL bool
794 Client_CheckNick( CLIENT *Client, char *Nick )
795 {
796         /* Nick ueberpruefen */
797
798         assert( Client != NULL );
799         assert( Nick != NULL );
800         
801         /* Nick ungueltig? */
802         if( ! Client_IsValidNick( Nick ))
803         {
804                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
805                 return false;
806         }
807
808         /* Nick bereits vergeben? */
809         if( Client_Search( Nick ))
810         {
811                 /* den Nick gibt es bereits */
812                 IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
813                 return false;
814         }
815
816         return true;
817 } /* Client_CheckNick */
818
819
820 GLOBAL bool
821 Client_CheckID( CLIENT *Client, char *ID )
822 {
823         /* Nick ueberpruefen */
824
825         char str[COMMAND_LEN];
826         CLIENT *c;
827
828         assert( Client != NULL );
829         assert( Client->conn_id > NONE );
830         assert( ID != NULL );
831
832         /* Nick zu lang? */
833         if( strlen( ID ) > CLIENT_ID_LEN )
834         {
835                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), ID );
836                 return false;
837         }
838
839         /* ID bereits vergeben? */
840         c = My_Clients;
841         while( c )
842         {
843                 if( strcasecmp( c->id, ID ) == 0 )
844                 {
845                         /* die Server-ID gibt es bereits */
846                         snprintf( str, sizeof( str ), "ID \"%s\" already registered", ID );
847                         if( Client->conn_id != c->conn_id ) Log( LOG_ERR, "%s (on connection %d)!", str, c->conn_id );
848                         else Log( LOG_ERR, "%s (via network)!", str );
849                         Conn_Close( Client->conn_id, str, str, true);
850                         return false;
851                 }
852                 c = (CLIENT *)c->next;
853         }
854
855         return true;
856 } /* Client_CheckID */
857
858
859 GLOBAL CLIENT *
860 Client_First( void )
861 {
862         /* Ersten Client liefern. */
863
864         return My_Clients;
865 } /* Client_First */
866
867
868 GLOBAL CLIENT *
869 Client_Next( CLIENT *c )
870 {
871         /* Naechsten Client liefern. Existiert keiner,
872          * so wird NULL geliefert. */
873
874         assert( c != NULL );
875         return (CLIENT *)c->next;
876 } /* Client_Next */
877
878
879 GLOBAL long
880 Client_UserCount( void )
881 {
882         return Count( CLIENT_USER );
883 } /* Client_UserCount */
884
885
886 GLOBAL long
887 Client_ServiceCount( void )
888 {
889         return Count( CLIENT_SERVICE );;
890 } /* Client_ServiceCount */
891
892
893 GLOBAL long
894 Client_ServerCount( void )
895 {
896         return Count( CLIENT_SERVER );
897 } /* Client_ServerCount */
898
899
900 GLOBAL long
901 Client_MyUserCount( void )
902 {
903         return MyCount( CLIENT_USER );
904 } /* Client_MyUserCount */
905
906
907 GLOBAL long
908 Client_MyServiceCount( void )
909 {
910         return MyCount( CLIENT_SERVICE );
911 } /* Client_MyServiceCount */
912
913
914 GLOBAL long
915 Client_MyServerCount( void )
916 {
917         CLIENT *c;
918         long cnt;
919
920         cnt = 0;
921         c = My_Clients;
922         while( c )
923         {
924                 if(( c->type == CLIENT_SERVER ) && ( c->hops == 1 )) cnt++;
925                 c = (CLIENT *)c->next;
926         }
927         return cnt;
928 } /* Client_MyServerCount */
929
930
931 GLOBAL long
932 Client_OperCount( void )
933 {
934         CLIENT *c;
935         long cnt;
936
937         cnt = 0;
938         c = My_Clients;
939         while( c )
940         {
941                 if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++;
942                 c = (CLIENT *)c->next;
943         }
944         return cnt;
945 } /* Client_OperCount */
946
947
948 GLOBAL long
949 Client_UnknownCount( void )
950 {
951         CLIENT *c;
952         long cnt;
953
954         cnt = 0;
955         c = My_Clients;
956         while( c )
957         {
958                 if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
959                 c = (CLIENT *)c->next;
960         }
961         return cnt;
962 } /* Client_UnknownCount */
963
964
965 GLOBAL long
966 Client_MaxUserCount( void )
967 {
968         return Max_Users;
969 } /* Client_MaxUserCount */
970
971
972 GLOBAL long
973 Client_MyMaxUserCount( void )
974 {
975         return My_Max_Users;
976 } /* Client_MyMaxUserCount */
977
978
979 GLOBAL bool
980 Client_IsValidNick( char *Nick )
981 {
982         /* Ist der Nick gueltig? */
983
984         char *ptr, goodchars[20];
985         
986         assert( Nick != NULL );
987
988         strcpy( goodchars, ";0123456789-" );
989
990         if( Nick[0] == '#' ) return false;
991         if( strchr( goodchars, Nick[0] )) return false;
992         if( strlen( Nick ) >= CLIENT_NICK_LEN ) return false;
993
994         ptr = Nick;
995         while( *ptr )
996         {
997                 if(( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return false;
998                 if(( *ptr > '}' ) && ( ! strchr( goodchars, *ptr ))) return false;
999                 ptr++;
1000         }
1001         
1002         return true;
1003 } /* Client_IsValidNick */
1004
1005
1006 /**
1007  * Return pointer to "My_Whowas" structure.
1008  */
1009 GLOBAL WHOWAS *
1010 Client_GetWhowas( void )
1011 {
1012         return My_Whowas;
1013 } /* Client_GetWhowas */
1014
1015 /**
1016  * Return the index of the last used WHOWAS entry.
1017  */
1018 GLOBAL int
1019 Client_GetLastWhowasIndex( void )
1020 {
1021         return Last_Whowas;
1022 } /* Client_GetLastWhowasIndex */
1023
1024
1025 /**
1026  * Get the start time of this client.
1027  * The result is the start time in seconds since 1970-01-01, as reported
1028  * by the C function time(NULL).
1029  */
1030 GLOBAL time_t
1031 Client_StartTime(CLIENT *Client)
1032 {
1033         assert( Client != NULL );
1034         return Client->starttime;
1035 } /* Client_Uptime */
1036
1037
1038 static long
1039 Count( CLIENT_TYPE Type )
1040 {
1041         CLIENT *c;
1042         long cnt;
1043
1044         cnt = 0;
1045         c = My_Clients;
1046         while( c )
1047         {
1048                 if( c->type == Type ) cnt++;
1049                 c = (CLIENT *)c->next;
1050         }
1051         return cnt;
1052 } /* Count */
1053
1054
1055 static long
1056 MyCount( CLIENT_TYPE Type )
1057 {
1058         CLIENT *c;
1059         long cnt;
1060
1061         cnt = 0;
1062         c = My_Clients;
1063         while( c )
1064         {
1065                 if(( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
1066                 c = (CLIENT *)c->next;
1067         }
1068         return cnt;
1069 } /* MyCount */
1070
1071
1072 static CLIENT *
1073 New_Client_Struct( void )
1074 {
1075         /* Neue CLIENT-Struktur pre-initialisieren */
1076         
1077         CLIENT *c;
1078         
1079         c = (CLIENT *)malloc( sizeof( CLIENT ));
1080         if( ! c )
1081         {
1082                 Log( LOG_EMERG, "Can't allocate memory! [New_Client_Struct]" );
1083                 return NULL;
1084         }
1085
1086         memset( c, 0, sizeof ( CLIENT ));
1087
1088         c->type = CLIENT_UNKNOWN;
1089         c->conn_id = NONE;
1090         c->oper_by_me = false;
1091         c->hops = -1;
1092         c->token = -1;
1093         c->mytoken = -1;
1094
1095         return c;
1096 } /* New_Client */
1097
1098
1099 static void
1100 Generate_MyToken( CLIENT *Client )
1101 {
1102         CLIENT *c;
1103         int token;
1104
1105         c = My_Clients;
1106         token = 2;
1107         while( c )
1108         {
1109                 if( c->mytoken == token )
1110                 {
1111                         /* Das Token wurde bereits vergeben */
1112                         token++;
1113                         c = My_Clients;
1114                         continue;
1115                 }
1116                 else c = (CLIENT *)c->next;
1117         }
1118         Client->mytoken = token;
1119         Log( LOG_DEBUG, "Assigned token %d to server \"%s\".", token, Client->id );
1120 } /* Generate_MyToken */
1121
1122
1123 static void
1124 Adjust_Counters( CLIENT *Client )
1125 {
1126         long count;
1127
1128         assert( Client != NULL );
1129
1130         if( Client->type != CLIENT_USER ) return;
1131         
1132         if( Client->conn_id != NONE )
1133         {
1134                 /* Local connection */
1135                 count = Client_MyUserCount( );
1136                 if( count > My_Max_Users ) My_Max_Users = count;
1137         }
1138         count = Client_UserCount( );
1139         if( count > Max_Users ) Max_Users = count;
1140 } /* Adjust_Counters */
1141
1142
1143 /**
1144  * Register client in My_Whowas structure for further recall by WHOWAS.
1145  * Note: Only clients that have been connected at least 30 seconds will be
1146  * registered to prevent automated IRC bots to "destroy" a nice server
1147  * history database.
1148  */
1149 GLOBAL void
1150 Client_RegisterWhowas( CLIENT *Client )
1151 {
1152         int slot;
1153         
1154         assert( Client != NULL );
1155
1156         /* Don't register clients that were connected less than 30 seconds. */
1157         if( time(NULL) - Client->starttime < 30 )
1158                 return;
1159
1160         slot = Last_Whowas + 1;
1161         if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
1162
1163 #ifdef DEBUG
1164         Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
1165 #endif
1166         
1167         My_Whowas[slot].time = time( NULL );
1168         strlcpy( My_Whowas[slot].id, Client_ID( Client ),
1169                  sizeof( My_Whowas[slot].id ));
1170         strlcpy( My_Whowas[slot].user, Client_User( Client ),
1171                  sizeof( My_Whowas[slot].user ));
1172         strlcpy( My_Whowas[slot].host, Client_Hostname( Client ),
1173                  sizeof( My_Whowas[slot].host ));
1174         strlcpy( My_Whowas[slot].info, Client_Info( Client ),
1175                  sizeof( My_Whowas[slot].info ));
1176         strlcpy( My_Whowas[slot].server, Client_ID( Client_Introducer( Client )),
1177                  sizeof( My_Whowas[slot].server ));
1178         
1179         Last_Whowas = slot;
1180 } /* Client_RegisterWhowas */
1181
1182
1183 /* -eof- */