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