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