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