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