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