]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/client.c
138148617064fc6d46f675ef2c8e10db852c7456
[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.27 2002/01/09 01:08:08 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  * $Log: client.c,v $
24  * Revision 1.27  2002/01/09 01:08:08  alex
25  * - wird ein Server abgemeldet, so wird anderen Server ein SQUIT geschickt.
26  *
27  * Revision 1.26  2002/01/07 23:42:12  alex
28  * - Es werden fuer alle Server eigene Token generiert,
29  * - QUIT von einem Server fuer einen User wird an andere Server geforwarded,
30  * - ebenso NICK-Befehle, die "fremde" User einfuehren.
31  *
32  * Revision 1.25  2002/01/07 15:31:00  alex
33  * - Bei Log-Meldungen ueber Clients wird nun immer die "Client Mask" verwendet.
34  *
35  * Revision 1.24  2002/01/06 15:18:14  alex
36  * - Loglevel und Meldungen nochmals geaendert. Level passen nun besser.
37  *
38  * Revision 1.23  2002/01/05 23:26:05  alex
39  * - Vorbereitungen fuer Ident-Abfragen in Client-Strukturen.
40  *
41  * Revision 1.22  2002/01/05 20:08:17  alex
42  * - neue Funktion Client_NextHop().
43  *
44  * Revision 1.21  2002/01/05 19:15:03  alex
45  * - Fehlerpruefung bei select() in der "Hauptschleife" korrigiert.
46  *
47  * Revision 1.20  2002/01/04 17:57:08  alex
48  * - Client_Destroy() an Server-Links angepasst.
49  *
50  * Revision 1.19  2002/01/04 01:21:22  alex
51  * - Client-Strukturen koennen von anderen Modulen nun nur noch ueber die
52  *   enstprechenden (zum Teil neuen) Funktionen angesprochen werden.
53  *
54  * Revision 1.18  2002/01/03 02:28:06  alex
55  * - neue Funktion Client_CheckID(), diverse Aenderungen fuer Server-Links.
56  *
57  * Revision 1.17  2002/01/02 02:42:58  alex
58  * - Copyright-Texte aktualisiert.
59  *
60  * Revision 1.16  2002/01/01 18:25:44  alex
61  * - #include's fuer stdlib.h ergaenzt.
62  *
63  * Revision 1.15  2001/12/31 15:33:13  alex
64  * - neuer Befehl NAMES, kleinere Bugfixes.
65  * - Bug bei PING behoben: war zu restriktiv implementiert :-)
66  *
67  * Revision 1.14  2001/12/31 02:18:51  alex
68  * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
69  * - neuen Header "defines.h" mit (fast) allen Konstanten.
70  * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
71  *
72  * Revision 1.13  2001/12/30 19:26:11  alex
73  * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
74  *
75  * Revision 1.12  2001/12/29 20:18:18  alex
76  * - neue Funktion Client_SetHostname().
77  *
78  * Revision 1.11  2001/12/29 03:10:47  alex
79  * - Client-Modes implementiert; Loglevel mal wieder angepasst.
80  *
81  * Revision 1.10  2001/12/27 19:13:47  alex
82  * - neue Funktion Client_Search(), besseres Logging.
83  *
84  * Revision 1.9  2001/12/27 17:15:29  alex
85  * - der eigene Hostname wird nun komplet (als FQDN) ermittelt.
86  *
87  * Revision 1.8  2001/12/27 16:54:51  alex
88  * - neue Funktion Client_GetID(), liefert die "Client ID".
89  *
90  * Revision 1.7  2001/12/26 14:45:37  alex
91  * - "Code Cleanups".
92  *
93  * Revision 1.6  2001/12/26 03:19:16  alex
94  * - neue Funktion Client_Nick().
95  *
96  * Revision 1.5  2001/12/25 22:04:26  alex
97  * - Aenderungen an den Debug- und Logging-Funktionen.
98  *
99  * Revision 1.4  2001/12/25 19:21:26  alex
100  * - Client-Typ ("Status") besser unterteilt, My_Clients ist zudem nun global.
101  *
102  * Revision 1.3  2001/12/24 01:31:14  alex
103  * - einige assert()'s eingestraeut.
104  *
105  * Revision 1.2  2001/12/23 22:04:37  alex
106  * - einige neue Funktionen,
107  * - CLIENT-Struktur erweitert.
108  *
109  * Revision 1.1  2001/12/14 08:13:43  alex
110  * - neues Modul begonnen :-)
111  */
112
113
114 #define __client_c__
115
116
117 #include <portab.h>
118 #include "global.h"
119
120 #include <imp.h>
121 #include <assert.h>
122 #include <unistd.h>
123 #include <stdio.h>
124 #include <stdlib.h>
125 #include <string.h>
126 #include <netdb.h>
127
128 #include <exp.h>
129 #include "client.h"
130
131 #include <imp.h>
132 #include "ngircd.h"
133 #include "channel.h"
134 #include "conf.h"
135 #include "conn.h"
136 #include "irc.h"
137 #include "log.h"
138 #include "messages.h"
139
140 #include <exp.h>
141
142
143 LOCAL CLIENT *This_Server, *My_Clients;
144 LOCAL CHAR GetID_Buffer[CLIENT_ID_LEN];
145
146
147 LOCAL CLIENT *New_Client_Struct( VOID );
148 LOCAL VOID Generate_MyToken( CLIENT *Client );
149
150
151 GLOBAL VOID Client_Init( VOID )
152 {
153         struct hostent *h;
154         
155         This_Server = New_Client_Struct( );
156         if( ! This_Server )
157         {
158                 Log( LOG_EMERG, "Can't allocate client structure for server! Going down." );
159                 Log( LOG_ALERT, PACKAGE" exiting due to fatal errors!" );
160                 exit( 1 );
161         }
162
163         /* Client-Struktur dieses Servers */
164         This_Server->next = NULL;
165         This_Server->type = CLIENT_SERVER;
166         This_Server->conn_id = NONE;
167         This_Server->introducer = This_Server;
168         This_Server->mytoken = 1;
169
170         gethostname( This_Server->host, CLIENT_HOST_LEN );
171         h = gethostbyname( This_Server->host );
172         if( h ) strcpy( This_Server->host, h->h_name );
173
174         strcpy( This_Server->id, Conf_ServerName );
175         strcpy( This_Server->info, Conf_ServerInfo );
176
177         My_Clients = This_Server;
178 } /* Client_Init */
179
180
181 GLOBAL VOID Client_Exit( VOID )
182 {
183         CLIENT *c, *next;
184         INT cnt;
185
186         Client_Destroy( This_Server, "Server going down.", NULL );
187         
188         cnt = 0;
189         c = My_Clients;
190         while( c )
191         {
192                 cnt++;
193                 next = c->next;
194                 free( c );
195                 c = next;
196         }
197         if( cnt ) Log( LOG_INFO, "Freed %d client structure%s.", cnt, cnt == 1 ? "" : "s" );
198 } /* Client_Exit */
199
200
201 GLOBAL CLIENT *Client_ThisServer( VOID )
202 {
203         return This_Server;
204 } /* Client_ThisServer */
205
206
207 GLOBAL CLIENT *Client_NewLocal( CONN_ID Idx, CHAR *Hostname, INT Type, BOOLEAN Idented )
208 {
209         /* Neuen lokalen Client erzeugen: Wrapper-Funktion fuer Client_New(). */
210         return Client_New( Idx, This_Server, Type, NULL, NULL, Hostname, NULL, 0, 0, NULL, Idented );
211 } /* Client_NewLocal */
212
213
214 GLOBAL CLIENT *Client_NewRemoteServer( CLIENT *Introducer, CHAR *Hostname, INT Hops, INT Token, CHAR *Info, BOOLEAN Idented )
215 {
216         /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
217         return Client_New( NONE, Introducer, CLIENT_SERVER, Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented );
218 } /* Client_NewRemoteServer */
219
220
221 GLOBAL CLIENT *Client_NewRemoteUser( CLIENT *Introducer, CHAR *Nick, INT Hops, CHAR *User, CHAR *Hostname, INT Token, CHAR *Modes, CHAR *Info, BOOLEAN Idented )
222 {
223         /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
224         return Client_New( NONE, Introducer, CLIENT_USER, Nick, User, Hostname, Info, Hops, Token, NULL, Idented );
225 } /* Client_NewRemoteUser */
226
227
228 GLOBAL CLIENT *Client_New( CONN_ID Idx, CLIENT *Introducer, INT Type, CHAR *ID, CHAR *User, CHAR *Hostname, CHAR *Info, INT Hops, INT Token, CHAR *Modes, BOOLEAN Idented )
229 {
230         CLIENT *client;
231
232         assert( Idx >= NONE );
233         assert( Introducer != NULL );
234         assert( Hostname != NULL );
235
236         client = New_Client_Struct( );
237         if( ! client ) return NULL;
238
239         /* Initialisieren */
240         client->conn_id = Idx;
241         client->introducer = Introducer;
242         client->type = Type;
243         if( ID ) Client_SetID( client, ID );
244         if( User ) Client_SetUser( client, User, Idented );
245         if( Hostname ) Client_SetHostname( client, Hostname );
246         if( Info ) Client_SetInfo( client, Info );
247         client->hops = Hops;
248         client->token = Token;
249         if( Modes ) Client_SetModes( client, Modes );
250         if( Type == CLIENT_SERVER ) Generate_MyToken( client );
251
252         /* Verketten */
253         client->next = My_Clients;
254         My_Clients = client;
255
256         return client;
257 } /* Client_New */
258
259
260 GLOBAL VOID Client_Destroy( CLIENT *Client, CHAR *LogMsg, CHAR *FwdMsg )
261 {
262         /* Client entfernen. */
263         
264         CLIENT *last, *c;
265         CHAR *txt;
266
267         assert( Client != NULL );
268
269         if( LogMsg ) txt = LogMsg;
270         else txt = FwdMsg;
271         if( ! txt ) txt = "Reason unknown.";
272
273         last = NULL;
274         c = My_Clients;
275         while( c )
276         {
277                 if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
278                 {
279                         Client_Destroy( c, LogMsg, FwdMsg );
280                         last = NULL;
281                         c = My_Clients;
282                         continue;
283                 }
284                 if( c == Client )
285                 {
286                         if( last ) last->next = c->next;
287                         else My_Clients = c->next;
288
289                         if( c->type == CLIENT_USER )
290                         {
291                                 if( c->conn_id != NONE )
292                                 {
293                                         /* Ein lokaler User. Alle andere Server informieren! */
294                                         Log( LOG_NOTICE, "User \"%s\" unregistered (connection %d): %s", Client_Mask( c ), c->conn_id, txt );
295
296                                         if( FwdMsg ) IRC_WriteStrServersPrefix( NULL, c, "QUIT :%s", FwdMsg );
297                                         else IRC_WriteStrServersPrefix( NULL, c, "QUIT :" );
298                                 }
299                                 else
300                                 {
301                                         /* Remote User. Andere Server informieren, ausser denen,
302                                          * die "in Richtung dem liegen", auf dem der User registriert
303                                          * ist. Von denen haben wir das QUIT ja wohl bekommen. */
304                                         Log( LOG_DEBUG, "User \"%s\" unregistered: %s", Client_Mask( c ), txt );
305                                         
306                                         if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :%s", FwdMsg );
307                                         else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "QUIT :" );
308                                 }
309                         }
310                         else if( c->type == CLIENT_SERVER )
311                         {
312                                 if( c != This_Server ) Log( LOG_NOTICE, "Server \"%s\" unregistered: %s", c->id, txt );
313
314                                 /* andere Server informieren */
315                                 if( ! NGIRCd_Quit )
316                                 {
317                                         if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
318                                         else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :", c->id );
319                                 }
320                         }
321                         else Log( LOG_NOTICE, "Unknown client \"%s\" unregistered: %s", c->id, txt );
322
323                         free( c );
324                         break;
325                 }
326                 last = c;
327                 c = c->next;
328         }
329 } /* Client_Destroy */
330
331
332 GLOBAL VOID Client_SetHostname( CLIENT *Client, CHAR *Hostname )
333 {
334         /* Hostname eines Clients setzen */
335         
336         assert( Client != NULL );
337         strncpy( Client->host, Hostname, CLIENT_HOST_LEN );
338         Client->host[CLIENT_HOST_LEN - 1] = '\0';
339 } /* Client_SetHostname */
340
341
342 GLOBAL VOID Client_SetID( CLIENT *Client, CHAR *ID )
343 {
344         /* Hostname eines Clients setzen */
345
346         assert( Client != NULL );
347         strncpy( Client->id, ID, CLIENT_ID_LEN );
348         Client->id[CLIENT_ID_LEN - 1] = '\0';
349 } /* Client_SetID */
350
351
352 GLOBAL VOID Client_SetUser( CLIENT *Client, CHAR *User, BOOLEAN Idented )
353 {
354         /* Username eines Clients setzen */
355
356         assert( Client != NULL );
357         if( Idented ) strncpy( Client->user, User, CLIENT_USER_LEN );
358         else
359         {
360                 Client->user[0] = '~';
361                 strncpy( Client->user + 1, User, CLIENT_USER_LEN - 1 );
362         }
363         Client->user[CLIENT_USER_LEN - 1] = '\0';
364 } /* Client_SetUser */
365
366
367 GLOBAL VOID Client_SetInfo( CLIENT *Client, CHAR *Info )
368 {
369         /* Hostname eines Clients setzen */
370
371         assert( Client != NULL );
372         strncpy( Client->info, Info, CLIENT_INFO_LEN );
373         Client->info[CLIENT_INFO_LEN - 1] = '\0';
374 } /* Client_SetInfo */
375
376
377 GLOBAL VOID Client_SetModes( CLIENT *Client, CHAR *Modes )
378 {
379         /* Hostname eines Clients setzen */
380
381         assert( Client != NULL );
382         strncpy( Client->modes, Modes, CLIENT_MODE_LEN );
383         Client->info[CLIENT_MODE_LEN - 1] = '\0';
384 } /* Client_SetModes */
385
386
387 GLOBAL VOID Client_SetPassword( CLIENT *Client, CHAR *Pwd )
388 {
389         /* Von einem Client geliefertes Passwort */
390
391         assert( Client != NULL );
392         strncpy( Client->pwd, Pwd, CLIENT_PASS_LEN );
393         Client->pwd[CLIENT_PASS_LEN - 1] = '\0';
394 } /* Client_SetPassword */
395
396
397 GLOBAL VOID Client_SetType( CLIENT *Client, INT Type )
398 {
399         assert( Client != NULL );
400         Client->type = Type;
401         if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
402 } /* Client_SetType */
403
404
405 GLOBAL VOID Client_SetHops( CLIENT *Client, INT Hops )
406 {
407         assert( Client != NULL );
408         Client->hops = Hops;
409 } /* Client_SetHops */
410
411
412 GLOBAL VOID Client_SetToken( CLIENT *Client, INT Token )
413 {
414         assert( Client != NULL );
415         Client->token = Token;
416 } /* Client_SetToken */
417
418
419 GLOBAL VOID Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
420 {
421         assert( Client != NULL );
422         Client->introducer = Introducer;
423 } /* Client_SetIntroducer */
424
425
426 GLOBAL VOID Client_SetOperByMe( CLIENT *Client, BOOLEAN OperByMe )
427 {
428         assert( Client != NULL );
429         Client->oper_by_me = OperByMe;
430 } /* Client_SetOperByMe */
431
432
433 GLOBAL BOOLEAN Client_ModeAdd( CLIENT *Client, CHAR Mode )
434 {
435         /* Mode soll gesetzt werden. TRUE wird geliefert, wenn der
436          * Mode neu gesetzt wurde, FALSE, wenn der Client den Mode
437          * bereits hatte. */
438
439         CHAR x[2];
440         
441         assert( Client != NULL );
442
443         x[0] = Mode; x[1] = '\0';
444         if( ! strchr( Client->modes, x[0] ))
445         {
446                 /* Client hat den Mode noch nicht -> setzen */
447                 strcat( Client->modes, x );
448                 return TRUE;
449         }
450         else return FALSE;
451 } /* Client_ModeAdd */
452
453
454 GLOBAL BOOLEAN Client_ModeDel( CLIENT *Client, CHAR Mode )
455 {
456         /* Mode soll geloescht werden. TRUE wird geliefert, wenn der
457         * Mode entfernt wurde, FALSE, wenn der Client den Mode
458         * ueberhaupt nicht hatte. */
459
460         CHAR x[2], *p;
461
462         assert( Client != NULL );
463
464         x[0] = Mode; x[1] = '\0';
465
466         p = strchr( Client->modes, x[0] );
467         if( ! p ) return FALSE;
468
469         /* Client hat den Mode -> loeschen */
470         while( *p )
471         {
472                 *p = *(p + 1);
473                 p++;
474         }
475         return TRUE;
476 } /* Client_ModeDel */
477
478
479 GLOBAL CLIENT *Client_GetFromConn( CONN_ID Idx )
480 {
481         /* Client-Struktur, die zur lokalen Verbindung Idx gehoert,
482          * liefern. Wird keine gefunden, so wird NULL geliefert. */
483
484         CLIENT *c;
485
486         assert( Idx >= 0 );
487         
488         c = My_Clients;
489         while( c )
490         {
491                 if( c->conn_id == Idx ) return c;
492                 c = c->next;
493         }
494         return NULL;
495 } /* Client_GetFromConn */
496
497
498 GLOBAL CLIENT *Client_GetFromID( CHAR *Nick )
499 {
500         /* Client-Struktur, die den entsprechenden Nick hat,
501         * liefern. Wird keine gefunden, so wird NULL geliefert. */
502
503         CLIENT *c;
504
505         assert( Nick != NULL );
506
507         c = My_Clients;
508         while( c )
509         {
510                 if( strcasecmp( c->id, Nick ) == 0 ) return c;
511                 c = c->next;
512         }
513         return NULL;
514 } /* Client_GetFromID */
515
516
517 GLOBAL CLIENT *Client_GetFromToken( CLIENT *Client, INT Token )
518 {
519         /* Client-Struktur, die den entsprechenden Introducer (=Client)
520          * und das gegebene Token hat, liefern. Wird keine gefunden,
521          * so wird NULL geliefert. */
522
523         CLIENT *c;
524
525         assert( Client != NULL );
526         assert( Token > 0 );
527
528         c = My_Clients;
529         while( c )
530         {
531                 if(( c->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c->token == Token )) return c;
532                 c = c->next;
533         }
534         return NULL;
535 } /* Client_GetFromToken */
536
537
538 GLOBAL INT Client_Type( CLIENT *Client )
539 {
540         assert( Client != NULL );
541         return Client->type;
542 } /* Client_Type */
543
544
545 GLOBAL CONN_ID Client_Conn( CLIENT *Client )
546 {
547         assert( Client != NULL );
548         return Client->conn_id;
549 } /* Client_Conn */
550
551
552 GLOBAL CHAR *Client_ID( CLIENT *Client )
553 {
554         assert( Client != NULL );
555
556         if( Client->id[0] ) return Client->id;
557         else return "*";
558 } /* Client_ID */
559
560
561 GLOBAL CHAR *Client_Info( CLIENT *Client )
562 {
563         assert( Client != NULL );
564         return Client->info;
565 } /* Client_Info */
566
567
568 GLOBAL CHAR *Client_User( CLIENT *Client )
569 {
570         assert( Client != NULL );
571         if( Client->user ) return Client->user;
572         else return "~";
573 } /* Client_User */
574
575
576 GLOBAL CHAR *Client_Hostname( CLIENT *Client )
577 {
578         assert( Client != NULL );
579         return Client->host;
580 } /* Client_Hostname */
581
582
583 GLOBAL CHAR *Client_Password( CLIENT *Client )
584 {
585         assert( Client != NULL );
586         return Client->pwd;
587 } /* Client_Password */
588
589
590 GLOBAL CHAR *Client_Modes( CLIENT *Client )
591 {
592         assert( Client != NULL );
593         return Client->modes;
594 } /* Client_Modes */
595
596
597 GLOBAL BOOLEAN Client_OperByMe( CLIENT *Client )
598 {
599         assert( Client != NULL );
600         return Client->oper_by_me;
601 } /* Client_OperByMe */
602
603
604 GLOBAL INT Client_Hops( CLIENT *Client )
605 {
606         assert( Client != NULL );
607         return Client->hops;
608 } /* Client_Hops */
609
610
611 GLOBAL INT Client_Token( CLIENT *Client )
612 {
613         assert( Client != NULL );
614         return Client->token;
615 } /* Client_Token */
616
617
618 GLOBAL INT Client_MyToken( CLIENT *Client )
619 {
620         assert( Client != NULL );
621         return Client->mytoken;
622 } /* Client_MyToken */
623
624
625 GLOBAL CLIENT *Client_NextHop( CLIENT *Client )
626 {
627         CLIENT *c;
628         
629         assert( Client != NULL );
630
631         c = Client;
632         while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server )) c = c->introducer;
633         return c;
634 } /* Client_NextHop */
635
636
637 GLOBAL CHAR *Client_Mask( CLIENT *Client )
638 {
639         /* Client-"ID" liefern, wie sie z.B. fuer
640          * Prefixe benoetigt wird. */
641
642         assert( Client != NULL );
643         
644         if( Client->type == CLIENT_SERVER ) return Client->id;
645
646         sprintf( GetID_Buffer, "%s!%s@%s", Client->id, Client->user, Client->host );
647         return GetID_Buffer;
648 } /* Client_Mask */
649
650
651 GLOBAL CLIENT *Client_Introducer( CLIENT *Client )
652 {
653         assert( Client != NULL );
654         return Client->introducer;
655 } /* Client_Introducer */
656
657
658 GLOBAL BOOLEAN Client_HasMode( CLIENT *Client, CHAR Mode )
659 {
660         assert( Client != NULL );
661         return strchr( Client->modes, Mode ) != NULL;
662 } /* Client_HasMode */
663
664
665 GLOBAL BOOLEAN Client_CheckNick( CLIENT *Client, CHAR *Nick )
666 {
667         /* Nick ueberpruefen */
668
669         CLIENT *c;
670         
671         assert( Client != NULL );
672         assert( Nick != NULL );
673         
674         /* Nick zu lang? */
675         if( strlen( Nick ) > CLIENT_NICK_LEN ) return IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
676
677         /* Nick bereits vergeben? */
678         c = My_Clients;
679         while( c )
680         {
681                 if( strcasecmp( c->id, Nick ) == 0 )
682                 {
683                         /* den Nick gibt es bereits */
684                         IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
685                         return FALSE;
686                 }
687                 c = c->next;
688         }
689
690         return TRUE;
691 } /* Client_CheckNick */
692
693
694 GLOBAL BOOLEAN Client_CheckID( CLIENT *Client, CHAR *ID )
695 {
696         /* Nick ueberpruefen */
697
698         CHAR str[COMMAND_LEN];
699         CLIENT *c;
700
701         assert( Client != NULL );
702         assert( Client->conn_id > NONE );
703         assert( ID != NULL );
704
705         /* Nick zu lang? */
706         if( strlen( ID ) > CLIENT_ID_LEN ) return IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), ID );
707
708         /* ID bereits vergeben? */
709         c = My_Clients;
710         while( c )
711         {
712                 if( strcasecmp( c->id, ID ) == 0 )
713                 {
714                         /* die Server-ID gibt es bereits */
715                         sprintf( str, "ID \"%s\" already registered!", ID );
716                         Log( LOG_ERR, "%s (on connection %d)", str, Client->conn_id );
717                         Conn_Close( Client->conn_id, str, str, TRUE );
718                         return FALSE;
719                 }
720                 c = c->next;
721         }
722
723         return TRUE;
724 } /* Client_CheckID */
725
726
727 GLOBAL CLIENT *Client_Search( CHAR *ID )
728 {
729         /* Client suchen, auf den ID passt */
730
731         CLIENT *c;
732
733         assert( ID != NULL );
734
735         c = My_Clients;
736         while( c )
737         {
738                 if( strcasecmp( c->id, ID ) == 0 ) return c;
739                 c = c->next;
740         }
741         
742         return NULL;
743 } /* Client_Search */
744
745
746 GLOBAL CLIENT *Client_First( VOID )
747 {
748         /* Ersten Client liefern. */
749
750         return My_Clients;
751 } /* Client_First */
752
753
754 GLOBAL CLIENT *Client_Next( CLIENT *c )
755 {
756         /* Naechsten Client liefern. Existiert keiner,
757          * so wird NULL geliefert. */
758
759         assert( c != NULL );
760         return c->next;
761 } /* Client_Next */
762
763
764 LOCAL CLIENT *New_Client_Struct( VOID )
765 {
766         /* Neue CLIENT-Struktur pre-initialisieren */
767         
768         CLIENT *c;
769         INT i;
770         
771         c = malloc( sizeof( CLIENT ));
772         if( ! c )
773         {
774                 Log( LOG_EMERG, "Can't allocate memory!" );
775                 return NULL;
776         }
777
778         c->next = NULL;
779         c->type = CLIENT_UNKNOWN;
780         c->conn_id = NONE;
781         c->introducer = NULL;
782         strcpy( c->id, "" );
783         strcpy( c->pwd, "" );
784         strcpy( c->host, "" );
785         strcpy( c->user, "" );
786         strcpy( c->info, "" );
787         for( i = 0; i < MAX_CHANNELS; c->channels[i++] = NULL );
788         strcpy( c->modes, "" );
789         c->oper_by_me = FALSE;
790         c->hops = -1;
791         c->token = -1;
792         c->mytoken = -1;
793
794         return c;
795 } /* New_Client */
796
797
798 LOCAL VOID Generate_MyToken( CLIENT *Client )
799 {
800         CLIENT *c;
801         INT token;
802
803         c = My_Clients;
804         token = 2;
805         while( c )
806         {
807                 if( c->mytoken == token )
808                 {
809                         /* Das Token wurde bereits vergeben */
810                         token++;
811                         c = My_Clients;
812                         continue;
813                 }
814                 else c = c->next;
815         }
816         Client->mytoken = token;
817         Log( LOG_DEBUG, "Assigned token %d to server \"%s\".", token, Client->id );
818 } /* Generate_MyToken */
819
820
821 /* -eof- */