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