]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/client.c
fix ngt_TrimStr(), fix format string
[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.90 2006/03/24 23:25:38 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_GetFromConn( CONN_ID Idx )
568 {
569         /* return Client-Structure that belongs to the local Connection Idx.
570          * If none is found, return NULL.
571          */
572
573         CLIENT *c;
574
575         assert( Idx >= 0 );
576         
577         c = My_Clients;
578         while( c )
579         {
580                 if( c->conn_id == Idx ) return c;
581                 c = (CLIENT *)c->next;
582         }
583         return NULL;
584 } /* Client_GetFromConn */
585
586
587 GLOBAL CLIENT *
588 Client_Search( char *Nick )
589 {
590         /* return Client-Structure that has the corresponding Nick.
591          * If none is found, return NULL.
592          */
593
594         char search_id[CLIENT_ID_LEN], *ptr;
595         CLIENT *c = NULL;
596         UINT32 search_hash;
597
598         assert( Nick != NULL );
599
600         /* copy Nick and truncate hostmask if necessary */
601         strlcpy( search_id, Nick, sizeof( search_id ));
602         ptr = strchr( search_id, '!' );
603         if( ptr ) *ptr = '\0';
604
605         search_hash = Hash( search_id );
606
607         c = My_Clients;
608         while( c )
609         {
610                 if( c->hash == search_hash )
611                 {
612                         /* lt. Hash-Wert: Treffer! */
613                         if( strcasecmp( c->id, search_id ) == 0 ) return c;
614                 }
615                 c = (CLIENT *)c->next;
616         }
617         return NULL;
618 } /* Client_Search */
619
620
621 GLOBAL CLIENT *
622 Client_GetFromToken( CLIENT *Client, int Token )
623 {
624         /* Client-Struktur, die den entsprechenden Introducer (=Client)
625          * und das gegebene Token hat, liefern. Wird keine gefunden,
626          * so wird NULL geliefert. */
627
628         CLIENT *c;
629
630         assert( Client != NULL );
631         assert( Token > 0 );
632
633         c = My_Clients;
634         while( c )
635         {
636                 if(( c->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c->token == Token )) return c;
637                 c = (CLIENT *)c->next;
638         }
639         return NULL;
640 } /* Client_GetFromToken */
641
642
643 GLOBAL int
644 Client_Type( CLIENT *Client )
645 {
646         assert( Client != NULL );
647         return Client->type;
648 } /* Client_Type */
649
650
651 GLOBAL CONN_ID
652 Client_Conn( CLIENT *Client )
653 {
654         assert( Client != NULL );
655         return Client->conn_id;
656 } /* Client_Conn */
657
658
659 GLOBAL char *
660 Client_ID( CLIENT *Client )
661 {
662         assert( Client != NULL );
663
664 #ifdef DEBUG
665         if( Client->type == CLIENT_USER ) assert( strlen( Client->id ) < CLIENT_NICK_LEN );
666 #endif
667                                                    
668         if( Client->id[0] ) return Client->id;
669         else return "*";
670 } /* Client_ID */
671
672
673 GLOBAL char *
674 Client_Info( CLIENT *Client )
675 {
676         assert( Client != NULL );
677         return Client->info;
678 } /* Client_Info */
679
680
681 GLOBAL char *
682 Client_User( CLIENT *Client )
683 {
684         assert( Client != NULL );
685         if( Client->user[0] ) return Client->user;
686         else return "~";
687 } /* Client_User */
688
689
690 GLOBAL char *
691 Client_Hostname( CLIENT *Client )
692 {
693         assert( Client != NULL );
694         return Client->host;
695 } /* Client_Hostname */
696
697
698 GLOBAL char *
699 Client_Password( CLIENT *Client )
700 {
701         assert( Client != NULL );
702         return Client->pwd;
703 } /* Client_Password */
704
705
706 GLOBAL char *
707 Client_Modes( CLIENT *Client )
708 {
709         assert( Client != NULL );
710         return Client->modes;
711 } /* Client_Modes */
712
713
714 GLOBAL char *
715 Client_Flags( CLIENT *Client )
716 {
717         assert( Client != NULL );
718         return Client->flags;
719 } /* Client_Flags */
720
721
722 GLOBAL bool
723 Client_OperByMe( CLIENT *Client )
724 {
725         assert( Client != NULL );
726         return Client->oper_by_me;
727 } /* Client_OperByMe */
728
729
730 GLOBAL int
731 Client_Hops( CLIENT *Client )
732 {
733         assert( Client != NULL );
734         return Client->hops;
735 } /* Client_Hops */
736
737
738 GLOBAL int
739 Client_Token( CLIENT *Client )
740 {
741         assert( Client != NULL );
742         return Client->token;
743 } /* Client_Token */
744
745
746 GLOBAL int
747 Client_MyToken( CLIENT *Client )
748 {
749         assert( Client != NULL );
750         return Client->mytoken;
751 } /* Client_MyToken */
752
753
754 GLOBAL CLIENT *
755 Client_NextHop( CLIENT *Client )
756 {
757         CLIENT *c;
758         
759         assert( Client != NULL );
760
761         c = Client;
762         while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server )) c = c->introducer;
763         return c;
764 } /* Client_NextHop */
765
766
767 GLOBAL char *
768 Client_Mask( CLIENT *Client )
769 {
770         /* Client-"ID" liefern, wie sie z.B. fuer
771          * Prefixe benoetigt wird. */
772
773         assert( Client != NULL );
774         
775         if( Client->type == CLIENT_SERVER ) return Client->id;
776
777         snprintf( GetID_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user, Client->host );
778         return GetID_Buffer;
779 } /* Client_Mask */
780
781
782 GLOBAL CLIENT *
783 Client_Introducer( CLIENT *Client )
784 {
785         assert( Client != NULL );
786         return Client->introducer;
787 } /* Client_Introducer */
788
789
790 GLOBAL CLIENT *
791 Client_TopServer( CLIENT *Client )
792 {
793         assert( Client != NULL );
794         return Client->topserver;
795 } /* Client_TopServer */
796
797
798 GLOBAL bool
799 Client_HasMode( CLIENT *Client, char Mode )
800 {
801         assert( Client != NULL );
802         return strchr( Client->modes, Mode ) != NULL;
803 } /* Client_HasMode */
804
805
806 GLOBAL char *
807 Client_Away( CLIENT *Client )
808 {
809         /* AWAY-Text liefern */
810
811         assert( Client != NULL );
812         return Client->away;
813 } /* Client_Away */
814
815
816 GLOBAL bool
817 Client_CheckNick( CLIENT *Client, char *Nick )
818 {
819         /* Nick ueberpruefen */
820
821         assert( Client != NULL );
822         assert( Nick != NULL );
823         
824         /* Nick ungueltig? */
825         if( ! Client_IsValidNick( Nick ))
826         {
827                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
828                 return false;
829         }
830
831         /* Nick bereits vergeben? */
832         if( Client_Search( Nick ))
833         {
834                 /* den Nick gibt es bereits */
835                 IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
836                 return false;
837         }
838
839         return true;
840 } /* Client_CheckNick */
841
842
843 GLOBAL bool
844 Client_CheckID( CLIENT *Client, char *ID )
845 {
846         /* Nick ueberpruefen */
847
848         char str[COMMAND_LEN];
849         CLIENT *c;
850
851         assert( Client != NULL );
852         assert( Client->conn_id > NONE );
853         assert( ID != NULL );
854
855         /* Nick zu lang? */
856         if( strlen( ID ) > CLIENT_ID_LEN )
857         {
858                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), ID );
859                 return false;
860         }
861
862         /* ID bereits vergeben? */
863         c = My_Clients;
864         while( c )
865         {
866                 if( strcasecmp( c->id, ID ) == 0 )
867                 {
868                         /* die Server-ID gibt es bereits */
869                         snprintf( str, sizeof( str ), "ID \"%s\" already registered", ID );
870                         if( Client->conn_id != c->conn_id ) Log( LOG_ERR, "%s (on connection %d)!", str, c->conn_id );
871                         else Log( LOG_ERR, "%s (via network)!", str );
872                         Conn_Close( Client->conn_id, str, str, true);
873                         return false;
874                 }
875                 c = (CLIENT *)c->next;
876         }
877
878         return true;
879 } /* Client_CheckID */
880
881
882 GLOBAL CLIENT *
883 Client_First( void )
884 {
885         /* Ersten Client liefern. */
886
887         return My_Clients;
888 } /* Client_First */
889
890
891 GLOBAL CLIENT *
892 Client_Next( CLIENT *c )
893 {
894         /* Naechsten Client liefern. Existiert keiner,
895          * so wird NULL geliefert. */
896
897         assert( c != NULL );
898         return (CLIENT *)c->next;
899 } /* Client_Next */
900
901
902 GLOBAL long
903 Client_UserCount( void )
904 {
905         return Count( CLIENT_USER );
906 } /* Client_UserCount */
907
908
909 GLOBAL long
910 Client_ServiceCount( void )
911 {
912         return Count( CLIENT_SERVICE );;
913 } /* Client_ServiceCount */
914
915
916 GLOBAL long
917 Client_ServerCount( void )
918 {
919         return Count( CLIENT_SERVER );
920 } /* Client_ServerCount */
921
922
923 GLOBAL long
924 Client_MyUserCount( void )
925 {
926         return MyCount( CLIENT_USER );
927 } /* Client_MyUserCount */
928
929
930 GLOBAL long
931 Client_MyServiceCount( void )
932 {
933         return MyCount( CLIENT_SERVICE );
934 } /* Client_MyServiceCount */
935
936
937 GLOBAL long
938 Client_MyServerCount( void )
939 {
940         CLIENT *c;
941         long cnt;
942
943         cnt = 0;
944         c = My_Clients;
945         while( c )
946         {
947                 if(( c->type == CLIENT_SERVER ) && ( c->hops == 1 )) cnt++;
948                 c = (CLIENT *)c->next;
949         }
950         return cnt;
951 } /* Client_MyServerCount */
952
953
954 GLOBAL long
955 Client_OperCount( void )
956 {
957         CLIENT *c;
958         long cnt;
959
960         cnt = 0;
961         c = My_Clients;
962         while( c )
963         {
964                 if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++;
965                 c = (CLIENT *)c->next;
966         }
967         return cnt;
968 } /* Client_OperCount */
969
970
971 GLOBAL long
972 Client_UnknownCount( void )
973 {
974         CLIENT *c;
975         long cnt;
976
977         cnt = 0;
978         c = My_Clients;
979         while( c )
980         {
981                 if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
982                 c = (CLIENT *)c->next;
983         }
984         return cnt;
985 } /* Client_UnknownCount */
986
987
988 GLOBAL long
989 Client_MaxUserCount( void )
990 {
991         return Max_Users;
992 } /* Client_MaxUserCount */
993
994
995 GLOBAL long
996 Client_MyMaxUserCount( void )
997 {
998         return My_Max_Users;
999 } /* Client_MyMaxUserCount */
1000
1001
1002 GLOBAL bool
1003 Client_IsValidNick( char *Nick )
1004 {
1005         /* Ist der Nick gueltig? */
1006
1007         char *ptr, goodchars[20];
1008         
1009         assert( Nick != NULL );
1010
1011         strcpy( goodchars, ";0123456789-" );
1012
1013         if( Nick[0] == '#' ) return false;
1014         if( strchr( goodchars, Nick[0] )) return false;
1015         if( strlen( Nick ) >= CLIENT_NICK_LEN ) return false;
1016
1017         ptr = Nick;
1018         while( *ptr )
1019         {
1020                 if(( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return false;
1021                 if(( *ptr > '}' ) && ( ! strchr( goodchars, *ptr ))) return false;
1022                 ptr++;
1023         }
1024         
1025         return true;
1026 } /* Client_IsValidNick */
1027
1028
1029 /**
1030  * Return pointer to "My_Whowas" structure.
1031  */
1032 GLOBAL WHOWAS *
1033 Client_GetWhowas( void )
1034 {
1035         return My_Whowas;
1036 } /* Client_GetWhowas */
1037
1038 /**
1039  * Return the index of the last used WHOWAS entry.
1040  */
1041 GLOBAL int
1042 Client_GetLastWhowasIndex( void )
1043 {
1044         return Last_Whowas;
1045 } /* Client_GetLastWhowasIndex */
1046
1047
1048 /**
1049  * Get the start time of this client.
1050  * The result is the start time in seconds since 1970-01-01, as reported
1051  * by the C function time(NULL).
1052  */
1053 GLOBAL time_t
1054 Client_StartTime(CLIENT *Client)
1055 {
1056         assert( Client != NULL );
1057         return Client->starttime;
1058 } /* Client_Uptime */
1059
1060
1061 static long
1062 Count( CLIENT_TYPE Type )
1063 {
1064         CLIENT *c;
1065         long cnt;
1066
1067         cnt = 0;
1068         c = My_Clients;
1069         while( c )
1070         {
1071                 if( c->type == Type ) cnt++;
1072                 c = (CLIENT *)c->next;
1073         }
1074         return cnt;
1075 } /* Count */
1076
1077
1078 static long
1079 MyCount( CLIENT_TYPE Type )
1080 {
1081         CLIENT *c;
1082         long cnt;
1083
1084         cnt = 0;
1085         c = My_Clients;
1086         while( c )
1087         {
1088                 if(( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
1089                 c = (CLIENT *)c->next;
1090         }
1091         return cnt;
1092 } /* MyCount */
1093
1094
1095 static CLIENT *
1096 New_Client_Struct( void )
1097 {
1098         /* Neue CLIENT-Struktur pre-initialisieren */
1099         
1100         CLIENT *c;
1101         
1102         c = (CLIENT *)malloc( sizeof( CLIENT ));
1103         if( ! c )
1104         {
1105                 Log( LOG_EMERG, "Can't allocate memory! [New_Client_Struct]" );
1106                 return NULL;
1107         }
1108
1109         memset( c, 0, sizeof ( CLIENT ));
1110
1111         c->type = CLIENT_UNKNOWN;
1112         c->conn_id = NONE;
1113         c->oper_by_me = false;
1114         c->hops = -1;
1115         c->token = -1;
1116         c->mytoken = -1;
1117
1118         return c;
1119 } /* New_Client */
1120
1121
1122 static void
1123 Generate_MyToken( CLIENT *Client )
1124 {
1125         CLIENT *c;
1126         int token;
1127
1128         c = My_Clients;
1129         token = 2;
1130         while( c )
1131         {
1132                 if( c->mytoken == token )
1133                 {
1134                         /* Das Token wurde bereits vergeben */
1135                         token++;
1136                         c = My_Clients;
1137                         continue;
1138                 }
1139                 else c = (CLIENT *)c->next;
1140         }
1141         Client->mytoken = token;
1142         Log( LOG_DEBUG, "Assigned token %d to server \"%s\".", token, Client->id );
1143 } /* Generate_MyToken */
1144
1145
1146 static void
1147 Adjust_Counters( CLIENT *Client )
1148 {
1149         long count;
1150
1151         assert( Client != NULL );
1152
1153         if( Client->type != CLIENT_USER ) return;
1154         
1155         if( Client->conn_id != NONE )
1156         {
1157                 /* Local connection */
1158                 count = Client_MyUserCount( );
1159                 if( count > My_Max_Users ) My_Max_Users = count;
1160         }
1161         count = Client_UserCount( );
1162         if( count > Max_Users ) Max_Users = count;
1163 } /* Adjust_Counters */
1164
1165
1166 /**
1167  * Register client in My_Whowas structure for further recall by WHOWAS.
1168  * Note: Only clients that have been connected at least 30 seconds will be
1169  * registered to prevent automated IRC bots to "destroy" a nice server
1170  * history database.
1171  */
1172 GLOBAL void
1173 Client_RegisterWhowas( CLIENT *Client )
1174 {
1175         int slot;
1176         time_t now;
1177         
1178         assert( Client != NULL );
1179
1180         now = time(NULL);
1181         /* Don't register clients that were connected less than 30 seconds. */
1182         if( now - Client->starttime < 30 )
1183                 return;
1184
1185         slot = Last_Whowas + 1;
1186         if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
1187
1188 #ifdef DEBUG
1189         Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
1190 #endif
1191         
1192         My_Whowas[slot].time = now;
1193         strlcpy( My_Whowas[slot].id, Client_ID( Client ),
1194                  sizeof( My_Whowas[slot].id ));
1195         strlcpy( My_Whowas[slot].user, Client_User( Client ),
1196                  sizeof( My_Whowas[slot].user ));
1197         strlcpy( My_Whowas[slot].host, Client_Hostname( Client ),
1198                  sizeof( My_Whowas[slot].host ));
1199         strlcpy( My_Whowas[slot].info, Client_Info( Client ),
1200                  sizeof( My_Whowas[slot].info ));
1201         strlcpy( My_Whowas[slot].server, Client_ID( Client_Introducer( Client )),
1202                  sizeof( My_Whowas[slot].server ));
1203         
1204         Last_Whowas = slot;
1205 } /* Client_RegisterWhowas */
1206
1207
1208 /* -eof- */