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