]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/client.c
- Netz-Split-Nachricht war so falsch. Nun ist sie korrekt aber nicht schoen.
[ngircd-alex.git] / src / ngircd / client.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
4  *
5  * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
6  * der GNU General Public License (GPL), wie von der Free Software Foundation
7  * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2
8  * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version.
9  * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
10  * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: client.c,v 1.50 2002/03/12 23:43:56 alex Exp $
13  *
14  * client.c: Management aller Clients
15  *
16  * Der Begriff "Client" ist in diesem Fall evtl. etwas verwirrend: Clients sind
17  * alle Verbindungen, die im gesamten(!) IRC-Netzwerk bekannt sind. Das sind IRC-
18  * Clients (User), andere Server und IRC-Services.
19  * Ueber welchen IRC-Server die Verbindung nun tatsaechlich in das Netzwerk her-
20  * gestellt wurde, muss der jeweiligen Struktur entnommen werden. Ist es dieser
21  * Server gewesen, so existiert eine entsprechende CONNECTION-Struktur.
22  */
23
24
25 #define __client_c__
26
27
28 #include "portab.h"
29
30 #include "imp.h"
31 #include <assert.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <netdb.h>
37
38 #include "exp.h"
39 #include "client.h"
40
41 #include <imp.h>
42 #include "ngircd.h"
43 #include "channel.h"
44 #include "conf.h"
45 #include "conn.h"
46 #include "irc-write.h"
47 #include "log.h"
48 #include "messages.h"
49
50 #include <exp.h>
51
52
53 LOCAL CLIENT *This_Server, *My_Clients;
54 LOCAL CHAR GetID_Buffer[CLIENT_ID_LEN];
55
56
57 LOCAL INT Count( CLIENT_TYPE Type );
58 LOCAL INT MyCount( CLIENT_TYPE Type );
59
60 LOCAL CLIENT *New_Client_Struct( VOID );
61 LOCAL VOID Generate_MyToken( CLIENT *Client );
62
63
64 GLOBAL VOID Client_Init( VOID )
65 {
66         struct hostent *h;
67         
68         This_Server = New_Client_Struct( );
69         if( ! This_Server )
70         {
71                 Log( LOG_EMERG, "Can't allocate client structure for server! Going down." );
72                 Log( LOG_ALERT, PACKAGE" exiting due to fatal errors!" );
73                 exit( 1 );
74         }
75
76         /* Client-Struktur dieses Servers */
77         This_Server->next = NULL;
78         This_Server->type = CLIENT_SERVER;
79         This_Server->conn_id = NONE;
80         This_Server->introducer = This_Server;
81         This_Server->mytoken = 1;
82         This_Server->hops = 0;
83
84         gethostname( This_Server->host, CLIENT_HOST_LEN );
85         h = gethostbyname( This_Server->host );
86         if( h ) strcpy( This_Server->host, h->h_name );
87
88         strcpy( This_Server->id, Conf_ServerName );
89         strcpy( This_Server->info, Conf_ServerInfo );
90
91         My_Clients = This_Server;
92 } /* Client_Init */
93
94
95 GLOBAL VOID Client_Exit( VOID )
96 {
97         CLIENT *c, *next;
98         INT cnt;
99
100         Client_Destroy( This_Server, "Server going down.", NULL, FALSE );
101         
102         cnt = 0;
103         c = My_Clients;
104         while( c )
105         {
106                 cnt++;
107                 next = c->next;
108                 free( c );
109                 c = next;
110         }
111         if( cnt ) Log( LOG_INFO, "Freed %d client structure%s.", cnt, cnt == 1 ? "" : "s" );
112 } /* Client_Exit */
113
114
115 GLOBAL CLIENT *Client_ThisServer( VOID )
116 {
117         return This_Server;
118 } /* Client_ThisServer */
119
120
121 GLOBAL CLIENT *Client_NewLocal( CONN_ID Idx, CHAR *Hostname, INT Type, BOOLEAN Idented )
122 {
123         /* Neuen lokalen Client erzeugen: Wrapper-Funktion fuer Client_New(). */
124         return Client_New( Idx, This_Server, NULL, Type, NULL, NULL, Hostname, NULL, 0, 0, NULL, Idented );
125 } /* Client_NewLocal */
126
127
128 GLOBAL CLIENT *Client_NewRemoteServer( CLIENT *Introducer, CHAR *Hostname, CLIENT *TopServer, INT Hops, INT Token, CHAR *Info, BOOLEAN Idented )
129 {
130         /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
131         return Client_New( NONE, Introducer, TopServer, CLIENT_SERVER, Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented );
132 } /* Client_NewRemoteServer */
133
134
135 GLOBAL CLIENT *Client_NewRemoteUser( CLIENT *Introducer, CHAR *Nick, INT Hops, CHAR *User, CHAR *Hostname, INT Token, CHAR *Modes, CHAR *Info, BOOLEAN Idented )
136 {
137         /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
138         return Client_New( NONE, Introducer, NULL, CLIENT_USER, Nick, User, Hostname, Info, Hops, Token, Modes, Idented );
139 } /* Client_NewRemoteUser */
140
141
142 GLOBAL CLIENT *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, BOOLEAN Idented )
143 {
144         CLIENT *client;
145
146         assert( Idx >= NONE );
147         assert( Introducer != NULL );
148         assert( Hostname != NULL );
149
150         client = New_Client_Struct( );
151         if( ! client ) return NULL;
152
153         /* Initialisieren */
154         client->conn_id = Idx;
155         client->introducer = Introducer;
156         client->topserver = TopServer;
157         client->type = Type;
158         if( ID ) Client_SetID( client, ID );
159         if( User ) Client_SetUser( client, User, Idented );
160         if( Hostname ) Client_SetHostname( client, Hostname );
161         if( Info ) Client_SetInfo( client, Info );
162         client->hops = Hops;
163         client->token = Token;
164         if( Modes ) Client_SetModes( client, Modes );
165         if( Type == CLIENT_SERVER ) Generate_MyToken( client );
166
167         /* ist der User away? */
168         if( strchr( client->modes, 'a' )) strcpy( client->away, DEFAULT_AWAY_MSG );
169
170         /* Verketten */
171         client->next = My_Clients;
172         My_Clients = client;
173
174         return client;
175 } /* Client_New */
176
177
178 GLOBAL VOID Client_Destroy( CLIENT *Client, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN SendQuit )
179 {
180         /* Client entfernen. */
181         
182         CLIENT *last, *c;
183         CHAR msg[LINE_LEN], *txt;
184
185         assert( Client != NULL );
186
187         if( LogMsg ) txt = LogMsg;
188         else txt = FwdMsg;
189         if( ! txt ) txt = "Reason unknown.";
190
191         /* Netz-Split-Nachricht vorbereiten (noch nicht optimal) */
192         if( Client->type == CLIENT_SERVER ) sprintf( msg, "%s: lost server %s", This_Server->id, Client->id );
193
194         last = NULL;
195         c = My_Clients;
196         while( c )
197         {
198                 if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
199                 {
200                         /* der Client, der geloescht wird ist ein Server. Der Client, den wir gerade
201                          * pruefen, ist ein Child von diesem und muss daher auch entfernt werden */
202                         Client_Destroy( c, NULL, msg, FALSE );
203                         last = NULL;
204                         c = My_Clients;
205                         continue;
206                 }
207                 if( c == Client )
208                 {
209                         /* Wir haben den Client gefunden: entfernen */
210                         if( last ) last->next = c->next;
211                         else My_Clients = c->next;
212
213                         if( c->type == CLIENT_USER )
214                         {
215                                 if( c->conn_id != NONE )
216                                 {
217                                         /* Ein lokaler User */
218                                         Log( LOG_NOTICE, "User \"%s\" unregistered (connection %d): %s", Client_Mask( c ), c->conn_id, txt );
219
220                                         if( SendQuit )
221                                         {
222                                                 /* Alle andere Server informieren! */
223                                                 if( FwdMsg ) IRC_WriteStrServersPrefix( NULL, c, "QUIT :%s", FwdMsg );
224                                                 else IRC_WriteStrServersPrefix( NULL, c, "QUIT :" );
225                                         }
226                                 }
227                                 else
228                                 {
229                                         /* Remote User */
230                                         Log( LOG_DEBUG, "User \"%s\" unregistered: %s", Client_Mask( c ), txt );
231
232                                         if( SendQuit )
233                                         {
234                                                 /* Andere Server informieren, ausser denen, die "in
235                                                  * Richtung dem liegen", auf dem der User registriert
236                                                  * ist. Von denen haben wir das QUIT ja wohl bekommen. */
237                                                 if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :%s", FwdMsg );
238                                                 else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :" );
239                                         }
240                                 }
241                                 Channel_RemoveClient( c, FwdMsg ? FwdMsg : c->id );
242                         }
243                         else if( c->type == CLIENT_SERVER )
244                         {
245                                 if( c != This_Server )
246                                 {
247                                         if( c->conn_id != NONE ) Log( LOG_NOTICE, "Server \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
248                                         else Log( LOG_NOTICE, "Server \"%s\" unregistered: %s", c->id, txt );
249                                 }
250
251                                 /* andere Server informieren */
252                                 if( ! NGIRCd_Quit )
253                                 {
254                                         if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
255                                         else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :", c->id );
256                                 }
257                         }
258                         else
259                         {
260                                 if( c->conn_id != NONE )
261                                 {
262                                         if( c->id[0] ) Log( LOG_NOTICE, "Client \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
263                                         else Log( LOG_NOTICE, "Client unregistered (connection %d): %s", c->conn_id, txt );
264                                 }
265                                 else
266                                 {
267                                         if( c->id[0] ) Log( LOG_WARNING, "Unregistered unknown client \"%s\": %s", c->id, txt );
268                                         else Log( LOG_WARNING, "Unregistered unknown client: %s", c->id, txt );
269                                 }
270                         }
271
272                         free( c );
273                         break;
274                 }
275                 last = c;
276                 c = c->next;
277         }
278 } /* Client_Destroy */
279
280
281 GLOBAL VOID Client_SetHostname( CLIENT *Client, CHAR *Hostname )
282 {
283         /* Hostname eines Clients setzen */
284         
285         assert( Client != NULL );
286         assert( Hostname != NULL );
287         
288         strncpy( Client->host, Hostname, CLIENT_HOST_LEN - 1 );
289         Client->host[CLIENT_HOST_LEN - 1] = '\0';
290 } /* Client_SetHostname */
291
292
293 GLOBAL VOID Client_SetID( CLIENT *Client, CHAR *ID )
294 {
295         /* Hostname eines Clients setzen */
296
297         assert( Client != NULL );
298         assert( ID != NULL );
299         
300         strncpy( Client->id, ID, CLIENT_ID_LEN - 1 );
301         Client->id[CLIENT_ID_LEN - 1] = '\0';
302 } /* Client_SetID */
303
304
305 GLOBAL VOID Client_SetUser( CLIENT *Client, CHAR *User, BOOLEAN Idented )
306 {
307         /* Username eines Clients setzen */
308
309         assert( Client != NULL );
310         assert( User != NULL );
311         
312         if( Idented ) strncpy( Client->user, User, CLIENT_USER_LEN - 1 );
313         else
314         {
315                 Client->user[0] = '~';
316                 strncpy( Client->user + 1, User, CLIENT_USER_LEN - 2 );
317         }
318         Client->user[CLIENT_USER_LEN - 1] = '\0';
319 } /* Client_SetUser */
320
321
322 GLOBAL VOID Client_SetInfo( CLIENT *Client, CHAR *Info )
323 {
324         /* Hostname eines Clients setzen */
325
326         assert( Client != NULL );
327         assert( Info != NULL );
328         
329         strncpy( Client->info, Info, CLIENT_INFO_LEN - 1 );
330         Client->info[CLIENT_INFO_LEN - 1] = '\0';
331 } /* Client_SetInfo */
332
333
334 GLOBAL VOID Client_SetModes( CLIENT *Client, CHAR *Modes )
335 {
336         /* Hostname eines Clients setzen */
337
338         assert( Client != NULL );
339         assert( Modes != NULL );
340
341         strncpy( Client->modes, Modes, CLIENT_MODE_LEN - 1 );
342         Client->modes[CLIENT_MODE_LEN - 1] = '\0';
343 } /* Client_SetModes */
344
345
346 GLOBAL VOID Client_SetPassword( CLIENT *Client, CHAR *Pwd )
347 {
348         /* Von einem Client geliefertes Passwort */
349
350         assert( Client != NULL );
351         assert( Pwd != NULL );
352         
353         strncpy( Client->pwd, Pwd, CLIENT_PASS_LEN - 1 );
354         Client->pwd[CLIENT_PASS_LEN - 1] = '\0';
355 } /* Client_SetPassword */
356
357
358 GLOBAL VOID Client_SetAway( CLIENT *Client, CHAR *Txt )
359 {
360         /* Von einem Client gelieferte AWAY-Nachricht */
361
362         assert( Client != NULL );
363
364         if( Txt )
365         {
366                 /* Client AWAY setzen */
367                 strncpy( Client->away, Txt, CLIENT_AWAY_LEN - 1 );
368                 Client->away[CLIENT_AWAY_LEN - 1] = '\0';
369                 Client_ModeAdd( Client, 'a' );
370                 Log( LOG_DEBUG, "User \"%s\" is away: %s", Client_Mask( Client ), Txt );
371         }
372         else
373         {
374                 /* AWAY loeschen */
375                 Client_ModeDel( Client, 'a' );
376                 Log( LOG_DEBUG, "User \"%s\" is no longer away.", Client_Mask( Client ));
377         }
378 } /* Client_SetAway */
379
380
381 GLOBAL VOID Client_SetType( CLIENT *Client, INT Type )
382 {
383         assert( Client != NULL );
384         Client->type = Type;
385         if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
386 } /* Client_SetType */
387
388
389 GLOBAL VOID Client_SetHops( CLIENT *Client, INT Hops )
390 {
391         assert( Client != NULL );
392         Client->hops = Hops;
393 } /* Client_SetHops */
394
395
396 GLOBAL VOID Client_SetToken( CLIENT *Client, INT Token )
397 {
398         assert( Client != NULL );
399         Client->token = Token;
400 } /* Client_SetToken */
401
402
403 GLOBAL VOID Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
404 {
405         assert( Client != NULL );
406         assert( Introducer != NULL );
407         Client->introducer = Introducer;
408 } /* Client_SetIntroducer */
409
410
411 GLOBAL VOID Client_SetOperByMe( CLIENT *Client, BOOLEAN OperByMe )
412 {
413         assert( Client != NULL );
414         Client->oper_by_me = OperByMe;
415 } /* Client_SetOperByMe */
416
417
418 GLOBAL BOOLEAN Client_ModeAdd( CLIENT *Client, CHAR Mode )
419 {
420         /* Mode soll gesetzt werden. TRUE wird geliefert, wenn der
421          * Mode neu gesetzt wurde, FALSE, wenn der Client den Mode
422          * bereits hatte. */
423
424         CHAR x[2];
425         
426         assert( Client != NULL );
427
428         x[0] = Mode; x[1] = '\0';
429         if( ! strchr( Client->modes, x[0] ))
430         {
431                 /* Client hat den Mode noch nicht -> setzen */
432                 strcat( Client->modes, x );
433                 return TRUE;
434         }
435         else return FALSE;
436 } /* Client_ModeAdd */
437
438
439 GLOBAL BOOLEAN Client_ModeDel( CLIENT *Client, CHAR Mode )
440 {
441         /* Mode soll geloescht werden. TRUE wird geliefert, wenn der
442         * Mode entfernt wurde, FALSE, wenn der Client den Mode
443         * ueberhaupt nicht hatte. */
444
445         CHAR x[2], *p;
446
447         assert( Client != NULL );
448
449         x[0] = Mode; x[1] = '\0';
450
451         p = strchr( Client->modes, x[0] );
452         if( ! p ) return FALSE;
453
454         /* Client hat den Mode -> loeschen */
455         while( *p )
456         {
457                 *p = *(p + 1);
458                 p++;
459         }
460         return TRUE;
461 } /* Client_ModeDel */
462
463
464 GLOBAL CLIENT *Client_GetFromConn( CONN_ID Idx )
465 {
466         /* Client-Struktur, die zur lokalen Verbindung Idx gehoert,
467          * liefern. Wird keine gefunden, so wird NULL geliefert. */
468
469         CLIENT *c;
470
471         assert( Idx >= 0 );
472         
473         c = My_Clients;
474         while( c )
475         {
476                 if( c->conn_id == Idx ) return c;
477                 c = c->next;
478         }
479         return NULL;
480 } /* Client_GetFromConn */
481
482
483 GLOBAL CLIENT *Client_GetFromID( CHAR *Nick )
484 {
485         /* Client-Struktur, die den entsprechenden Nick hat, liefern.
486          * Wird keine gefunden, so wird NULL geliefert. */
487
488         CHAR n[CLIENT_ID_LEN], *ptr;
489         CLIENT *c = NULL;
490
491         assert( Nick != NULL );
492
493         /* Nick kopieren und ggf. Host-Mask abschneiden */
494         strncpy( n, Nick, CLIENT_ID_LEN - 1 );
495         n[CLIENT_ID_LEN - 1] = '\0';
496         ptr = strchr( n, '!' );
497         if( ptr ) *ptr = '\0';
498
499         c = My_Clients;
500         while( c )
501         {
502                 if( strcasecmp( c->id, n ) == 0 ) return c;
503                 c = c->next;
504         }
505         return NULL;
506 } /* Client_GetFromID */
507
508
509 GLOBAL CLIENT *Client_GetFromToken( CLIENT *Client, INT Token )
510 {
511         /* Client-Struktur, die den entsprechenden Introducer (=Client)
512          * und das gegebene Token hat, liefern. Wird keine gefunden,
513          * so wird NULL geliefert. */
514
515         CLIENT *c;
516
517         assert( Client != NULL );
518         assert( Token > 0 );
519
520         c = My_Clients;
521         while( c )
522         {
523                 if(( c->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c->token == Token )) return c;
524                 c = c->next;
525         }
526         return NULL;
527 } /* Client_GetFromToken */
528
529
530 GLOBAL INT Client_Type( CLIENT *Client )
531 {
532         assert( Client != NULL );
533         return Client->type;
534 } /* Client_Type */
535
536
537 GLOBAL CONN_ID Client_Conn( CLIENT *Client )
538 {
539         assert( Client != NULL );
540         return Client->conn_id;
541 } /* Client_Conn */
542
543
544 GLOBAL CHAR *Client_ID( CLIENT *Client )
545 {
546         assert( Client != NULL );
547
548 #ifdef DEBUG
549         if( Client->type == CLIENT_USER ) assert( strlen( Client->id ) < CLIENT_NICK_LEN );
550 #endif
551                                                    
552         if( Client->id[0] ) return Client->id;
553         else return "*";
554 } /* Client_ID */
555
556
557 GLOBAL CHAR *Client_Info( CLIENT *Client )
558 {
559         assert( Client != NULL );
560         return Client->info;
561 } /* Client_Info */
562
563
564 GLOBAL CHAR *Client_User( CLIENT *Client )
565 {
566         assert( Client != NULL );
567         if( Client->user ) return Client->user;
568         else return "~";
569 } /* Client_User */
570
571
572 GLOBAL CHAR *Client_Hostname( CLIENT *Client )
573 {
574         assert( Client != NULL );
575         return Client->host;
576 } /* Client_Hostname */
577
578
579 GLOBAL CHAR *Client_Password( CLIENT *Client )
580 {
581         assert( Client != NULL );
582         return Client->pwd;
583 } /* Client_Password */
584
585
586 GLOBAL CHAR *Client_Modes( CLIENT *Client )
587 {
588         assert( Client != NULL );
589         return Client->modes;
590 } /* Client_Modes */
591
592
593 GLOBAL BOOLEAN Client_OperByMe( CLIENT *Client )
594 {
595         assert( Client != NULL );
596         return Client->oper_by_me;
597 } /* Client_OperByMe */
598
599
600 GLOBAL INT Client_Hops( CLIENT *Client )
601 {
602         assert( Client != NULL );
603         return Client->hops;
604 } /* Client_Hops */
605
606
607 GLOBAL INT Client_Token( CLIENT *Client )
608 {
609         assert( Client != NULL );
610         return Client->token;
611 } /* Client_Token */
612
613
614 GLOBAL INT Client_MyToken( CLIENT *Client )
615 {
616         assert( Client != NULL );
617         return Client->mytoken;
618 } /* Client_MyToken */
619
620
621 GLOBAL CLIENT *Client_NextHop( CLIENT *Client )
622 {
623         CLIENT *c;
624         
625         assert( Client != NULL );
626
627         c = Client;
628         while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server )) c = c->introducer;
629         return c;
630 } /* Client_NextHop */
631
632
633 GLOBAL CHAR *Client_Mask( CLIENT *Client )
634 {
635         /* Client-"ID" liefern, wie sie z.B. fuer
636          * Prefixe benoetigt wird. */
637
638         assert( Client != NULL );
639         
640         if( Client->type == CLIENT_SERVER ) return Client->id;
641
642         sprintf( GetID_Buffer, "%s!%s@%s", Client->id, Client->user, Client->host );
643         return GetID_Buffer;
644 } /* Client_Mask */
645
646
647 GLOBAL CLIENT *Client_Introducer( CLIENT *Client )
648 {
649         assert( Client != NULL );
650         return Client->introducer;
651 } /* Client_Introducer */
652
653
654 GLOBAL CLIENT *Client_TopServer( CLIENT *Client )
655 {
656         assert( Client != NULL );
657         return Client->topserver;
658 } /* Client_TopServer */
659
660
661 GLOBAL BOOLEAN Client_HasMode( CLIENT *Client, CHAR Mode )
662 {
663         assert( Client != NULL );
664         return strchr( Client->modes, Mode ) != NULL;
665 } /* Client_HasMode */
666
667
668 GLOBAL CHAR *Client_Away( CLIENT *Client )
669 {
670         /* AWAY-Text liefern */
671
672         assert( Client != NULL );
673         return Client->away;
674 } /* Client_Away */
675
676
677 GLOBAL BOOLEAN Client_CheckNick( CLIENT *Client, CHAR *Nick )
678 {
679         /* Nick ueberpruefen */
680
681         CLIENT *c;
682         
683         assert( Client != NULL );
684         assert( Nick != NULL );
685         
686         /* Nick ungueltig? */
687         if( ! Client_IsValidNick( Nick ))
688         {
689                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
690                 return FALSE;
691         }
692
693         /* Nick bereits vergeben? */
694         c = My_Clients;
695         while( c )
696         {
697                 if( strcasecmp( c->id, Nick ) == 0 )
698                 {
699                         /* den Nick gibt es bereits */
700                         IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
701                         return FALSE;
702                 }
703                 c = c->next;
704         }
705
706         return TRUE;
707 } /* Client_CheckNick */
708
709
710 GLOBAL BOOLEAN Client_CheckID( CLIENT *Client, CHAR *ID )
711 {
712         /* Nick ueberpruefen */
713
714         CHAR str[COMMAND_LEN];
715         CLIENT *c;
716
717         assert( Client != NULL );
718         assert( Client->conn_id > NONE );
719         assert( ID != NULL );
720
721         /* Nick zu lang? */
722         if( strlen( ID ) > CLIENT_ID_LEN )
723         {
724                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), ID );
725                 return FALSE;
726         }
727
728         /* ID bereits vergeben? */
729         c = My_Clients;
730         while( c )
731         {
732                 if( strcasecmp( c->id, ID ) == 0 )
733                 {
734                         /* die Server-ID gibt es bereits */
735                         sprintf( str, "ID \"%s\" already registered!", ID );
736                         Log( LOG_ERR, "%s (on connection %d)", str, Client->conn_id );
737                         Conn_Close( Client->conn_id, str, str, TRUE );
738                         return FALSE;
739                 }
740                 c = c->next;
741         }
742
743         return TRUE;
744 } /* Client_CheckID */
745
746
747 GLOBAL CLIENT *Client_Search( CHAR *ID )
748 {
749         /* Client suchen, auf den ID passt */
750
751         CLIENT *c;
752
753         assert( ID != NULL );
754
755         c = My_Clients;
756         while( c )
757         {
758                 if( strcasecmp( c->id, ID ) == 0 ) return c;
759                 c = c->next;
760         }
761         
762         return NULL;
763 } /* Client_Search */
764
765
766 GLOBAL CLIENT *Client_First( VOID )
767 {
768         /* Ersten Client liefern. */
769
770         return My_Clients;
771 } /* Client_First */
772
773
774 GLOBAL CLIENT *Client_Next( CLIENT *c )
775 {
776         /* Naechsten Client liefern. Existiert keiner,
777          * so wird NULL geliefert. */
778
779         assert( c != NULL );
780         return c->next;
781 } /* Client_Next */
782
783
784 GLOBAL INT Client_UserCount( VOID )
785 {
786         return Count( CLIENT_USER );
787 } /* Client_UserCount */
788
789
790 GLOBAL INT Client_ServiceCount( VOID )
791 {
792         return Count( CLIENT_SERVICE );;
793 } /* Client_ServiceCount */
794
795
796 GLOBAL INT Client_ServerCount( VOID )
797 {
798         return Count( CLIENT_SERVER );
799 } /* Client_ServerCount */
800
801
802 GLOBAL INT Client_MyUserCount( VOID )
803 {
804         return MyCount( CLIENT_USER );
805 } /* Client_MyUserCount */
806
807
808 GLOBAL INT Client_MyServiceCount( VOID )
809 {
810         return MyCount( CLIENT_SERVICE );
811 } /* Client_MyServiceCount */
812
813
814 GLOBAL INT Client_MyServerCount( VOID )
815 {
816         return MyCount( CLIENT_SERVER );
817 } /* Client_MyServerCount */
818
819
820 GLOBAL INT Client_OperCount( VOID )
821 {
822         CLIENT *c;
823         INT cnt;
824
825         cnt = 0;
826         c = My_Clients;
827         while( c )
828         {
829                 if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++;
830                 c = c->next;
831         }
832         return cnt;
833 } /* Client_OperCount */
834
835
836 GLOBAL INT Client_UnknownCount( VOID )
837 {
838         CLIENT *c;
839         INT cnt;
840
841         cnt = 0;
842         c = My_Clients;
843         while( c )
844         {
845                 if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
846                 c = c->next;
847         }
848         return cnt;
849 } /* Client_UnknownCount */
850
851
852 GLOBAL BOOLEAN Client_IsValidNick( CHAR *Nick )
853 {
854         /* Ist der Nick gueltig? */
855
856         CHAR *ptr, goodchars[] = ";0123456789-";
857         
858         assert( Nick != NULL );
859
860         if( Nick[0] == '#' ) return FALSE;
861         if( strchr( goodchars, Nick[0] )) return FALSE;
862         if( strlen( Nick ) >= CLIENT_NICK_LEN ) return FALSE;
863
864         ptr = Nick;
865         while( *ptr )
866         {
867                 if(( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return FALSE;
868                 if(( *ptr > '}' ) && ( ! strchr( goodchars, *ptr ))) return FALSE;
869                 ptr++;
870         }
871         
872         return TRUE;
873 } /* Client_IsValidNick */
874
875
876 LOCAL INT Count( CLIENT_TYPE Type )
877 {
878         CLIENT *c;
879         INT cnt;
880
881         cnt = 0;
882         c = My_Clients;
883         while( c )
884         {
885                 if( c && ( c->type == Type )) cnt++;
886                 c = c->next;
887         }
888         return cnt;
889 } /* Count */
890
891
892 LOCAL INT MyCount( CLIENT_TYPE Type )
893 {
894         CLIENT *c;
895         INT cnt;
896
897         cnt = 0;
898         c = My_Clients;
899         while( c )
900         {
901                 if( c && ( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
902                 c = c->next;
903         }
904         return cnt;
905 } /* MyCount */
906
907
908 LOCAL CLIENT *New_Client_Struct( VOID )
909 {
910         /* Neue CLIENT-Struktur pre-initialisieren */
911         
912         CLIENT *c;
913         
914         c = malloc( sizeof( CLIENT ));
915         if( ! c )
916         {
917                 Log( LOG_EMERG, "Can't allocate memory!" );
918                 return NULL;
919         }
920
921         c->next = NULL;
922         c->type = CLIENT_UNKNOWN;
923         c->conn_id = NONE;
924         c->introducer = NULL;
925         c->topserver = NULL;
926         strcpy( c->id, "" );
927         strcpy( c->pwd, "" );
928         strcpy( c->host, "" );
929         strcpy( c->user, "" );
930         strcpy( c->info, "" );
931         strcpy( c->modes, "" );
932         c->oper_by_me = FALSE;
933         c->hops = -1;
934         c->token = -1;
935         c->mytoken = -1;
936         strcpy( c->away, "" );
937
938         return c;
939 } /* New_Client */
940
941
942 LOCAL VOID Generate_MyToken( CLIENT *Client )
943 {
944         CLIENT *c;
945         INT token;
946
947         c = My_Clients;
948         token = 2;
949         while( c )
950         {
951                 if( c->mytoken == token )
952                 {
953                         /* Das Token wurde bereits vergeben */
954                         token++;
955                         c = My_Clients;
956                         continue;
957                 }
958                 else c = c->next;
959         }
960         Client->mytoken = token;
961         Log( LOG_DEBUG, "Assigned token %d to server \"%s\".", token, Client->id );
962 } /* Generate_MyToken */
963
964
965 /* -eof- */