]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/client.c
6c4edd193160e7e18a72df04a2a7ae1cdc573dc6
[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.93 2006/10/07 10:40:52 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 unsigned long Count PARAMS(( CLIENT_TYPE Type ));
61 static unsigned 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         if( strchr( client->modes, 'a' ))
215                 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 ))
742                 c = c->introducer;
743
744         return c;
745 } /* Client_NextHop */
746
747
748 GLOBAL char *
749 Client_Mask( CLIENT *Client )
750 {
751         /* Client-"ID" liefern, wie sie z.B. fuer
752          * Prefixe benoetigt wird. */
753
754         assert( Client != NULL );
755
756         if( Client->type == CLIENT_SERVER ) return Client->id;
757
758         snprintf( GetID_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user, Client->host );
759         return GetID_Buffer;
760 } /* Client_Mask */
761
762
763 GLOBAL CLIENT *
764 Client_Introducer( CLIENT *Client )
765 {
766         assert( Client != NULL );
767         return Client->introducer;
768 } /* Client_Introducer */
769
770
771 GLOBAL CLIENT *
772 Client_TopServer( CLIENT *Client )
773 {
774         assert( Client != NULL );
775         return Client->topserver;
776 } /* Client_TopServer */
777
778
779 GLOBAL bool
780 Client_HasMode( CLIENT *Client, char Mode )
781 {
782         assert( Client != NULL );
783         return strchr( Client->modes, Mode ) != NULL;
784 } /* Client_HasMode */
785
786
787 GLOBAL char *
788 Client_Away( CLIENT *Client )
789 {
790         /* AWAY-Text liefern */
791
792         assert( Client != NULL );
793         return Client->away;
794 } /* Client_Away */
795
796
797 GLOBAL bool
798 Client_CheckNick( CLIENT *Client, char *Nick )
799 {
800         assert( Client != NULL );
801         assert( Nick != NULL );
802
803         if( ! Client_IsValidNick( Nick ))
804         {
805                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
806                 return false;
807         }
808
809         /* Nick bereits vergeben? */
810         if( Client_Search( Nick ))
811         {
812                 /* den Nick gibt es bereits */
813                 IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
814                 return false;
815         }
816
817         return true;
818 } /* Client_CheckNick */
819
820
821 GLOBAL bool
822 Client_CheckID( CLIENT *Client, char *ID )
823 {
824         /* Nick ueberpruefen */
825
826         char str[COMMAND_LEN];
827         CLIENT *c;
828
829         assert( Client != NULL );
830         assert( Client->conn_id > NONE );
831         assert( ID != NULL );
832
833         /* Nick zu lang? */
834         if( strlen( ID ) > CLIENT_ID_LEN )
835         {
836                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), ID );
837                 return false;
838         }
839
840         /* ID bereits vergeben? */
841         c = My_Clients;
842         while( c )
843         {
844                 if( strcasecmp( c->id, ID ) == 0 )
845                 {
846                         /* die Server-ID gibt es bereits */
847                         snprintf( str, sizeof( str ), "ID \"%s\" already registered", ID );
848                         if( Client->conn_id != c->conn_id ) Log( LOG_ERR, "%s (on connection %d)!", str, c->conn_id );
849                         else Log( LOG_ERR, "%s (via network)!", str );
850                         Conn_Close( Client->conn_id, str, str, true);
851                         return false;
852                 }
853                 c = (CLIENT *)c->next;
854         }
855
856         return true;
857 } /* Client_CheckID */
858
859
860 GLOBAL CLIENT *
861 Client_First( void )
862 {
863         /* Ersten Client liefern. */
864
865         return My_Clients;
866 } /* Client_First */
867
868
869 GLOBAL CLIENT *
870 Client_Next( CLIENT *c )
871 {
872         /* Naechsten Client liefern. Existiert keiner,
873          * so wird NULL geliefert. */
874
875         assert( c != NULL );
876         return (CLIENT *)c->next;
877 } /* Client_Next */
878
879
880 GLOBAL long
881 Client_UserCount( void )
882 {
883         return Count( CLIENT_USER );
884 } /* Client_UserCount */
885
886
887 GLOBAL long
888 Client_ServiceCount( void )
889 {
890         return Count( CLIENT_SERVICE );;
891 } /* Client_ServiceCount */
892
893
894 GLOBAL long
895 Client_ServerCount( void )
896 {
897         return Count( CLIENT_SERVER );
898 } /* Client_ServerCount */
899
900
901 GLOBAL long
902 Client_MyUserCount( void )
903 {
904         return MyCount( CLIENT_USER );
905 } /* Client_MyUserCount */
906
907
908 GLOBAL long
909 Client_MyServiceCount( void )
910 {
911         return MyCount( CLIENT_SERVICE );
912 } /* Client_MyServiceCount */
913
914
915 GLOBAL unsigned long
916 Client_MyServerCount( void )
917 {
918         CLIENT *c;
919         unsigned long cnt;
920
921         cnt = 0;
922         c = My_Clients;
923         while( c )
924         {
925                 if(( c->type == CLIENT_SERVER ) && ( c->hops == 1 )) cnt++;
926                 c = (CLIENT *)c->next;
927         }
928         return cnt;
929 } /* Client_MyServerCount */
930
931
932 GLOBAL unsigned long
933 Client_OperCount( void )
934 {
935         CLIENT *c;
936         unsigned long cnt;
937
938         cnt = 0;
939         c = My_Clients;
940         while( c )
941         {
942                 if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++;
943                 c = (CLIENT *)c->next;
944         }
945         return cnt;
946 } /* Client_OperCount */
947
948
949 GLOBAL unsigned long
950 Client_UnknownCount( void )
951 {
952         CLIENT *c;
953         unsigned long cnt = 0;
954
955         c = My_Clients;
956         while( c )
957         {
958                 if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
959                 c = (CLIENT *)c->next;
960         }
961
962         return cnt;
963 } /* Client_UnknownCount */
964
965
966 GLOBAL long
967 Client_MaxUserCount( void )
968 {
969         return Max_Users;
970 } /* Client_MaxUserCount */
971
972
973 GLOBAL long
974 Client_MyMaxUserCount( void )
975 {
976         return My_Max_Users;
977 } /* Client_MyMaxUserCount */
978
979
980 GLOBAL bool
981 Client_IsValidNick( const char *Nick )
982 {
983         const char *ptr;
984         static const char goodchars[] = ";0123456789-";
985
986         assert( Nick != NULL );
987
988         if( Nick[0] == '#' ) return false;
989         if( strchr( goodchars, Nick[0] )) return false;
990         if( strlen( Nick ) >= CLIENT_NICK_LEN ) return false;
991
992         ptr = Nick;
993         while( *ptr )
994         {
995                 if (( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return false;
996                 if ( *ptr > '}' ) return false;
997                 ptr++;
998         }
999
1000         return true;
1001 } /* Client_IsValidNick */
1002
1003
1004 /**
1005  * Return pointer to "My_Whowas" structure.
1006  */
1007 GLOBAL WHOWAS *
1008 Client_GetWhowas( void )
1009 {
1010         return My_Whowas;
1011 } /* Client_GetWhowas */
1012
1013 /**
1014  * Return the index of the last used WHOWAS entry.
1015  */
1016 GLOBAL int
1017 Client_GetLastWhowasIndex( void )
1018 {
1019         return Last_Whowas;
1020 } /* Client_GetLastWhowasIndex */
1021
1022
1023 /**
1024  * Get the start time of this client.
1025  * The result is the start time in seconds since 1970-01-01, as reported
1026  * by the C function time(NULL).
1027  */
1028 GLOBAL time_t
1029 Client_StartTime(CLIENT *Client)
1030 {
1031         assert( Client != NULL );
1032         return Client->starttime;
1033 } /* Client_Uptime */
1034
1035
1036 static unsigned long
1037 Count( CLIENT_TYPE Type )
1038 {
1039         CLIENT *c;
1040         unsigned long cnt = 0;
1041
1042         c = My_Clients;
1043         while( c )
1044         {
1045                 if( c->type == Type ) cnt++;
1046                 c = (CLIENT *)c->next;
1047         }
1048         return cnt;
1049 } /* Count */
1050
1051
1052 static unsigned long
1053 MyCount( CLIENT_TYPE Type )
1054 {
1055         CLIENT *c;
1056         unsigned long cnt = 0;
1057
1058         c = My_Clients;
1059         while( c )
1060         {
1061                 if(( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
1062                 c = (CLIENT *)c->next;
1063         }
1064         return cnt;
1065 } /* MyCount */
1066
1067
1068 static CLIENT *
1069 New_Client_Struct( void )
1070 {
1071         /* Neue CLIENT-Struktur pre-initialisieren */
1072
1073         CLIENT *c;
1074
1075         c = (CLIENT *)malloc( sizeof( CLIENT ));
1076         if( ! c )
1077         {
1078                 Log( LOG_EMERG, "Can't allocate memory! [New_Client_Struct]" );
1079                 return NULL;
1080         }
1081
1082         memset( c, 0, sizeof ( CLIENT ));
1083
1084         c->type = CLIENT_UNKNOWN;
1085         c->conn_id = NONE;
1086         c->oper_by_me = false;
1087         c->hops = -1;
1088         c->token = -1;
1089         c->mytoken = -1;
1090
1091         return c;
1092 } /* New_Client */
1093
1094
1095 static void
1096 Generate_MyToken( CLIENT *Client )
1097 {
1098         CLIENT *c;
1099         int token;
1100
1101         c = My_Clients;
1102         token = 2;
1103         while( c )
1104         {
1105                 if( c->mytoken == token )
1106                 {
1107                         /* Das Token wurde bereits vergeben */
1108                         token++;
1109                         c = My_Clients;
1110                         continue;
1111                 }
1112                 else c = (CLIENT *)c->next;
1113         }
1114         Client->mytoken = token;
1115         Log( LOG_DEBUG, "Assigned token %d to server \"%s\".", token, Client->id );
1116 } /* Generate_MyToken */
1117
1118
1119 static void
1120 Adjust_Counters( CLIENT *Client )
1121 {
1122         long count;
1123
1124         assert( Client != NULL );
1125
1126         if( Client->type != CLIENT_USER ) return;
1127
1128         if( Client->conn_id != NONE )
1129         {
1130                 /* Local connection */
1131                 count = Client_MyUserCount( );
1132                 if( count > My_Max_Users ) My_Max_Users = count;
1133         }
1134         count = Client_UserCount( );
1135         if( count > Max_Users ) Max_Users = count;
1136 } /* Adjust_Counters */
1137
1138
1139 /**
1140  * Register client in My_Whowas structure for further recall by WHOWAS.
1141  * Note: Only clients that have been connected at least 30 seconds will be
1142  * registered to prevent automated IRC bots to "destroy" a nice server
1143  * history database.
1144  */
1145 GLOBAL void
1146 Client_RegisterWhowas( CLIENT *Client )
1147 {
1148         int slot;
1149         time_t now;
1150
1151         assert( Client != NULL );
1152
1153         now = time(NULL);
1154         /* Don't register clients that were connected less than 30 seconds. */
1155         if( now - Client->starttime < 30 )
1156                 return;
1157
1158         slot = Last_Whowas + 1;
1159         if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
1160
1161 #ifdef DEBUG
1162         Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
1163 #endif
1164
1165         My_Whowas[slot].time = now;
1166         strlcpy( My_Whowas[slot].id, Client_ID( Client ),
1167                  sizeof( My_Whowas[slot].id ));
1168         strlcpy( My_Whowas[slot].user, Client_User( Client ),
1169                  sizeof( My_Whowas[slot].user ));
1170         strlcpy( My_Whowas[slot].host, Client_Hostname( Client ),
1171                  sizeof( My_Whowas[slot].host ));
1172         strlcpy( My_Whowas[slot].info, Client_Info( Client ),
1173                  sizeof( My_Whowas[slot].info ));
1174         strlcpy( My_Whowas[slot].server, Client_ID( Client_Introducer( Client )),
1175                  sizeof( My_Whowas[slot].server ));
1176
1177         Last_Whowas = slot;
1178 } /* Client_RegisterWhowas */
1179
1180
1181 /* -eof- */