]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/client.c
- externe portab-Header werden nicht mehr benoetigt/benutzt, dadurch
[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.48 2002/03/12 14:37:52 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         if( Client->type == CLIENT_SERVER )
192         {
193                 /* Netz-Split-Nachricht vorbereiten */
194                 sprintf( msg, "%s | %s", Client_ID( Client ), Client_ID( Client_TopServer( Client ) ? Client_TopServer( Client ) : Client_ThisServer( )));
195         }
196
197         last = NULL;
198         c = My_Clients;
199         while( c )
200         {
201                 if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
202                 {
203                         /* der Client, der geloescht wird ist ein Server. Der Client, den wir gerade
204                          * pruefen, ist ein Child von diesem und muss daher auch entfernt werden */
205                         Client_Destroy( c, NULL, msg, FALSE );
206                         last = NULL;
207                         c = My_Clients;
208                         continue;
209                 }
210                 if( c == Client )
211                 {
212                         /* Wir haben den Client gefunden: entfernen */
213                         if( last ) last->next = c->next;
214                         else My_Clients = c->next;
215
216                         if( c->type == CLIENT_USER )
217                         {
218                                 if( c->conn_id != NONE )
219                                 {
220                                         /* Ein lokaler User */
221                                         Log( LOG_NOTICE, "User \"%s\" unregistered (connection %d): %s", Client_Mask( c ), c->conn_id, txt );
222
223                                         if( SendQuit )
224                                         {
225                                                 /* Alle andere Server informieren! */
226                                                 if( FwdMsg ) IRC_WriteStrServersPrefix( NULL, c, "QUIT :%s", FwdMsg );
227                                                 else IRC_WriteStrServersPrefix( NULL, c, "QUIT :" );
228                                         }
229                                 }
230                                 else
231                                 {
232                                         /* Remote User */
233                                         Log( LOG_DEBUG, "User \"%s\" unregistered: %s", Client_Mask( c ), txt );
234
235                                         if( SendQuit )
236                                         {
237                                                 /* Andere Server informieren, ausser denen, die "in
238                                                  * Richtung dem liegen", auf dem der User registriert
239                                                  * ist. Von denen haben wir das QUIT ja wohl bekommen. */
240                                                 if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :%s", FwdMsg );
241                                                 else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :" );
242                                         }
243                                 }
244                                 Channel_RemoveClient( c, FwdMsg ? FwdMsg : c->id );
245                         }
246                         else if( c->type == CLIENT_SERVER )
247                         {
248                                 if( c != This_Server )
249                                 {
250                                         if( c->conn_id != NONE ) Log( LOG_NOTICE, "Server \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
251                                         else Log( LOG_NOTICE, "Server \"%s\" unregistered: %s", c->id, txt );
252                                 }
253
254                                 /* andere Server informieren */
255                                 if( ! NGIRCd_Quit )
256                                 {
257                                         if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
258                                         else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :", c->id );
259                                 }
260                         }
261                         else
262                         {
263                                 if( c->conn_id != NONE )
264                                 {
265                                         if( c->id[0] ) Log( LOG_NOTICE, "Client \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
266                                         else Log( LOG_NOTICE, "Client unregistered (connection %d): %s", c->conn_id, txt );
267                                 }
268                                 else
269                                 {
270                                         if( c->id[0] ) Log( LOG_WARNING, "Unregistered unknown client \"%s\": %s", c->id, txt );
271                                         else Log( LOG_WARNING, "Unregistered unknown client: %s", c->id, txt );
272                                 }
273                         }
274
275                         free( c );
276                         break;
277                 }
278                 last = c;
279                 c = c->next;
280         }
281 } /* Client_Destroy */
282
283
284 GLOBAL VOID Client_SetHostname( CLIENT *Client, CHAR *Hostname )
285 {
286         /* Hostname eines Clients setzen */
287         
288         assert( Client != NULL );
289         assert( Hostname != NULL );
290         
291         strncpy( Client->host, Hostname, CLIENT_HOST_LEN - 1 );
292         Client->host[CLIENT_HOST_LEN - 1] = '\0';
293 } /* Client_SetHostname */
294
295
296 GLOBAL VOID Client_SetID( CLIENT *Client, CHAR *ID )
297 {
298         /* Hostname eines Clients setzen */
299
300         assert( Client != NULL );
301         assert( ID != NULL );
302         
303         strncpy( Client->id, ID, CLIENT_ID_LEN - 1 );
304         Client->id[CLIENT_ID_LEN - 1] = '\0';
305 } /* Client_SetID */
306
307
308 GLOBAL VOID Client_SetUser( CLIENT *Client, CHAR *User, BOOLEAN Idented )
309 {
310         /* Username eines Clients setzen */
311
312         assert( Client != NULL );
313         assert( User != NULL );
314         
315         if( Idented ) strncpy( Client->user, User, CLIENT_USER_LEN - 1 );
316         else
317         {
318                 Client->user[0] = '~';
319                 strncpy( Client->user + 1, User, CLIENT_USER_LEN - 2 );
320         }
321         Client->user[CLIENT_USER_LEN - 1] = '\0';
322 } /* Client_SetUser */
323
324
325 GLOBAL VOID Client_SetInfo( CLIENT *Client, CHAR *Info )
326 {
327         /* Hostname eines Clients setzen */
328
329         assert( Client != NULL );
330         assert( Info != NULL );
331         
332         strncpy( Client->info, Info, CLIENT_INFO_LEN - 1 );
333         Client->info[CLIENT_INFO_LEN - 1] = '\0';
334 } /* Client_SetInfo */
335
336
337 GLOBAL VOID Client_SetModes( CLIENT *Client, CHAR *Modes )
338 {
339         /* Hostname eines Clients setzen */
340
341         assert( Client != NULL );
342         assert( Modes != NULL );
343
344         strncpy( Client->modes, Modes, CLIENT_MODE_LEN - 1 );
345         Client->modes[CLIENT_MODE_LEN - 1] = '\0';
346 } /* Client_SetModes */
347
348
349 GLOBAL VOID Client_SetPassword( CLIENT *Client, CHAR *Pwd )
350 {
351         /* Von einem Client geliefertes Passwort */
352
353         assert( Client != NULL );
354         assert( Pwd != NULL );
355         
356         strncpy( Client->pwd, Pwd, CLIENT_PASS_LEN - 1 );
357         Client->pwd[CLIENT_PASS_LEN - 1] = '\0';
358 } /* Client_SetPassword */
359
360
361 GLOBAL VOID Client_SetAway( CLIENT *Client, CHAR *Txt )
362 {
363         /* Von einem Client gelieferte AWAY-Nachricht */
364
365         assert( Client != NULL );
366
367         if( Txt )
368         {
369                 /* Client AWAY setzen */
370                 strncpy( Client->away, Txt, CLIENT_AWAY_LEN - 1 );
371                 Client->away[CLIENT_AWAY_LEN - 1] = '\0';
372                 Client_ModeAdd( Client, 'a' );
373                 Log( LOG_DEBUG, "User \"%s\" is away: %s", Client_Mask( Client ), Txt );
374         }
375         else
376         {
377                 /* AWAY loeschen */
378                 Client_ModeDel( Client, 'a' );
379                 Log( LOG_DEBUG, "User \"%s\" is no longer away.", Client_Mask( Client ));
380         }
381 } /* Client_SetAway */
382
383
384 GLOBAL VOID Client_SetType( CLIENT *Client, INT Type )
385 {
386         assert( Client != NULL );
387         Client->type = Type;
388         if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
389 } /* Client_SetType */
390
391
392 GLOBAL VOID Client_SetHops( CLIENT *Client, INT Hops )
393 {
394         assert( Client != NULL );
395         Client->hops = Hops;
396 } /* Client_SetHops */
397
398
399 GLOBAL VOID Client_SetToken( CLIENT *Client, INT Token )
400 {
401         assert( Client != NULL );
402         Client->token = Token;
403 } /* Client_SetToken */
404
405
406 GLOBAL VOID Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
407 {
408         assert( Client != NULL );
409         assert( Introducer != NULL );
410         Client->introducer = Introducer;
411 } /* Client_SetIntroducer */
412
413
414 GLOBAL VOID Client_SetOperByMe( CLIENT *Client, BOOLEAN OperByMe )
415 {
416         assert( Client != NULL );
417         Client->oper_by_me = OperByMe;
418 } /* Client_SetOperByMe */
419
420
421 GLOBAL BOOLEAN Client_ModeAdd( CLIENT *Client, CHAR Mode )
422 {
423         /* Mode soll gesetzt werden. TRUE wird geliefert, wenn der
424          * Mode neu gesetzt wurde, FALSE, wenn der Client den Mode
425          * bereits hatte. */
426
427         CHAR x[2];
428         
429         assert( Client != NULL );
430
431         x[0] = Mode; x[1] = '\0';
432         if( ! strchr( Client->modes, x[0] ))
433         {
434                 /* Client hat den Mode noch nicht -> setzen */
435                 strcat( Client->modes, x );
436                 return TRUE;
437         }
438         else return FALSE;
439 } /* Client_ModeAdd */
440
441
442 GLOBAL BOOLEAN Client_ModeDel( CLIENT *Client, CHAR Mode )
443 {
444         /* Mode soll geloescht werden. TRUE wird geliefert, wenn der
445         * Mode entfernt wurde, FALSE, wenn der Client den Mode
446         * ueberhaupt nicht hatte. */
447
448         CHAR x[2], *p;
449
450         assert( Client != NULL );
451
452         x[0] = Mode; x[1] = '\0';
453
454         p = strchr( Client->modes, x[0] );
455         if( ! p ) return FALSE;
456
457         /* Client hat den Mode -> loeschen */
458         while( *p )
459         {
460                 *p = *(p + 1);
461                 p++;
462         }
463         return TRUE;
464 } /* Client_ModeDel */
465
466
467 GLOBAL CLIENT *Client_GetFromConn( CONN_ID Idx )
468 {
469         /* Client-Struktur, die zur lokalen Verbindung Idx gehoert,
470          * liefern. Wird keine gefunden, so wird NULL geliefert. */
471
472         CLIENT *c;
473
474         assert( Idx >= 0 );
475         
476         c = My_Clients;
477         while( c )
478         {
479                 if( c->conn_id == Idx ) return c;
480                 c = c->next;
481         }
482         return NULL;
483 } /* Client_GetFromConn */
484
485
486 GLOBAL CLIENT *Client_GetFromID( CHAR *Nick )
487 {
488         /* Client-Struktur, die den entsprechenden Nick hat, liefern.
489          * Wird keine gefunden, so wird NULL geliefert. */
490
491         CHAR n[CLIENT_ID_LEN], *ptr;
492         CLIENT *c = NULL;
493
494         assert( Nick != NULL );
495
496         /* Nick kopieren und ggf. Host-Mask abschneiden */
497         strncpy( n, Nick, CLIENT_ID_LEN - 1 );
498         n[CLIENT_ID_LEN - 1] = '\0';
499         ptr = strchr( n, '!' );
500         if( ptr ) *ptr = '\0';
501
502         c = My_Clients;
503         while( c )
504         {
505                 if( strcasecmp( c->id, n ) == 0 ) return c;
506                 c = c->next;
507         }
508         return NULL;
509 } /* Client_GetFromID */
510
511
512 GLOBAL CLIENT *Client_GetFromToken( CLIENT *Client, INT Token )
513 {
514         /* Client-Struktur, die den entsprechenden Introducer (=Client)
515          * und das gegebene Token hat, liefern. Wird keine gefunden,
516          * so wird NULL geliefert. */
517
518         CLIENT *c;
519
520         assert( Client != NULL );
521         assert( Token > 0 );
522
523         c = My_Clients;
524         while( c )
525         {
526                 if(( c->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c->token == Token )) return c;
527                 c = c->next;
528         }
529         return NULL;
530 } /* Client_GetFromToken */
531
532
533 GLOBAL INT Client_Type( CLIENT *Client )
534 {
535         assert( Client != NULL );
536         return Client->type;
537 } /* Client_Type */
538
539
540 GLOBAL CONN_ID Client_Conn( CLIENT *Client )
541 {
542         assert( Client != NULL );
543         return Client->conn_id;
544 } /* Client_Conn */
545
546
547 GLOBAL CHAR *Client_ID( CLIENT *Client )
548 {
549         assert( Client != NULL );
550
551 #ifdef DEBUG
552         if( Client->type == CLIENT_USER ) assert( strlen( Client->id ) < CLIENT_NICK_LEN );
553 #endif
554                                                    
555         if( Client->id[0] ) return Client->id;
556         else return "*";
557 } /* Client_ID */
558
559
560 GLOBAL CHAR *Client_Info( CLIENT *Client )
561 {
562         assert( Client != NULL );
563         return Client->info;
564 } /* Client_Info */
565
566
567 GLOBAL CHAR *Client_User( CLIENT *Client )
568 {
569         assert( Client != NULL );
570         if( Client->user ) return Client->user;
571         else return "~";
572 } /* Client_User */
573
574
575 GLOBAL CHAR *Client_Hostname( CLIENT *Client )
576 {
577         assert( Client != NULL );
578         return Client->host;
579 } /* Client_Hostname */
580
581
582 GLOBAL CHAR *Client_Password( CLIENT *Client )
583 {
584         assert( Client != NULL );
585         return Client->pwd;
586 } /* Client_Password */
587
588
589 GLOBAL CHAR *Client_Modes( CLIENT *Client )
590 {
591         assert( Client != NULL );
592         return Client->modes;
593 } /* Client_Modes */
594
595
596 GLOBAL BOOLEAN Client_OperByMe( CLIENT *Client )
597 {
598         assert( Client != NULL );
599         return Client->oper_by_me;
600 } /* Client_OperByMe */
601
602
603 GLOBAL INT Client_Hops( CLIENT *Client )
604 {
605         assert( Client != NULL );
606         return Client->hops;
607 } /* Client_Hops */
608
609
610 GLOBAL INT Client_Token( CLIENT *Client )
611 {
612         assert( Client != NULL );
613         return Client->token;
614 } /* Client_Token */
615
616
617 GLOBAL INT Client_MyToken( CLIENT *Client )
618 {
619         assert( Client != NULL );
620         return Client->mytoken;
621 } /* Client_MyToken */
622
623
624 GLOBAL CLIENT *Client_NextHop( CLIENT *Client )
625 {
626         CLIENT *c;
627         
628         assert( Client != NULL );
629
630         c = Client;
631         while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server )) c = c->introducer;
632         return c;
633 } /* Client_NextHop */
634
635
636 GLOBAL CHAR *Client_Mask( CLIENT *Client )
637 {
638         /* Client-"ID" liefern, wie sie z.B. fuer
639          * Prefixe benoetigt wird. */
640
641         assert( Client != NULL );
642         
643         if( Client->type == CLIENT_SERVER ) return Client->id;
644
645         sprintf( GetID_Buffer, "%s!%s@%s", Client->id, Client->user, Client->host );
646         return GetID_Buffer;
647 } /* Client_Mask */
648
649
650 GLOBAL CLIENT *Client_Introducer( CLIENT *Client )
651 {
652         assert( Client != NULL );
653         return Client->introducer;
654 } /* Client_Introducer */
655
656
657 GLOBAL CLIENT *Client_TopServer( CLIENT *Client )
658 {
659         assert( Client != NULL );
660         return Client->topserver;
661 } /* Client_TopServer */
662
663
664 GLOBAL BOOLEAN Client_HasMode( CLIENT *Client, CHAR Mode )
665 {
666         assert( Client != NULL );
667         return strchr( Client->modes, Mode ) != NULL;
668 } /* Client_HasMode */
669
670
671 GLOBAL CHAR *Client_Away( CLIENT *Client )
672 {
673         /* AWAY-Text liefern */
674
675         assert( Client != NULL );
676         return Client->away;
677 } /* Client_Away */
678
679
680 GLOBAL BOOLEAN Client_CheckNick( CLIENT *Client, CHAR *Nick )
681 {
682         /* Nick ueberpruefen */
683
684         CLIENT *c;
685         
686         assert( Client != NULL );
687         assert( Nick != NULL );
688         
689         /* Nick ungueltig? */
690         if( ! Client_IsValidNick( Nick ))
691         {
692                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
693                 return FALSE;
694         }
695
696         /* Nick bereits vergeben? */
697         c = My_Clients;
698         while( c )
699         {
700                 if( strcasecmp( c->id, Nick ) == 0 )
701                 {
702                         /* den Nick gibt es bereits */
703                         IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
704                         return FALSE;
705                 }
706                 c = c->next;
707         }
708
709         return TRUE;
710 } /* Client_CheckNick */
711
712
713 GLOBAL BOOLEAN Client_CheckID( CLIENT *Client, CHAR *ID )
714 {
715         /* Nick ueberpruefen */
716
717         CHAR str[COMMAND_LEN];
718         CLIENT *c;
719
720         assert( Client != NULL );
721         assert( Client->conn_id > NONE );
722         assert( ID != NULL );
723
724         /* Nick zu lang? */
725         if( strlen( ID ) > CLIENT_ID_LEN )
726         {
727                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), ID );
728                 return FALSE;
729         }
730
731         /* ID bereits vergeben? */
732         c = My_Clients;
733         while( c )
734         {
735                 if( strcasecmp( c->id, ID ) == 0 )
736                 {
737                         /* die Server-ID gibt es bereits */
738                         sprintf( str, "ID \"%s\" already registered!", ID );
739                         Log( LOG_ERR, "%s (on connection %d)", str, Client->conn_id );
740                         Conn_Close( Client->conn_id, str, str, TRUE );
741                         return FALSE;
742                 }
743                 c = c->next;
744         }
745
746         return TRUE;
747 } /* Client_CheckID */
748
749
750 GLOBAL CLIENT *Client_Search( CHAR *ID )
751 {
752         /* Client suchen, auf den ID passt */
753
754         CLIENT *c;
755
756         assert( ID != NULL );
757
758         c = My_Clients;
759         while( c )
760         {
761                 if( strcasecmp( c->id, ID ) == 0 ) return c;
762                 c = c->next;
763         }
764         
765         return NULL;
766 } /* Client_Search */
767
768
769 GLOBAL CLIENT *Client_First( VOID )
770 {
771         /* Ersten Client liefern. */
772
773         return My_Clients;
774 } /* Client_First */
775
776
777 GLOBAL CLIENT *Client_Next( CLIENT *c )
778 {
779         /* Naechsten Client liefern. Existiert keiner,
780          * so wird NULL geliefert. */
781
782         assert( c != NULL );
783         return c->next;
784 } /* Client_Next */
785
786
787 GLOBAL INT Client_UserCount( VOID )
788 {
789         return Count( CLIENT_USER );
790 } /* Client_UserCount */
791
792
793 GLOBAL INT Client_ServiceCount( VOID )
794 {
795         return Count( CLIENT_SERVICE );;
796 } /* Client_ServiceCount */
797
798
799 GLOBAL INT Client_ServerCount( VOID )
800 {
801         return Count( CLIENT_SERVER );
802 } /* Client_ServerCount */
803
804
805 GLOBAL INT Client_MyUserCount( VOID )
806 {
807         return MyCount( CLIENT_USER );
808 } /* Client_MyUserCount */
809
810
811 GLOBAL INT Client_MyServiceCount( VOID )
812 {
813         return MyCount( CLIENT_SERVICE );
814 } /* Client_MyServiceCount */
815
816
817 GLOBAL INT Client_MyServerCount( VOID )
818 {
819         return MyCount( CLIENT_SERVER );
820 } /* Client_MyServerCount */
821
822
823 GLOBAL INT Client_OperCount( VOID )
824 {
825         CLIENT *c;
826         INT cnt;
827
828         cnt = 0;
829         c = My_Clients;
830         while( c )
831         {
832                 if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++;
833                 c = c->next;
834         }
835         return cnt;
836 } /* Client_OperCount */
837
838
839 GLOBAL INT Client_UnknownCount( VOID )
840 {
841         CLIENT *c;
842         INT cnt;
843
844         cnt = 0;
845         c = My_Clients;
846         while( c )
847         {
848                 if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
849                 c = c->next;
850         }
851         return cnt;
852 } /* Client_UnknownCount */
853
854
855 GLOBAL BOOLEAN Client_IsValidNick( CHAR *Nick )
856 {
857         /* Ist der Nick gueltig? */
858
859         CHAR *ptr, goodchars[] = ";0123456789-";
860         
861         assert( Nick != NULL );
862
863         if( Nick[0] == '#' ) return FALSE;
864         if( strchr( goodchars, Nick[0] )) return FALSE;
865         if( strlen( Nick ) >= CLIENT_NICK_LEN ) return FALSE;
866
867         ptr = Nick;
868         while( *ptr )
869         {
870                 if(( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return FALSE;
871                 if(( *ptr > '}' ) && ( ! strchr( goodchars, *ptr ))) return FALSE;
872                 ptr++;
873         }
874         
875         return TRUE;
876 } /* Client_IsValidNick */
877
878
879 LOCAL INT Count( CLIENT_TYPE Type )
880 {
881         CLIENT *c;
882         INT cnt;
883
884         cnt = 0;
885         c = My_Clients;
886         while( c )
887         {
888                 if( c && ( c->type == Type )) cnt++;
889                 c = c->next;
890         }
891         return cnt;
892 } /* Count */
893
894
895 LOCAL INT MyCount( CLIENT_TYPE Type )
896 {
897         CLIENT *c;
898         INT cnt;
899
900         cnt = 0;
901         c = My_Clients;
902         while( c )
903         {
904                 if( c && ( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
905                 c = c->next;
906         }
907         return cnt;
908 } /* MyCount */
909
910
911 LOCAL CLIENT *New_Client_Struct( VOID )
912 {
913         /* Neue CLIENT-Struktur pre-initialisieren */
914         
915         CLIENT *c;
916         
917         c = malloc( sizeof( CLIENT ));
918         if( ! c )
919         {
920                 Log( LOG_EMERG, "Can't allocate memory!" );
921                 return NULL;
922         }
923
924         c->next = NULL;
925         c->type = CLIENT_UNKNOWN;
926         c->conn_id = NONE;
927         c->introducer = NULL;
928         c->topserver = NULL;
929         strcpy( c->id, "" );
930         strcpy( c->pwd, "" );
931         strcpy( c->host, "" );
932         strcpy( c->user, "" );
933         strcpy( c->info, "" );
934         strcpy( c->modes, "" );
935         c->oper_by_me = FALSE;
936         c->hops = -1;
937         c->token = -1;
938         c->mytoken = -1;
939         strcpy( c->away, "" );
940
941         return c;
942 } /* New_Client */
943
944
945 LOCAL VOID Generate_MyToken( CLIENT *Client )
946 {
947         CLIENT *c;
948         INT token;
949
950         c = My_Clients;
951         token = 2;
952         while( c )
953         {
954                 if( c->mytoken == token )
955                 {
956                         /* Das Token wurde bereits vergeben */
957                         token++;
958                         c = My_Clients;
959                         continue;
960                 }
961                 else c = c->next;
962         }
963         Client->mytoken = token;
964         Log( LOG_DEBUG, "Assigned token %d to server \"%s\".", token, Client->id );
965 } /* Generate_MyToken */
966
967
968 /* -eof- */