]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/client.c
- Loglevel und Meldungen nochmals geaendert. Level passen nun besser.
[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.24 2002/01/06 15:18:14 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.24  2002/01/06 15:18:14  alex
25  * - Loglevel und Meldungen nochmals geaendert. Level passen nun besser.
26  *
27  * Revision 1.23  2002/01/05 23:26:05  alex
28  * - Vorbereitungen fuer Ident-Abfragen in Client-Strukturen.
29  *
30  * Revision 1.22  2002/01/05 20:08:17  alex
31  * - neue Funktion Client_NextHop().
32  *
33  * Revision 1.21  2002/01/05 19:15:03  alex
34  * - Fehlerpruefung bei select() in der "Hauptschleife" korrigiert.
35  *
36  * Revision 1.20  2002/01/04 17:57:08  alex
37  * - Client_Destroy() an Server-Links angepasst.
38  *
39  * Revision 1.19  2002/01/04 01:21:22  alex
40  * - Client-Strukturen koennen von anderen Modulen nun nur noch ueber die
41  *   enstprechenden (zum Teil neuen) Funktionen angesprochen werden.
42  *
43  * Revision 1.18  2002/01/03 02:28:06  alex
44  * - neue Funktion Client_CheckID(), diverse Aenderungen fuer Server-Links.
45  *
46  * Revision 1.17  2002/01/02 02:42:58  alex
47  * - Copyright-Texte aktualisiert.
48  *
49  * Revision 1.16  2002/01/01 18:25:44  alex
50  * - #include's fuer stdlib.h ergaenzt.
51  *
52  * Revision 1.15  2001/12/31 15:33:13  alex
53  * - neuer Befehl NAMES, kleinere Bugfixes.
54  * - Bug bei PING behoben: war zu restriktiv implementiert :-)
55  *
56  * Revision 1.14  2001/12/31 02:18:51  alex
57  * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
58  * - neuen Header "defines.h" mit (fast) allen Konstanten.
59  * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
60  *
61  * Revision 1.13  2001/12/30 19:26:11  alex
62  * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
63  *
64  * Revision 1.12  2001/12/29 20:18:18  alex
65  * - neue Funktion Client_SetHostname().
66  *
67  * Revision 1.11  2001/12/29 03:10:47  alex
68  * - Client-Modes implementiert; Loglevel mal wieder angepasst.
69  *
70  * Revision 1.10  2001/12/27 19:13:47  alex
71  * - neue Funktion Client_Search(), besseres Logging.
72  *
73  * Revision 1.9  2001/12/27 17:15:29  alex
74  * - der eigene Hostname wird nun komplet (als FQDN) ermittelt.
75  *
76  * Revision 1.8  2001/12/27 16:54:51  alex
77  * - neue Funktion Client_GetID(), liefert die "Client ID".
78  *
79  * Revision 1.7  2001/12/26 14:45:37  alex
80  * - "Code Cleanups".
81  *
82  * Revision 1.6  2001/12/26 03:19:16  alex
83  * - neue Funktion Client_Nick().
84  *
85  * Revision 1.5  2001/12/25 22:04:26  alex
86  * - Aenderungen an den Debug- und Logging-Funktionen.
87  *
88  * Revision 1.4  2001/12/25 19:21:26  alex
89  * - Client-Typ ("Status") besser unterteilt, My_Clients ist zudem nun global.
90  *
91  * Revision 1.3  2001/12/24 01:31:14  alex
92  * - einige assert()'s eingestraeut.
93  *
94  * Revision 1.2  2001/12/23 22:04:37  alex
95  * - einige neue Funktionen,
96  * - CLIENT-Struktur erweitert.
97  *
98  * Revision 1.1  2001/12/14 08:13:43  alex
99  * - neues Modul begonnen :-)
100  */
101
102
103 #define __client_c__
104
105
106 #include <portab.h>
107 #include "global.h"
108
109 #include <imp.h>
110 #include <assert.h>
111 #include <unistd.h>
112 #include <stdio.h>
113 #include <stdlib.h>
114 #include <string.h>
115 #include <netdb.h>
116
117 #include <exp.h>
118 #include "client.h"
119
120 #include <imp.h>
121 #include "ngircd.h"
122 #include "channel.h"
123 #include "conf.h"
124 #include "conn.h"
125 #include "irc.h"
126 #include "log.h"
127 #include "messages.h"
128
129 #include <exp.h>
130
131
132 LOCAL CLIENT *This_Server, *My_Clients;
133 LOCAL CHAR GetID_Buffer[CLIENT_ID_LEN];
134
135
136 LOCAL CLIENT *New_Client_Struct( VOID );
137
138
139 GLOBAL VOID Client_Init( VOID )
140 {
141         struct hostent *h;
142         
143         This_Server = New_Client_Struct( );
144         if( ! This_Server )
145         {
146                 Log( LOG_EMERG, "Can't allocate client structure for server! Going down." );
147                 Log( LOG_ALERT, PACKAGE" exiting due to fatal errors!" );
148                 exit( 1 );
149         }
150
151         /* Client-Struktur dieses Servers */
152         This_Server->next = NULL;
153         This_Server->type = CLIENT_SERVER;
154         This_Server->conn_id = NONE;
155         This_Server->introducer = This_Server;
156
157         gethostname( This_Server->host, CLIENT_HOST_LEN );
158         h = gethostbyname( This_Server->host );
159         if( h ) strcpy( This_Server->host, h->h_name );
160
161         strcpy( This_Server->id, Conf_ServerName );
162         strcpy( This_Server->info, Conf_ServerInfo );
163
164         My_Clients = This_Server;
165 } /* Client_Init */
166
167
168 GLOBAL VOID Client_Exit( VOID )
169 {
170         CLIENT *c, *next;
171         INT cnt;
172
173         Client_Destroy( This_Server, "Server going down.", NULL );
174         
175         cnt = 0;
176         c = My_Clients;
177         while( c )
178         {
179                 cnt++;
180                 next = c->next;
181                 free( c );
182                 c = next;
183         }
184         if( cnt ) Log( LOG_INFO, "Freed %d client structure%s.", cnt, cnt == 1 ? "" : "s" );
185 } /* Client_Exit */
186
187
188 GLOBAL CLIENT *Client_ThisServer( VOID )
189 {
190         return This_Server;
191 } /* Client_ThisServer */
192
193
194 GLOBAL CLIENT *Client_NewLocal( CONN_ID Idx, CHAR *Hostname, INT Type, BOOLEAN Idented )
195 {
196         /* Neuen lokalen Client erzeugen: Wrapper-Funktion fuer Client_New(). */
197         return Client_New( Idx, This_Server, Type, NULL, NULL, Hostname, NULL, 0, 0, NULL, Idented );
198 } /* Client_NewLocal */
199
200
201 GLOBAL CLIENT *Client_NewRemoteServer( CLIENT *Introducer, CHAR *Hostname, INT Hops, INT Token, CHAR *Info, BOOLEAN Idented )
202 {
203         /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
204         return Client_New( NONE, Introducer, CLIENT_SERVER, Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented );
205 } /* Client_NewRemoteServer */
206
207
208 GLOBAL CLIENT *Client_NewRemoteUser( CLIENT *Introducer, CHAR *Nick, INT Hops, CHAR *User, CHAR *Hostname, INT Token, CHAR *Modes, CHAR *Info, BOOLEAN Idented )
209 {
210         /* Neuen Remote-Client erzeugen: Wrapper-Funktion fuer Client_New (). */
211         return Client_New( NONE, Introducer, CLIENT_USER, Nick, User, Hostname, Info, Hops, Token, NULL, Idented );
212 } /* Client_NewRemoteUser */
213
214
215 GLOBAL CLIENT *Client_New( CONN_ID Idx, CLIENT *Introducer, INT Type, CHAR *ID, CHAR *User, CHAR *Hostname, CHAR *Info, INT Hops, INT Token, CHAR *Modes, BOOLEAN Idented )
216 {
217         CLIENT *client;
218
219         assert( Idx >= NONE );
220         assert( Introducer != NULL );
221         assert( Hostname != NULL );
222
223         client = New_Client_Struct( );
224         if( ! client ) return NULL;
225
226         /* Initialisieren */
227         client->conn_id = Idx;
228         client->introducer = Introducer;
229         client->type = Type;
230         if( ID ) Client_SetID( client, ID );
231         if( User ) Client_SetUser( client, User, Idented );
232         if( Hostname ) Client_SetHostname( client, Hostname );
233         if( Info ) Client_SetInfo( client, Info );
234         client->hops = Hops;
235         client->token = Token;
236         if( Modes ) Client_SetModes( client, Modes );
237
238         /* Verketten */
239         client->next = My_Clients;
240         My_Clients = client;
241
242         return client;
243 } /* Client_New */
244
245
246 GLOBAL VOID Client_Destroy( CLIENT *Client, CHAR *LogMsg, CHAR *FwdMsg )
247 {
248         /* Client entfernen. */
249         
250         CLIENT *last, *c;
251         CHAR *txt;
252
253         assert( Client != NULL );
254
255         if( LogMsg ) txt = LogMsg;
256         else txt = FwdMsg;
257         if( ! txt ) txt = "Reason unknown.";
258
259         last = NULL;
260         c = My_Clients;
261         while( c )
262         {
263                 if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
264                 {
265                         Client_Destroy( c, LogMsg, FwdMsg );
266                         last = NULL;
267                         c = My_Clients;
268                         continue;
269                 }
270                 if( c == Client )
271                 {
272                         if( last ) last->next = c->next;
273                         else My_Clients = c->next;
274
275                         if( c->type == CLIENT_USER )
276                         {
277                                 if( c->conn_id != NONE )
278                                 {
279                                         /* Ein lokaler User. Andere Server informieren! */
280                                         Log( LOG_NOTICE, "User \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
281
282                                         if( FwdMsg ) IRC_WriteStrServersPrefix( NULL, c, "QUIT :%s", FwdMsg );
283                                         else IRC_WriteStrServersPrefix( NULL, c, "QUIT :" );
284                                 }
285                                 else
286                                 {
287                                         Log( LOG_DEBUG, "User \"%s\" unregistered: %s", c->id, txt );
288                                 }
289                         }
290                         else if( c->type == CLIENT_SERVER )
291                         {
292                                 if( c != This_Server ) Log( LOG_NOTICE, "Server \"%s\" unregistered: %s", c->id, txt );
293                         }
294                         else Log( LOG_NOTICE, "Unknown client \"%s\" unregistered: %s", c->id, txt );
295
296                         free( c );
297                         break;
298                 }
299                 last = c;
300                 c = c->next;
301         }
302 } /* Client_Destroy */
303
304
305 GLOBAL VOID Client_SetHostname( CLIENT *Client, CHAR *Hostname )
306 {
307         /* Hostname eines Clients setzen */
308         
309         assert( Client != NULL );
310         strncpy( Client->host, Hostname, CLIENT_HOST_LEN );
311         Client->host[CLIENT_HOST_LEN - 1] = '\0';
312 } /* Client_SetHostname */
313
314
315 GLOBAL VOID Client_SetID( CLIENT *Client, CHAR *ID )
316 {
317         /* Hostname eines Clients setzen */
318
319         assert( Client != NULL );
320         strncpy( Client->id, ID, CLIENT_ID_LEN );
321         Client->id[CLIENT_ID_LEN - 1] = '\0';
322 } /* Client_SetID */
323
324
325 GLOBAL VOID Client_SetUser( CLIENT *Client, CHAR *User, BOOLEAN Idented )
326 {
327         /* Username eines Clients setzen */
328
329         assert( Client != NULL );
330         if( Idented ) strncpy( Client->user, User, CLIENT_USER_LEN );
331         else
332         {
333                 Client->user[0] = '~';
334                 strncpy( Client->user + 1, User, CLIENT_USER_LEN - 1 );
335         }
336         Client->user[CLIENT_USER_LEN - 1] = '\0';
337 } /* Client_SetUser */
338
339
340 GLOBAL VOID Client_SetInfo( CLIENT *Client, CHAR *Info )
341 {
342         /* Hostname eines Clients setzen */
343
344         assert( Client != NULL );
345         strncpy( Client->info, Info, CLIENT_INFO_LEN );
346         Client->info[CLIENT_INFO_LEN - 1] = '\0';
347 } /* Client_SetInfo */
348
349
350 GLOBAL VOID Client_SetModes( CLIENT *Client, CHAR *Modes )
351 {
352         /* Hostname eines Clients setzen */
353
354         assert( Client != NULL );
355         strncpy( Client->modes, Modes, CLIENT_MODE_LEN );
356         Client->info[CLIENT_MODE_LEN - 1] = '\0';
357 } /* Client_SetModes */
358
359
360 GLOBAL VOID Client_SetPassword( CLIENT *Client, CHAR *Pwd )
361 {
362         /* Von einem Client geliefertes Passwort */
363
364         assert( Client != NULL );
365         strncpy( Client->pwd, Pwd, CLIENT_PASS_LEN );
366         Client->pwd[CLIENT_PASS_LEN - 1] = '\0';
367 } /* Client_SetPassword */
368
369
370 GLOBAL VOID Client_SetType( CLIENT *Client, INT Type )
371 {
372         assert( Client != NULL );
373         Client->type = Type;
374 } /* Client_SetType */
375
376
377 GLOBAL VOID Client_SetHops( CLIENT *Client, INT Hops )
378 {
379         assert( Client != NULL );
380         Client->hops = Hops;
381 } /* Client_SetHops */
382
383
384 GLOBAL VOID Client_SetToken( CLIENT *Client, INT Token )
385 {
386         assert( Client != NULL );
387         Client->token = Token;
388 } /* Client_SetToken */
389
390
391 GLOBAL VOID Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
392 {
393         assert( Client != NULL );
394         Client->introducer = Introducer;
395 } /* Client_SetIntroducer */
396
397
398 GLOBAL VOID Client_SetOperByMe( CLIENT *Client, BOOLEAN OperByMe )
399 {
400         assert( Client != NULL );
401         Client->oper_by_me = OperByMe;
402 } /* Client_SetOperByMe */
403
404
405 GLOBAL BOOLEAN Client_ModeAdd( CLIENT *Client, CHAR Mode )
406 {
407         /* Mode soll gesetzt werden. TRUE wird geliefert, wenn der
408          * Mode neu gesetzt wurde, FALSE, wenn der Client den Mode
409          * bereits hatte. */
410
411         CHAR x[2];
412         
413         assert( Client != NULL );
414
415         x[0] = Mode; x[1] = '\0';
416         if( ! strchr( Client->modes, x[0] ))
417         {
418                 /* Client hat den Mode noch nicht -> setzen */
419                 strcat( Client->modes, x );
420                 return TRUE;
421         }
422         else return FALSE;
423 } /* Client_ModeAdd */
424
425
426 GLOBAL BOOLEAN Client_ModeDel( CLIENT *Client, CHAR Mode )
427 {
428         /* Mode soll geloescht werden. TRUE wird geliefert, wenn der
429         * Mode entfernt wurde, FALSE, wenn der Client den Mode
430         * ueberhaupt nicht hatte. */
431
432         CHAR x[2], *p;
433
434         assert( Client != NULL );
435
436         x[0] = Mode; x[1] = '\0';
437
438         p = strchr( Client->modes, x[0] );
439         if( ! p ) return FALSE;
440
441         /* Client hat den Mode -> loeschen */
442         while( *p )
443         {
444                 *p = *(p + 1);
445                 p++;
446         }
447         return TRUE;
448 } /* Client_ModeDel */
449
450
451 GLOBAL CLIENT *Client_GetFromConn( CONN_ID Idx )
452 {
453         /* Client-Struktur, die zur lokalen Verbindung Idx gehoert,
454          * liefern. Wird keine gefunden, so wird NULL geliefert. */
455
456         CLIENT *c;
457
458         assert( Idx >= 0 );
459         
460         c = My_Clients;
461         while( c )
462         {
463                 if( c->conn_id == Idx ) return c;
464                 c = c->next;
465         }
466         return NULL;
467 } /* Client_GetFromConn */
468
469
470 GLOBAL CLIENT *Client_GetFromID( CHAR *Nick )
471 {
472         /* Client-Struktur, die den entsprechenden Nick hat,
473         * liefern. Wird keine gefunden, so wird NULL geliefert. */
474
475         CLIENT *c;
476
477         assert( Nick != NULL );
478
479         c = My_Clients;
480         while( c )
481         {
482                 if( strcasecmp( c->id, Nick ) == 0 ) return c;
483                 c = c->next;
484         }
485         return NULL;
486 } /* Client_GetFromID */
487
488
489 GLOBAL CLIENT *Client_GetFromToken( CLIENT *Client, INT Token )
490 {
491         /* Client-Struktur, die den entsprechenden Introducer (=Client)
492          * und das gegebene Token hat, liefern. Wird keine gefunden,
493          * so wird NULL geliefert. */
494
495         CLIENT *c;
496
497         assert( Client != NULL );
498         assert( Token > 0 );
499
500         c = My_Clients;
501         while( c )
502         {
503                 if(( c->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c->token == Token )) return c;
504                 c = c->next;
505         }
506         return NULL;
507 } /* Client_GetFromToken */
508
509
510 GLOBAL INT Client_Type( CLIENT *Client )
511 {
512         assert( Client != NULL );
513         return Client->type;
514 } /* Client_Type */
515
516
517 GLOBAL CONN_ID Client_Conn( CLIENT *Client )
518 {
519         assert( Client != NULL );
520         return Client->conn_id;
521 } /* Client_Conn */
522
523
524 GLOBAL CHAR *Client_ID( CLIENT *Client )
525 {
526         assert( Client != NULL );
527
528         if( Client->id[0] ) return Client->id;
529         else return "*";
530 } /* Client_ID */
531
532
533 GLOBAL CHAR *Client_Info( CLIENT *Client )
534 {
535         assert( Client != NULL );
536         return Client->info;
537 } /* Client_Info */
538
539
540 GLOBAL CHAR *Client_User( CLIENT *Client )
541 {
542         assert( Client != NULL );
543         if( Client->user ) return Client->user;
544         else return "~";
545 } /* Client_User */
546
547
548 GLOBAL CHAR *Client_Hostname( CLIENT *Client )
549 {
550         assert( Client != NULL );
551         return Client->host;
552 } /* Client_Hostname */
553
554
555 GLOBAL CHAR *Client_Password( CLIENT *Client )
556 {
557         assert( Client != NULL );
558         return Client->pwd;
559 } /* Client_Password */
560
561
562 GLOBAL CHAR *Client_Modes( CLIENT *Client )
563 {
564         assert( Client != NULL );
565         return Client->modes;
566 } /* Client_Modes */
567
568
569 GLOBAL BOOLEAN Client_OperByMe( CLIENT *Client )
570 {
571         assert( Client != NULL );
572         return Client->oper_by_me;
573 } /* Client_OperByMe */
574
575
576 GLOBAL INT Client_Hops( CLIENT *Client )
577 {
578         assert( Client != NULL );
579         return Client->hops;
580 } /* Client_Hops */
581
582
583 GLOBAL INT Client_Token( CLIENT *Client )
584 {
585         assert( Client != NULL );
586         return Client->token;
587 } /* Client_Token */
588
589
590 GLOBAL CLIENT *Client_NextHop( CLIENT *Client )
591 {
592         CLIENT *c;
593         
594         assert( Client != NULL );
595
596         c = Client;
597         while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server )) c = c->introducer;
598         return c;
599 } /* Client_NextHop */
600
601
602 GLOBAL CHAR *Client_Mask( CLIENT *Client )
603 {
604         /* Client-"ID" liefern, wie sie z.B. fuer
605          * Prefixe benoetigt wird. */
606
607         assert( Client != NULL );
608         
609         if( Client->type == CLIENT_SERVER ) return Client->id;
610
611         sprintf( GetID_Buffer, "%s!%s@%s", Client->id, Client->user, Client->host );
612         return GetID_Buffer;
613 } /* Client_Mask */
614
615
616 GLOBAL CLIENT *Client_Introducer( CLIENT *Client )
617 {
618         assert( Client != NULL );
619         return Client->introducer;
620 } /* Client_Introducer */
621
622
623 GLOBAL BOOLEAN Client_HasMode( CLIENT *Client, CHAR Mode )
624 {
625         assert( Client != NULL );
626         return strchr( Client->modes, Mode ) != NULL;
627 } /* Client_HasMode */
628
629
630 GLOBAL BOOLEAN Client_CheckNick( CLIENT *Client, CHAR *Nick )
631 {
632         /* Nick ueberpruefen */
633
634         CLIENT *c;
635         
636         assert( Client != NULL );
637         assert( Nick != NULL );
638         
639         /* Nick zu lang? */
640         if( strlen( Nick ) > CLIENT_NICK_LEN ) return IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
641
642         /* Nick bereits vergeben? */
643         c = My_Clients;
644         while( c )
645         {
646                 if( strcasecmp( c->id, Nick ) == 0 )
647                 {
648                         /* den Nick gibt es bereits */
649                         IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
650                         return FALSE;
651                 }
652                 c = c->next;
653         }
654
655         return TRUE;
656 } /* Client_CheckNick */
657
658
659 GLOBAL BOOLEAN Client_CheckID( CLIENT *Client, CHAR *ID )
660 {
661         /* Nick ueberpruefen */
662
663         CHAR str[COMMAND_LEN];
664         CLIENT *c;
665
666         assert( Client != NULL );
667         assert( Client->conn_id > NONE );
668         assert( ID != NULL );
669
670         /* Nick zu lang? */
671         if( strlen( ID ) > CLIENT_ID_LEN ) return IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), ID );
672
673         /* ID bereits vergeben? */
674         c = My_Clients;
675         while( c )
676         {
677                 if( strcasecmp( c->id, ID ) == 0 )
678                 {
679                         /* die Server-ID gibt es bereits */
680                         sprintf( str, "ID \"%s\" already registered!", ID );
681                         Log( LOG_ERR, "%s (on connection %d)", str, Client->conn_id );
682                         Conn_Close( Client->conn_id, str, str, TRUE );
683                         return FALSE;
684                 }
685                 c = c->next;
686         }
687
688         return TRUE;
689 } /* Client_CheckID */
690
691
692 GLOBAL CLIENT *Client_Search( CHAR *ID )
693 {
694         /* Client suchen, auf den ID passt */
695
696         CLIENT *c;
697
698         assert( ID != NULL );
699
700         c = My_Clients;
701         while( c )
702         {
703                 if( strcasecmp( c->id, ID ) == 0 ) return c;
704                 c = c->next;
705         }
706         
707         return NULL;
708 } /* Client_Search */
709
710
711 GLOBAL CLIENT *Client_First( VOID )
712 {
713         /* Ersten Client liefern. */
714
715         return My_Clients;
716 } /* Client_First */
717
718
719 GLOBAL CLIENT *Client_Next( CLIENT *c )
720 {
721         /* Naechsten Client liefern. Existiert keiner,
722          * so wird NULL geliefert. */
723
724         assert( c != NULL );
725         return c->next;
726 } /* Client_Next */
727
728
729 LOCAL CLIENT *New_Client_Struct( VOID )
730 {
731         /* Neue CLIENT-Struktur pre-initialisieren */
732         
733         CLIENT *c;
734         INT i;
735         
736         c = malloc( sizeof( CLIENT ));
737         if( ! c )
738         {
739                 Log( LOG_EMERG, "Can't allocate memory!" );
740                 return NULL;
741         }
742
743         c->next = NULL;
744         c->type = CLIENT_UNKNOWN;
745         c->conn_id = NONE;
746         c->introducer = NULL;
747         strcpy( c->id, "" );
748         strcpy( c->pwd, "" );
749         strcpy( c->host, "" );
750         strcpy( c->user, "" );
751         strcpy( c->info, "" );
752         for( i = 0; i < MAX_CHANNELS; c->channels[i++] = NULL );
753         strcpy( c->modes, "" );
754         c->oper_by_me = FALSE;
755         c->hops = -1;
756         c->token = -1;
757
758         return c;
759 } /* New_Client */
760
761
762 /* -eof- */