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