]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/client.c
- CLIENT-Struktur um Flags erweitert.
[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.60 2002/09/03 18:54:31 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         /* Modes 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_SetFlags( CLIENT *Client, CHAR *Flags )
368 {
369         /* Flags eines Clients setzen */
370
371         assert( Client != NULL );
372         assert( Flags != NULL );
373
374         strncpy( Client->flags, Flags, CLIENT_FLAGS_LEN - 1 );
375         Client->modes[CLIENT_FLAGS_LEN - 1] = '\0';
376 } /* Client_SetFlags */
377
378
379 GLOBAL VOID
380 Client_SetPassword( CLIENT *Client, CHAR *Pwd )
381 {
382         /* Von einem Client geliefertes Passwort */
383
384         assert( Client != NULL );
385         assert( Pwd != NULL );
386         
387         strncpy( Client->pwd, Pwd, CLIENT_PASS_LEN - 1 );
388         Client->pwd[CLIENT_PASS_LEN - 1] = '\0';
389 } /* Client_SetPassword */
390
391
392 GLOBAL VOID
393 Client_SetAway( CLIENT *Client, CHAR *Txt )
394 {
395         /* Von einem Client gelieferte AWAY-Nachricht */
396
397         assert( Client != NULL );
398
399         if( Txt )
400         {
401                 /* Client AWAY setzen */
402                 strncpy( Client->away, Txt, CLIENT_AWAY_LEN - 1 );
403                 Client->away[CLIENT_AWAY_LEN - 1] = '\0';
404                 Client_ModeAdd( Client, 'a' );
405                 Log( LOG_DEBUG, "User \"%s\" is away: %s", Client_Mask( Client ), Txt );
406         }
407         else
408         {
409                 /* AWAY loeschen */
410                 Client_ModeDel( Client, 'a' );
411                 Log( LOG_DEBUG, "User \"%s\" is no longer away.", Client_Mask( Client ));
412         }
413 } /* Client_SetAway */
414
415
416 GLOBAL VOID
417 Client_SetType( CLIENT *Client, INT Type )
418 {
419         assert( Client != NULL );
420         Client->type = Type;
421         if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
422 } /* Client_SetType */
423
424
425 GLOBAL VOID
426 Client_SetHops( CLIENT *Client, INT Hops )
427 {
428         assert( Client != NULL );
429         Client->hops = Hops;
430 } /* Client_SetHops */
431
432
433 GLOBAL VOID
434 Client_SetToken( CLIENT *Client, INT Token )
435 {
436         assert( Client != NULL );
437         Client->token = Token;
438 } /* Client_SetToken */
439
440
441 GLOBAL VOID
442 Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
443 {
444         assert( Client != NULL );
445         assert( Introducer != NULL );
446         Client->introducer = Introducer;
447 } /* Client_SetIntroducer */
448
449
450 GLOBAL VOID
451 Client_SetOperByMe( CLIENT *Client, BOOLEAN OperByMe )
452 {
453         assert( Client != NULL );
454         Client->oper_by_me = OperByMe;
455 } /* Client_SetOperByMe */
456
457
458 GLOBAL BOOLEAN
459 Client_ModeAdd( CLIENT *Client, CHAR Mode )
460 {
461         /* Mode soll gesetzt werden. TRUE wird geliefert, wenn der
462          * Mode neu gesetzt wurde, FALSE, wenn der Client den Mode
463          * bereits hatte. */
464
465         CHAR x[2];
466         
467         assert( Client != NULL );
468
469         x[0] = Mode; x[1] = '\0';
470         if( ! strchr( Client->modes, x[0] ))
471         {
472                 /* Client hat den Mode noch nicht -> setzen */
473                 strcat( Client->modes, x );
474                 return TRUE;
475         }
476         else return FALSE;
477 } /* Client_ModeAdd */
478
479
480 GLOBAL BOOLEAN
481 Client_ModeDel( CLIENT *Client, CHAR Mode )
482 {
483         /* Mode soll geloescht werden. TRUE wird geliefert, wenn der
484         * Mode entfernt wurde, FALSE, wenn der Client den Mode
485         * ueberhaupt nicht hatte. */
486
487         CHAR x[2], *p;
488
489         assert( Client != NULL );
490
491         x[0] = Mode; x[1] = '\0';
492
493         p = strchr( Client->modes, x[0] );
494         if( ! p ) return FALSE;
495
496         /* Client hat den Mode -> loeschen */
497         while( *p )
498         {
499                 *p = *(p + 1);
500                 p++;
501         }
502         return TRUE;
503 } /* Client_ModeDel */
504
505
506 GLOBAL CLIENT *
507 Client_GetFromConn( CONN_ID Idx )
508 {
509         /* Client-Struktur, die zur lokalen Verbindung Idx gehoert,
510          * liefern. Wird keine gefunden, so wird NULL geliefert. */
511
512         CLIENT *c;
513
514         assert( Idx >= 0 );
515         
516         c = My_Clients;
517         while( c )
518         {
519                 if( c->conn_id == Idx ) return c;
520                 c = (CLIENT *)c->next;
521         }
522         return NULL;
523 } /* Client_GetFromConn */
524
525
526 GLOBAL CLIENT *
527 Client_Search( CHAR *Nick )
528 {
529         /* Client-Struktur, die den entsprechenden Nick hat, liefern.
530          * Wird keine gefunden, so wird NULL geliefert. */
531
532         CHAR search_id[CLIENT_ID_LEN], *ptr;
533         CLIENT *c = NULL;
534         UINT32 search_hash;
535
536         assert( Nick != NULL );
537
538         /* Nick kopieren und ggf. Host-Mask abschneiden */
539         strncpy( search_id, Nick, CLIENT_ID_LEN - 1 );
540         search_id[CLIENT_ID_LEN - 1] = '\0';
541         ptr = strchr( search_id, '!' );
542         if( ptr ) *ptr = '\0';
543
544         search_hash = Hash( search_id );
545
546         c = My_Clients;
547         while( c )
548         {
549                 if( c->hash == search_hash )
550                 {
551                         /* lt. Hash-Wert: Treffer! */
552                         if( strcasecmp( c->id, search_id ) == 0 ) return c;
553                 }
554                 c = (CLIENT *)c->next;
555         }
556         return NULL;
557 } /* Client_Search */
558
559
560 GLOBAL CLIENT *
561 Client_GetFromToken( CLIENT *Client, INT Token )
562 {
563         /* Client-Struktur, die den entsprechenden Introducer (=Client)
564          * und das gegebene Token hat, liefern. Wird keine gefunden,
565          * so wird NULL geliefert. */
566
567         CLIENT *c;
568
569         assert( Client != NULL );
570         assert( Token > 0 );
571
572         c = My_Clients;
573         while( c )
574         {
575                 if(( c->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c->token == Token )) return c;
576                 c = (CLIENT *)c->next;
577         }
578         return NULL;
579 } /* Client_GetFromToken */
580
581
582 GLOBAL INT
583 Client_Type( CLIENT *Client )
584 {
585         assert( Client != NULL );
586         return Client->type;
587 } /* Client_Type */
588
589
590 GLOBAL CONN_ID
591 Client_Conn( CLIENT *Client )
592 {
593         assert( Client != NULL );
594         return Client->conn_id;
595 } /* Client_Conn */
596
597
598 GLOBAL CHAR *
599 Client_ID( CLIENT *Client )
600 {
601         assert( Client != NULL );
602
603 #ifdef DEBUG
604         if( Client->type == CLIENT_USER ) assert( strlen( Client->id ) < CLIENT_NICK_LEN );
605 #endif
606                                                    
607         if( Client->id[0] ) return Client->id;
608         else return "*";
609 } /* Client_ID */
610
611
612 GLOBAL CHAR *
613 Client_Info( CLIENT *Client )
614 {
615         assert( Client != NULL );
616         return Client->info;
617 } /* Client_Info */
618
619
620 GLOBAL CHAR *
621 Client_User( CLIENT *Client )
622 {
623         assert( Client != NULL );
624         if( Client->user[0] ) return Client->user;
625         else return "~";
626 } /* Client_User */
627
628
629 GLOBAL CHAR *
630 Client_Hostname( CLIENT *Client )
631 {
632         assert( Client != NULL );
633         return Client->host;
634 } /* Client_Hostname */
635
636
637 GLOBAL CHAR *
638 Client_Password( CLIENT *Client )
639 {
640         assert( Client != NULL );
641         return Client->pwd;
642 } /* Client_Password */
643
644
645 GLOBAL CHAR *
646 Client_Modes( CLIENT *Client )
647 {
648         assert( Client != NULL );
649         return Client->modes;
650 } /* Client_Modes */
651
652
653 GLOBAL CHAR *
654 Client_Flags( CLIENT *Client )
655 {
656         assert( Client != NULL );
657         return Client->flags;
658 } /* Client_Flags */
659
660
661 GLOBAL BOOLEAN
662 Client_OperByMe( CLIENT *Client )
663 {
664         assert( Client != NULL );
665         return Client->oper_by_me;
666 } /* Client_OperByMe */
667
668
669 GLOBAL INT
670 Client_Hops( CLIENT *Client )
671 {
672         assert( Client != NULL );
673         return Client->hops;
674 } /* Client_Hops */
675
676
677 GLOBAL INT
678 Client_Token( CLIENT *Client )
679 {
680         assert( Client != NULL );
681         return Client->token;
682 } /* Client_Token */
683
684
685 GLOBAL INT
686 Client_MyToken( CLIENT *Client )
687 {
688         assert( Client != NULL );
689         return Client->mytoken;
690 } /* Client_MyToken */
691
692
693 GLOBAL CLIENT *
694 Client_NextHop( CLIENT *Client )
695 {
696         CLIENT *c;
697         
698         assert( Client != NULL );
699
700         c = Client;
701         while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server )) c = c->introducer;
702         return c;
703 } /* Client_NextHop */
704
705
706 GLOBAL CHAR *
707 Client_Mask( CLIENT *Client )
708 {
709         /* Client-"ID" liefern, wie sie z.B. fuer
710          * Prefixe benoetigt wird. */
711
712         assert( Client != NULL );
713         
714         if( Client->type == CLIENT_SERVER ) return Client->id;
715
716         sprintf( GetID_Buffer, "%s!%s@%s", Client->id, Client->user, Client->host );
717         return GetID_Buffer;
718 } /* Client_Mask */
719
720
721 GLOBAL CLIENT *
722 Client_Introducer( CLIENT *Client )
723 {
724         assert( Client != NULL );
725         return Client->introducer;
726 } /* Client_Introducer */
727
728
729 GLOBAL CLIENT *
730 Client_TopServer( CLIENT *Client )
731 {
732         assert( Client != NULL );
733         return Client->topserver;
734 } /* Client_TopServer */
735
736
737 GLOBAL BOOLEAN
738 Client_HasMode( CLIENT *Client, CHAR Mode )
739 {
740         assert( Client != NULL );
741         return strchr( Client->modes, Mode ) != NULL;
742 } /* Client_HasMode */
743
744
745 GLOBAL CHAR *
746 Client_Away( CLIENT *Client )
747 {
748         /* AWAY-Text liefern */
749
750         assert( Client != NULL );
751         return Client->away;
752 } /* Client_Away */
753
754
755 GLOBAL BOOLEAN
756 Client_CheckNick( CLIENT *Client, CHAR *Nick )
757 {
758         /* Nick ueberpruefen */
759
760         assert( Client != NULL );
761         assert( Nick != NULL );
762         
763         /* Nick ungueltig? */
764         if( ! Client_IsValidNick( Nick ))
765         {
766                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
767                 return FALSE;
768         }
769
770         /* Nick bereits vergeben? */
771         if( Client_Search( Nick ))
772         {
773                 /* den Nick gibt es bereits */
774                 IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
775                 return FALSE;
776         }
777
778         return TRUE;
779 } /* Client_CheckNick */
780
781
782 GLOBAL BOOLEAN
783 Client_CheckID( CLIENT *Client, CHAR *ID )
784 {
785         /* Nick ueberpruefen */
786
787         CHAR str[COMMAND_LEN];
788         CLIENT *c;
789
790         assert( Client != NULL );
791         assert( Client->conn_id > NONE );
792         assert( ID != NULL );
793
794         /* Nick zu lang? */
795         if( strlen( ID ) > CLIENT_ID_LEN )
796         {
797                 IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), ID );
798                 return FALSE;
799         }
800
801         /* ID bereits vergeben? */
802         c = My_Clients;
803         while( c )
804         {
805                 if( strcasecmp( c->id, ID ) == 0 )
806                 {
807                         /* die Server-ID gibt es bereits */
808                         sprintf( str, "ID \"%s\" already registered!", ID );
809                         Log( LOG_ERR, "%s (on connection %d)", str, Client->conn_id );
810                         Conn_Close( Client->conn_id, str, str, TRUE );
811                         return FALSE;
812                 }
813                 c = (CLIENT *)c->next;
814         }
815
816         return TRUE;
817 } /* Client_CheckID */
818
819
820 GLOBAL CLIENT *
821 Client_First( VOID )
822 {
823         /* Ersten Client liefern. */
824
825         return My_Clients;
826 } /* Client_First */
827
828
829 GLOBAL CLIENT *
830 Client_Next( CLIENT *c )
831 {
832         /* Naechsten Client liefern. Existiert keiner,
833          * so wird NULL geliefert. */
834
835         assert( c != NULL );
836         return (CLIENT *)c->next;
837 } /* Client_Next */
838
839
840 GLOBAL INT
841 Client_UserCount( VOID )
842 {
843         return Count( CLIENT_USER );
844 } /* Client_UserCount */
845
846
847 GLOBAL INT
848 Client_ServiceCount( VOID )
849 {
850         return Count( CLIENT_SERVICE );;
851 } /* Client_ServiceCount */
852
853
854 GLOBAL INT
855 Client_ServerCount( VOID )
856 {
857         return Count( CLIENT_SERVER );
858 } /* Client_ServerCount */
859
860
861 GLOBAL INT
862 Client_MyUserCount( VOID )
863 {
864         return MyCount( CLIENT_USER );
865 } /* Client_MyUserCount */
866
867
868 GLOBAL INT
869 Client_MyServiceCount( VOID )
870 {
871         return MyCount( CLIENT_SERVICE );
872 } /* Client_MyServiceCount */
873
874
875 GLOBAL INT
876 Client_MyServerCount( VOID )
877 {
878         CLIENT *c;
879         INT cnt;
880
881         cnt = 0;
882         c = My_Clients;
883         while( c )
884         {
885                 if(( c->type == CLIENT_SERVER ) && ( c->hops == 1 )) cnt++;
886                 c = (CLIENT *)c->next;
887         }
888         return cnt;
889 } /* Client_MyServerCount */
890
891
892 GLOBAL INT
893 Client_OperCount( VOID )
894 {
895         CLIENT *c;
896         INT cnt;
897
898         cnt = 0;
899         c = My_Clients;
900         while( c )
901         {
902                 if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++;
903                 c = (CLIENT *)c->next;
904         }
905         return cnt;
906 } /* Client_OperCount */
907
908
909 GLOBAL INT
910 Client_UnknownCount( VOID )
911 {
912         CLIENT *c;
913         INT cnt;
914
915         cnt = 0;
916         c = My_Clients;
917         while( c )
918         {
919                 if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
920                 c = (CLIENT *)c->next;
921         }
922         return cnt;
923 } /* Client_UnknownCount */
924
925
926 GLOBAL BOOLEAN
927 Client_IsValidNick( CHAR *Nick )
928 {
929         /* Ist der Nick gueltig? */
930
931         CHAR *ptr, goodchars[20];
932         
933         assert( Nick != NULL );
934
935         strcpy( goodchars, ";0123456789-" );
936
937         if( Nick[0] == '#' ) return FALSE;
938         if( strchr( goodchars, Nick[0] )) return FALSE;
939         if( strlen( Nick ) >= CLIENT_NICK_LEN ) return FALSE;
940
941         ptr = Nick;
942         while( *ptr )
943         {
944                 if(( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return FALSE;
945                 if(( *ptr > '}' ) && ( ! strchr( goodchars, *ptr ))) return FALSE;
946                 ptr++;
947         }
948         
949         return TRUE;
950 } /* Client_IsValidNick */
951
952
953 LOCAL INT
954 Count( CLIENT_TYPE Type )
955 {
956         CLIENT *c;
957         INT cnt;
958
959         cnt = 0;
960         c = My_Clients;
961         while( c )
962         {
963                 if( c->type == Type ) cnt++;
964                 c = (CLIENT *)c->next;
965         }
966         return cnt;
967 } /* Count */
968
969
970 LOCAL INT
971 MyCount( CLIENT_TYPE Type )
972 {
973         CLIENT *c;
974         INT cnt;
975
976         cnt = 0;
977         c = My_Clients;
978         while( c )
979         {
980                 if(( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
981                 c = (CLIENT *)c->next;
982         }
983         return cnt;
984 } /* MyCount */
985
986
987 LOCAL CLIENT *
988 New_Client_Struct( VOID )
989 {
990         /* Neue CLIENT-Struktur pre-initialisieren */
991         
992         CLIENT *c;
993         
994         c = malloc( sizeof( CLIENT ));
995         if( ! c )
996         {
997                 Log( LOG_EMERG, "Can't allocate memory! [New_Client_Struct]" );
998                 return NULL;
999         }
1000
1001         c->next = NULL;
1002         c->hash = 0;
1003         c->type = CLIENT_UNKNOWN;
1004         c->conn_id = NONE;
1005         c->introducer = NULL;
1006         c->topserver = NULL;
1007         strcpy( c->id, "" );
1008         strcpy( c->pwd, "" );
1009         strcpy( c->host, "" );
1010         strcpy( c->user, "" );
1011         strcpy( c->info, "" );
1012         strcpy( c->modes, "" );
1013         c->oper_by_me = FALSE;
1014         c->hops = -1;
1015         c->token = -1;
1016         c->mytoken = -1;
1017         strcpy( c->away, "" );
1018         strcpy( c->flags, "" );
1019
1020         return c;
1021 } /* New_Client */
1022
1023
1024 LOCAL VOID
1025 Generate_MyToken( CLIENT *Client )
1026 {
1027         CLIENT *c;
1028         INT token;
1029
1030         c = My_Clients;
1031         token = 2;
1032         while( c )
1033         {
1034                 if( c->mytoken == token )
1035                 {
1036                         /* Das Token wurde bereits vergeben */
1037                         token++;
1038                         c = My_Clients;
1039                         continue;
1040                 }
1041                 else c = (CLIENT *)c->next;
1042         }
1043         Client->mytoken = token;
1044         Log( LOG_DEBUG, "Assigned token %d to server \"%s\".", token, Client->id );
1045 } /* Generate_MyToken */
1046
1047
1048 /* -eof- */