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