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