]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc.c
c6b4fd52d1f77fb461f5ea1ae4a3e8a755da704e
[ngircd-alex.git] / src / ngircd / irc.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: irc.c,v 1.51 2002/02/11 15:15:53 alex Exp $
13  *
14  * irc.c: IRC-Befehle
15  *
16  * $Log: irc.c,v $
17  * Revision 1.51  2002/02/11 15:15:53  alex
18  * - PING und PONG werden nun auch korrekt an andere Server geforwarded.
19  * - bei MODE-Meldungen wird der letzte Parameter nicht mehr mit ":" getrennt.
20  *
21  * Revision 1.50  2002/02/11 01:03:20  alex
22  * - Aenderungen und Anpassungen an Channel-Modes und Channel-User-Modes:
23  *   Modes werden besser geforwarded, lokale User, fuer die ein Channel
24  *   angelegt wird, werden Channel-Operator, etc. pp. ...
25  * - NJOIN's von Servern werden nun korrekt an andere Server weitergeleitet.
26  *
27  * Revision 1.49  2002/02/06 16:51:22  alex
28  * - neue Funktion zur MODE-Behandlung, fuer Channel-Modes vorbereitet.
29  *
30  * Revision 1.48  2002/01/29 00:13:45  alex
31  * - WHOIS zeigt nun auch die Channels an, in denen der jeweilige User Mitglied ist.
32  * - zu jedem Server wird nun der "Top-Server" gespeichert, somit funktioniert
33  *   LINKS wieder korrekt.
34  *
35  * Revision 1.47  2002/01/28 13:05:48  alex
36  * - nach einem JOIN wird die Liste der Mitglieder an den Client geschickt.
37  * - MODE fuer Channels wird nun komplett ignoriert (keine Fehlermeldung mehr).
38  *
39  * Revision 1.46  2002/01/28 01:45:43  alex
40  * - SERVER-Meldungen an neue Server sind nun in der richtigen Reihenfolge.
41  *
42  * Revision 1.45  2002/01/28 01:18:14  alex
43  * - connectierenden Servern werden Channels nun mit NJOIN bekannt gemacht.
44  *
45  * Revision 1.44  2002/01/28 00:55:08  alex
46  * - ein neu connectierender Server wird nun korrekt im Netz bekannt gemacht.
47  *
48  * Revision 1.43  2002/01/27 21:56:39  alex
49  * - IRC_WriteStrServersPrefixID() und IRC_WriteStrClientPrefixID() wieder entfernt.
50  * - einige kleinere Fixes bezueglich Channels ...
51  *
52  * Revision 1.42  2002/01/27 18:28:01  alex
53  * - bei NICK wurde das falsche Prefix an andere Server weitergegeben.
54  *
55  * Revision 1.41  2002/01/27 17:15:49  alex
56  * - anderungen an den Funktions-Prototypen von IRC_WriteStrChannel() und
57  *   IRC_WriteStrChannelPrefix(),
58  * - neue: IRC_WriteStrClientPrefixID() und IRC_WriteStrServersPrefixID().
59  *
60  * Revision 1.40  2002/01/26 18:43:11  alex
61  * - neue Funktionen IRC_WriteStrChannelPrefix() und IRC_WriteStrChannel(),
62  *   die IRC_Write_xxx_Related() sind dafuer entfallen.
63  * - IRC_PRIVMSG() kann nun auch mit Channels als Ziel umgehen.
64  *
65  * Revision 1.39  2002/01/21 00:05:11  alex
66  * - neue Funktionen IRC_JOIN und IRC_PART begonnen, ebenso die Funktionen
67  *   IRC_WriteStrRelatedPrefix und IRC_WriteStrRelatedChannelPrefix().
68  * - diverse Aenderungen im Zusammenhang mit Channels.
69  *
70  * Revision 1.38  2002/01/18 15:31:32  alex
71  * - die User-Modes bei einem NICK von einem Server wurden falsch uebernommen.
72  *
73  * Revision 1.37  2002/01/16 22:10:18  alex
74  * - IRC_LUSERS() implementiert.
75  *
76  * Revision 1.36  2002/01/11 23:50:55  alex
77  * - LINKS implementiert, LUSERS begonnen.
78  *
79  * Revision 1.35  2002/01/09 21:30:45  alex
80  * - WHOIS wurde faelschlicherweise an User geforwarded statt vom Server beantwortet.
81  *
82  * Revision 1.34  2002/01/09 01:09:58  alex
83  * - WHOIS wird im "Strict-RFC-Mode" nicht mehr automatisch geforwarded,
84  * - andere Server werden nun ueber bisherige Server und User informiert.
85  *
86  * Revision 1.33  2002/01/07 23:42:12  alex
87  * - Es werden fuer alle Server eigene Token generiert,
88  * - QUIT von einem Server fuer einen User wird an andere Server geforwarded,
89  * - ebenso NICK-Befehle, die "fremde" User einfuehren.
90  *
91  * Revision 1.32  2002/01/07 16:02:36  alex
92  * - Loglevel von Remote-Mode-Aenderungen angepasst (nun Debug).
93  * - Im Debug-Mode werden nun auch PING's protokolliert.
94  *
95  * Revision 1.31  2002/01/07 15:39:46  alex
96  * - Server nimmt nun Server-Links an: PASS und SERVER entsprechend angepasst.
97  * - MODE und NICK melden nun die Aenderungen an andere Server.
98  *
99  * Revision 1.30  2002/01/06 15:21:29  alex
100  * - Loglevel und Meldungen nochmals ueberarbeitet.
101  * - QUIT und SQUIT forwarden nun den Grund der Trennung,
102  * - WHOIS wird nun immer an den "Original-Server" weitergeleitet.
103  *
104  * Revision 1.29  2002/01/05 23:24:54  alex
105  * - WHOIS erweitert: Anfragen koennen an andere Server weitergeleitet werden.
106  * - Vorbereitungen fuer Ident-Abfragen bei neuen Client-Strukturen.
107  *
108  * Revision 1.28  2002/01/05 20:08:02  alex
109  * - Div. Aenderungen fuer die Server-Links (u.a. WHOIS, QUIT, NICK angepasst).
110  * - Neue Funktionen IRC_WriteStrServer() und IRC_WriteStrServerPrefix().
111  *
112  * Revision 1.27  2002/01/05 19:15:03  alex
113  * - Fehlerpruefung bei select() in der "Hauptschleife" korrigiert.
114  *
115  * Revision 1.26  2002/01/05 16:51:18  alex
116  * - das Passwort von Servern wird nun ueberprueft (PASS- und SERVER-Befehl).
117  *
118  * Revision 1.25  2002/01/05 00:48:33  alex
119  * - bei SQUIT wurde immer die Verbindung getrennt, auch bei Remote-Servern.
120  *
121  * Revision 1.24  2002/01/04 17:58:44  alex
122  * - IRC_WriteStrXXX()-Funktionen eingefuehrt, groessere Anpassungen daran.
123  * - neuer Befehl SQUIT, QUIT an Server-Links angepasst.
124  *
125  * Revision 1.23  2002/01/04 01:36:40  alex
126  * - Loglevel ein wenig angepasst.
127  *
128  * Revision 1.22  2002/01/04 01:21:47  alex
129  * - Client-Strukruren werden nur noch ueber Funktionen angesprochen.
130  * - Weitere Anpassungen und Erweiterungen der Server-Links.
131  *
132  * Revision 1.21  2002/01/03 02:26:51  alex
133  * - neue Befehle SERVER und NJOIN begonnen,
134  * - begonnen, diverse IRC-Befehle an Server-Links anzupassen.
135  *
136  * Revision 1.20  2002/01/02 12:46:41  alex
137  * - die Gross- und Kleinschreibung des Nicks kann mit NICK nun geaendert werden.
138  *
139  * Revision 1.19  2002/01/02 02:51:39  alex
140  * - Copyright-Texte angepasst.
141  * - neuer Befehl "ERROR".
142  *
143  * Revision 1.17  2001/12/31 15:33:13  alex
144  * - neuer Befehl NAMES, kleinere Bugfixes.
145  * - Bug bei PING behoben: war zu restriktiv implementiert :-)
146  *
147  * Revision 1.16  2001/12/31 02:18:51  alex
148  * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
149  * - neuen Header "defines.h" mit (fast) allen Konstanten.
150  * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
151  *
152  * Revision 1.15  2001/12/30 19:26:11  alex
153  * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
154  *
155  * Revision 1.14  2001/12/30 11:42:00  alex
156  * - der Server meldet nun eine ordentliche "Start-Zeit".
157  *
158  * Revision 1.13  2001/12/29 03:10:06  alex
159  * - Neue Funktion IRC_MODE() implementiert, div. Aenderungen.
160  * - neue configure-Optione "--enable-strict-rfc".
161  *
162  * Revision 1.12  2001/12/27 19:17:26  alex
163  * - neue Befehle PRIVMSG, NOTICE, PING.
164  *
165  * Revision 1.11  2001/12/27 16:55:41  alex
166  * - neu: IRC_WriteStrRelated(), Aenderungen auch in IRC_WriteStrClient().
167  *
168  * Revision 1.10  2001/12/26 22:48:53  alex
169  * - MOTD-Datei ist nun konfigurierbar und wird gelesen.
170  *
171  * Revision 1.9  2001/12/26 14:45:37  alex
172  * - "Code Cleanups".
173  *
174  * Revision 1.8  2001/12/26 03:21:46  alex
175  * - PING/PONG-Befehle implementiert,
176  * - Meldungen ueberarbeitet: enthalten nun (fast) immer den Nick.
177  *
178  * Revision 1.7  2001/12/25 23:25:18  alex
179  * - und nochmal Aenderungen am Logging ;-)
180  *
181  * Revision 1.6  2001/12/25 23:13:33  alex
182  * - Debug-Meldungen angepasst.
183  *
184  * Revision 1.5  2001/12/25 22:02:42  alex
185  * - neuer IRC-Befehl "/QUIT". Verbessertes Logging & Debug-Ausgaben.
186  *
187  * Revision 1.4  2001/12/25 19:19:30  alex
188  * - bessere Fehler-Abfragen, diverse Bugfixes.
189  * - Nicks werden nur einmal vergeben :-)
190  * - /MOTD wird unterstuetzt.
191  *
192  * Revision 1.3  2001/12/24 01:34:06  alex
193  * - USER und NICK wird nun in beliebiger Reihenfolge akzeptiert (wg. BitchX)
194  * - MOTD-Ausgabe begonnen zu implementieren.
195  *
196  * Revision 1.2  2001/12/23 21:57:16  alex
197  * - erste IRC-Befehle zu implementieren begonnen.
198  *
199  * Revision 1.1  2001/12/14 08:13:43  alex
200  * - neues Modul begonnen :-)
201  */
202
203
204 #include <portab.h>
205 #include "global.h"
206
207 #include <imp.h>
208 #include <assert.h>
209 #include <errno.h>
210 #include <stdarg.h>
211 #include <stdio.h>
212 #include <stdlib.h>
213 #include <string.h>
214
215 #include "ngircd.h"
216 #include "channel.h"
217 #include "client.h"
218 #include "conf.h"
219 #include "conn.h"
220 #include "log.h"
221 #include "messages.h"
222 #include "parse.h"
223 #include "tool.h"
224
225 #include <exp.h>
226 #include "irc.h"
227
228
229 #define CONNECTED TRUE
230 #define DISCONNECTED FALSE
231
232
233 LOCAL BOOLEAN Hello_User( CLIENT *Client );
234 LOCAL BOOLEAN Show_MOTD( CLIENT *Client );
235
236 LOCAL VOID Kill_Nick( CHAR *Nick );
237
238 LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan );
239
240
241 GLOBAL VOID IRC_Init( VOID )
242 {
243 } /* IRC_Init */
244
245
246 GLOBAL VOID IRC_Exit( VOID )
247 {
248 } /* IRC_Exit */
249
250
251 GLOBAL BOOLEAN IRC_WriteStrClient( CLIENT *Client, CHAR *Format, ... )
252 {
253         CHAR buffer[1000];
254         BOOLEAN ok = CONNECTED;
255         va_list ap;
256
257         assert( Client != NULL );
258         assert( Format != NULL );
259
260         va_start( ap, Format );
261         vsnprintf( buffer, 1000, Format, ap );
262         va_end( ap );
263
264         /* an den Client selber */
265         ok = IRC_WriteStrClientPrefix( Client, Client_ThisServer( ), buffer );
266
267         return ok;
268 } /* IRC_WriteStrClient */
269
270
271 GLOBAL BOOLEAN IRC_WriteStrClientPrefix( CLIENT *Client, CLIENT *Prefix, CHAR *Format, ... )
272 {
273         /* Text an Clients, lokal bzw. remote, senden. */
274
275         CHAR buffer[1000];
276         va_list ap;
277
278         assert( Client != NULL );
279         assert( Format != NULL );
280         assert( Prefix != NULL );
281
282         va_start( ap, Format );
283         vsnprintf( buffer, 1000, Format, ap );
284         va_end( ap );
285
286         return Conn_WriteStr( Client_Conn( Client_NextHop( Client )), ":%s %s", Client_ID( Prefix ), buffer );
287 } /* IRC_WriteStrClientPrefix */
288
289
290 GLOBAL BOOLEAN IRC_WriteStrChannel( CLIENT *Client, CHANNEL *Chan, BOOLEAN Remote, CHAR *Format, ... )
291 {
292         CHAR buffer[1000];
293         va_list ap;
294
295         assert( Client != NULL );
296         assert( Format != NULL );
297
298         va_start( ap, Format );
299         vsnprintf( buffer, 1000, Format, ap );
300         va_end( ap );
301
302         return IRC_WriteStrChannelPrefix( Client, Chan, Client_ThisServer( ), Remote, buffer );
303 } /* IRC_WriteStrChannel */
304
305
306 GLOBAL BOOLEAN IRC_WriteStrChannelPrefix( CLIENT *Client, CHANNEL *Chan, CLIENT *Prefix, BOOLEAN Remote, CHAR *Format, ... )
307 {
308         CHAR buffer[1000];
309         BOOLEAN sock[MAX_CONNECTIONS], ok = CONNECTED, i;
310         CL2CHAN *cl2chan;
311         CLIENT *c;
312         INT s;
313         va_list ap;
314
315         assert( Client != NULL );
316         assert( Chan != NULL );
317         assert( Prefix != NULL );
318         assert( Format != NULL );
319
320         va_start( ap, Format );
321         vsnprintf( buffer, 1000, Format, ap );
322         va_end( ap );
323
324         for( i = 0; i < MAX_CONNECTIONS; i++ ) sock[i] = FALSE;
325
326         /* An alle Clients, die in den selben Channels sind.
327          * Dabei aber nur einmal je Remote-Server */
328         cl2chan = Channel_FirstMember( Chan );
329         while( cl2chan )
330         {
331                 c = Channel_GetClient( cl2chan );
332                 if( ! Remote )
333                 {
334                         if( Client_Conn( c ) <= NONE ) c = NULL;
335                         else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
336                 }
337                 if( c ) c = Client_NextHop( c );
338                         
339                 if( c && ( c != Client ))
340                 {
341                         /* Ok, anderer Client */
342                         s = Client_Conn( c );
343                         assert( s >= 0 );
344                         assert( s < MAX_CONNECTIONS );
345                         sock[s] = TRUE;
346                 }
347                 cl2chan = Channel_NextMember( Chan, cl2chan );
348         }
349
350         /* Senden ... */
351         for( i = 0; i < MAX_CONNECTIONS; i++ )
352         {
353                 if( sock[i] )
354                 {
355                         ok = Conn_WriteStr( i, ":%s %s", Client_ID( Prefix ), buffer );
356                         if( ! ok ) break;
357                 }
358         }
359         return ok;
360 } /* IRC_WriteStrChannelPrefix */
361
362
363 GLOBAL VOID IRC_WriteStrServers( CLIENT *ExceptOf, CHAR *Format, ... )
364 {
365         CHAR buffer[1000];
366         va_list ap;
367
368         assert( Format != NULL );
369
370         va_start( ap, Format );
371         vsnprintf( buffer, 1000, Format, ap );
372         va_end( ap );
373
374         /* an den Client selber */
375         return IRC_WriteStrServersPrefix( ExceptOf, Client_ThisServer( ), buffer );
376 } /* IRC_WriteStrServers */
377
378
379 GLOBAL VOID IRC_WriteStrServersPrefix( CLIENT *ExceptOf, CLIENT *Prefix, CHAR *Format, ... )
380 {
381         CHAR buffer[1000];
382         CLIENT *c;
383         va_list ap;
384         
385         assert( Format != NULL );
386         assert( Prefix != NULL );
387
388         va_start( ap, Format );
389         vsnprintf( buffer, 1000, Format, ap );
390         va_end( ap );
391         
392         c = Client_First( );
393         while( c )
394         {
395                 if(( Client_Type( c ) == CLIENT_SERVER ) && ( Client_Conn( c ) > NONE ) && ( c != Client_ThisServer( )) && ( c != ExceptOf ))
396                 {
397                         /* Ziel-Server gefunden */
398                         IRC_WriteStrClientPrefix( c, Prefix, buffer );
399                 }
400                 c = Client_Next( c );
401         }
402 } /* IRC_WriteStrServersPrefix */
403
404
405 GLOBAL BOOLEAN IRC_PASS( CLIENT *Client, REQUEST *Req )
406 {
407         assert( Client != NULL );
408         assert( Req != NULL );
409
410         /* Fehler liefern, wenn kein lokaler Client */
411         if( Client_Conn( Client ) <= NONE ) return IRC_WriteStrClient( Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID( Client ), Req->command );
412         
413         if(( Client_Type( Client ) == CLIENT_UNKNOWN ) && ( Req->argc == 1))
414         {
415                 /* noch nicht registrierte unbekannte Verbindung */
416                 Log( LOG_DEBUG, "Connection %d: got PASS command ...", Client_Conn( Client ));
417
418                 /* Passwort speichern */
419                 Client_SetPassword( Client, Req->argv[0] );
420
421                 Client_SetType( Client, CLIENT_GOTPASS );
422                 return CONNECTED;
423         }
424         else if((( Client_Type( Client ) == CLIENT_UNKNOWN ) || ( Client_Type( Client ) == CLIENT_UNKNOWNSERVER )) && (( Req->argc == 3 ) || ( Req->argc == 4 )))
425         {
426                 /* noch nicht registrierte Server-Verbindung */
427                 Log( LOG_DEBUG, "Connection %d: got PASS command (new server link) ...", Client_Conn( Client ));
428
429                 /* Passwort speichern */
430                 Client_SetPassword( Client, Req->argv[0] );
431
432                 Client_SetType( Client, CLIENT_GOTPASSSERVER );
433                 return CONNECTED;
434         }
435         else if(( Client_Type( Client ) == CLIENT_UNKNOWN  ) || ( Client_Type( Client ) == CLIENT_UNKNOWNSERVER ))
436         {
437                 /* Falsche Anzahl Parameter? */
438                 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
439         }
440         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
441 } /* IRC_PASS */
442
443
444 GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
445 {
446         CHAR str[LINE_LEN], *ptr;
447         CLIENT *from, *c, *cl;
448         CL2CHAN *cl2chan;
449         INT max_hops, i;
450         CHANNEL *chan;
451         BOOLEAN ok;
452         
453         assert( Client != NULL );
454         assert( Req != NULL );
455
456         /* Fehler liefern, wenn kein lokaler Client */
457         if( Client_Conn( Client ) <= NONE ) return IRC_WriteStrClient( Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID( Client ), Req->command );
458
459         if( Client_Type( Client ) == CLIENT_GOTPASSSERVER )
460         {
461                 /* Verbindung soll als Server-Server-Verbindung registriert werden */
462                 Log( LOG_DEBUG, "Connection %d: got SERVER command (new server link) ...", Client_Conn( Client ));
463
464                 /* Falsche Anzahl Parameter? */
465                 if(( Req->argc != 2 ) && ( Req->argc != 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
466
467                 /* Ist dieser Server bei uns konfiguriert? */
468                 for( i = 0; i < Conf_Server_Count; i++ ) if( strcasecmp( Req->argv[0], Conf_Server[i].name ) == 0 ) break;
469                 if( i >= Conf_Server_Count )
470                 {
471                         /* Server ist nicht konfiguriert! */
472                         Log( LOG_ERR, "Connection %d: Server \"%s\" not configured here!", Client_Conn( Client ), Req->argv[0] );
473                         Conn_Close( Client_Conn( Client ), NULL, "Server not configured here", TRUE );
474                         return DISCONNECTED;
475                 }
476                 if( strcmp( Client_Password( Client ), Conf_Server[i].pwd ) != 0 )
477                 {
478                         /* Falsches Passwort */
479                         Log( LOG_ERR, "Connection %d: Bad password for server \"%s\"!", Client_Conn( Client ), Req->argv[0] );
480                         Conn_Close( Client_Conn( Client ), NULL, "Bad password", TRUE );
481                         return DISCONNECTED;
482                 }
483                 
484                 /* Ist ein Server mit dieser ID bereits registriert? */
485                 if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
486
487                 /* Server-Strukturen fuellen ;-) */
488                 Client_SetID( Client, Req->argv[0] );
489                 Client_SetHops( Client, 1 );
490                 Client_SetInfo( Client, Req->argv[Req->argc - 1] );
491                 
492                 /* Meldet sich der Server bei uns an? */
493                 if( Req->argc == 2 )
494                 {
495                         /* Unseren SERVER- und PASS-Befehl senden */
496                         ok = TRUE;
497                         if( ! IRC_WriteStrClient( Client, "PASS %s "PASSSERVERADD, Conf_Server[i].pwd )) ok = FALSE;
498                         else ok = IRC_WriteStrClient( Client, "SERVER %s 1 :%s", Conf_ServerName, Conf_ServerInfo );
499                         if( ! ok )
500                         {
501                                 Conn_Close( Client_Conn( Client ), "Unexpected server behavior!", NULL, FALSE );
502                                 return DISCONNECTED;
503                         }
504                         Client_SetIntroducer( Client, Client );
505                         Client_SetToken( Client, 1 );
506                 }
507                 else  Client_SetToken( Client, atoi( Req->argv[1] ));
508
509                 Log( LOG_NOTICE, "Server \"%s\" registered (connection %d, 1 hop - direct link).", Client_ID( Client ), Client_Conn( Client ));
510
511                 Client_SetType( Client, CLIENT_SERVER );
512
513                 /* maximalen Hop Count ermitteln */
514                 max_hops = 0;
515                 c = Client_First( );
516                 while( c )
517                 {
518                         if( Client_Hops( c ) > max_hops ) max_hops = Client_Hops( c );
519                         c = Client_Next( c );
520                 }
521                 
522                 /* Alle bisherigen Server dem neuen Server bekannt machen,
523                  * die bisherigen Server ueber den neuen informierenn */
524                 for( i = 0; i < ( max_hops + 1 ); i++ )
525                 {
526                         c = Client_First( );
527                         while( c )
528                         {
529                                 if(( Client_Type( c ) == CLIENT_SERVER ) && ( c != Client ) && ( c != Client_ThisServer( )) && ( Client_Hops( c ) == i ))
530                                 {
531                                         if( Client_Conn( c ) > NONE )
532                                         {
533                                                 /* Dem gefundenen Server gleich den neuen
534                                                 * Server bekannt machen */
535                                                 if( ! IRC_WriteStrClient( c, "SERVER %s %d %d :%s", Client_ID( Client ), Client_Hops( Client ) + 1, Client_MyToken( Client ), Client_Info( Client ))) return DISCONNECTED;
536                                         }
537                                         
538                                         /* Den neuen Server ueber den alten informieren */
539                                         if( ! IRC_WriteStrClientPrefix( Client, Client_Hops( c ) == 1 ? Client_ThisServer( ) : Client_Introducer( c ), "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ))) return DISCONNECTED;
540                                 }
541                                 c = Client_Next( c );
542                         }
543                 }
544
545                 /* alle User dem neuen Server bekannt machen */
546                 c = Client_First( );
547                 while( c )
548                 {
549                         if( Client_Type( c ) == CLIENT_USER )
550                         {
551                                 /* User an neuen Server melden */
552                                 if( ! IRC_WriteStrClient( Client, "NICK %s %d %s %s %d +%s :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_User( c ), Client_Hostname( c ), Client_MyToken( Client_Introducer( c )), Client_Modes( c ), Client_Info( c ))) return DISCONNECTED;
553                         }
554                         c = Client_Next( c );
555                 }
556
557                 /* Channels dem neuen Server bekannt machen */
558                 chan = Channel_First( );
559                 while( chan )
560                 {
561                         sprintf( str, "NJOIN %s :", Channel_Name( chan ));
562
563                         /* alle Member suchen */
564                         cl2chan = Channel_FirstMember( chan );
565                         while( cl2chan )
566                         {
567                                 cl = Channel_GetClient( cl2chan );
568                                 assert( cl != NULL );
569
570                                 /* Nick, ggf. mit Modes, anhaengen */
571                                 if( str[strlen( str ) - 1] != ':' ) strcat( str, "," );
572                                 if( strchr( Channel_UserModes( chan, cl ), 'v' )) strcat( str, "+" );
573                                 if( strchr( Channel_UserModes( chan, cl ), 'o' )) strcat( str, "@" );
574                                 strcat( str, Client_ID( cl ));
575
576                                 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
577                                 {
578                                         /* Zeile senden */
579                                         if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
580                                         sprintf( str, "NJOIN %s :", Channel_Name( chan ));
581                                 }
582                                 
583                                 cl2chan = Channel_NextMember( chan, cl2chan );
584                         }
585
586                         /* noch Daten da? */
587                         if( str[strlen( str ) - 1] != ':')
588                         {
589                                 /* Ja; Also senden ... */
590                                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
591                         }
592
593                         /* naechsten Channel suchen */
594                         chan = Channel_Next( chan );
595                 }
596                 
597                 return CONNECTED;
598         }
599         else if( Client_Type( Client ) == CLIENT_SERVER )
600         {
601                 /* Neuer Server wird im Netz angekuendigt */
602
603                 /* Falsche Anzahl Parameter? */
604                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
605
606                 /* Ist ein Server mit dieser ID bereits registriert? */
607                 if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
608
609                 /* Ueberfluessige Hostnamen aus Info-Text entfernen */
610                 ptr = strchr( Req->argv[3] + 2, '[' );
611                 if( ! ptr ) ptr = Req->argv[3];
612
613                 from = Client_GetFromID( Req->prefix );
614                 if( ! from )
615                 {
616                         /* Hm, Server, der diesen einfuehrt, ist nicht bekannt!? */
617                         Log( LOG_ALERT, "Unknown ID in prefix of SERVER: \"%s\"! (on connection %d)", Req->prefix, Client_Conn( Client ));
618                         Conn_Close( Client_Conn( Client ), NULL, "Unknown ID in prefix of SERVER", TRUE );
619                         return DISCONNECTED;
620                 }
621
622                 /* Neue Client-Struktur anlegen */
623                 c = Client_NewRemoteServer( Client, Req->argv[0], from, atoi( Req->argv[1] ), atoi( Req->argv[2] ), ptr, TRUE );
624                 if( ! c )
625                 {
626                         /* Neue Client-Struktur konnte nicht angelegt werden */
627                         Log( LOG_ALERT, "Can't create client structure for server! (on connection %d)", Client_Conn( Client ));
628                         Conn_Close( Client_Conn( Client ), NULL, "Can't allocate client structure for remote server", TRUE );
629                         return DISCONNECTED;
630                 }
631
632                 /* Log-Meldung zusammenbauen und ausgeben */
633                 if(( Client_Hops( c ) > 1 ) && ( Req->prefix[0] )) sprintf( str, "connected to %s, ", Client_ID( from ));
634                 else strcpy( str, "" );
635                 Log( LOG_NOTICE, "Server \"%s\" registered (via %s, %s%d hop%s).", Client_ID( c ), Client_ID( Client ), str, Client_Hops( c ), Client_Hops( c ) > 1 ? "s": "" );
636
637                 /* Andere Server informieren */
638                 IRC_WriteStrServersPrefix( Client, from, "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ));
639
640                 return CONNECTED;
641         }
642         else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
643 } /* IRC_SERVER */
644
645
646 GLOBAL BOOLEAN IRC_NJOIN( CLIENT *Client, REQUEST *Req )
647 {
648         BOOLEAN is_op, is_voiced;
649         CHAR *channame, *ptr;
650         CHANNEL *chan;
651         CLIENT *c;
652         
653         assert( Client != NULL );
654         assert( Req != NULL );
655
656         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTEREDSERVER_MSG, Client_ID( Client ));
657
658         /* Falsche Anzahl Parameter? */
659         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
660
661         channame = Req->argv[0];
662         ptr = strtok( Req->argv[1], "," );
663         while( ptr )
664         {
665                 is_op = is_voiced = FALSE;
666                 
667                 /* Prefixe abschneiden */
668                 while(( *ptr == '@' ) || ( *ptr == '+' ))
669                 {
670                         if( *ptr == '@' ) is_op = TRUE;
671                         if( *ptr == '+' ) is_voiced = TRUE;
672                         ptr++;
673                 }
674
675                 c = Client_GetFromID( ptr );
676                 if( c )
677                 {
678                         Channel_Join( c, channame );
679                         chan = Channel_Search( channame );
680                         assert( chan != NULL );
681                         
682                         if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
683                         if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );
684                 }
685                 else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame );
686                 
687                 /* naechsten Nick suchen */
688                 ptr = strtok( NULL, "," );
689         }
690
691         /* an andere Server weiterleiten */
692         IRC_WriteStrServersPrefix( Client, Client_ThisServer( ), "NJOIN %s :%s", Req->argv[0], Req->argv[1] );
693
694         return CONNECTED;
695 } /* IRC_NJOIN */
696
697
698 GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req )
699 {
700         CLIENT *intr_c, *target, *c;
701         CHAR *modes;
702
703         assert( Client != NULL );
704         assert( Req != NULL );
705
706         /* Zumindest BitchX sendet NICK-USER in der falschen Reihenfolge. */
707 #ifndef STRICT_RFC
708         if( Client_Type( Client ) == CLIENT_UNKNOWN || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTUSER || Client_Type( Client ) == CLIENT_USER || ( Client_Type( Client ) == CLIENT_SERVER && Req->argc == 1 ))
709 #else
710         if( Client_Type( Client ) == CLIENT_UNKNOWN || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_USER || ( Client_Type( Client ) == CLIENT_SERVER && Req->argc == 1 ))
711 #endif
712         {
713                 /* User-Registrierung bzw. Nick-Aenderung */
714
715                 /* Falsche Anzahl Parameter? */
716                 if( Req->argc != 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
717
718                 /* "Ziel-Client" ermitteln */
719                 if( Client_Type( Client ) == CLIENT_SERVER )
720                 {
721                         target = Client_GetFromID( Req->prefix );
722                         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
723                 }
724                 else
725                 {
726                         /* Ist der Client "restricted"? */
727                         if( Client_HasMode( Client, 'r' )) return IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
728                         target = Client;
729                 }
730
731                 /* Wenn der Client zu seinem eigenen Nick wechseln will, so machen
732                  * wir nichts. So macht es das Original und mind. Snak hat probleme,
733                  * wenn wir es nicht so machen. Ob es so okay ist? Hm ... */
734 #ifndef STRICT_RFC
735                 if( strcmp( Client_ID( target ), Req->argv[0] ) == 0 ) return CONNECTED;
736 #endif
737                 
738                 /* pruefen, ob Nick bereits vergeben. Speziallfall: der Client
739                  * will nur die Gross- und Kleinschreibung aendern. Das darf
740                  * er natuerlich machen :-) */
741                 if( strcasecmp( Client_ID( target ), Req->argv[0] ) != 0 )
742                 {
743                         if( ! Client_CheckNick( target, Req->argv[0] )) return CONNECTED;
744                 }
745
746                 if( Client_Type( Client ) == CLIENT_USER )
747                 {
748                         /* Nick-Aenderung: allen mitteilen! */
749                         Log( LOG_INFO, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] );
750                         IRC_WriteStrClient( Client, "NICK :%s", Req->argv[0] );
751                         IRC_WriteStrServersPrefix( NULL, Client, "NICK :%s", Req->argv[0] );
752                 }
753                 else if( Client_Type( Client ) == CLIENT_SERVER )
754                 {
755                         /* Nick-Aenderung: allen mitteilen! */
756                         Log( LOG_DEBUG, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] );
757                         IRC_WriteStrServersPrefix( Client, target, "NICK :%s", Req->argv[0] );
758                 }
759         
760                 /* Client-Nick registrieren */
761                 Client_SetID( target, Req->argv[0] );
762
763                 if(( Client_Type( target ) != CLIENT_USER ) && ( Client_Type( target ) != CLIENT_SERVER ))
764                 {
765                         /* Neuer Client */
766                         Log( LOG_DEBUG, "Connection %d: got NICK command ...", Client_Conn( Client ));
767                         if( Client_Type( Client ) == CLIENT_GOTUSER ) return Hello_User( Client );
768                         else Client_SetType( Client, CLIENT_GOTNICK );
769                 }
770                 return CONNECTED;
771         }
772         else if( Client_Type( Client ) == CLIENT_SERVER )
773         {
774                 /* Server fuehrt neuen Client ein */
775
776                 /* Falsche Anzahl Parameter? */
777                 if( Req->argc != 7 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
778
779                 /* Nick ueberpruefen */
780                 c = Client_GetFromID( Req->argv[0] );
781                 if( c )
782                 {
783                         /* Der neue Nick ist auf diesem Server bereits registriert:
784                          * sowohl der neue, als auch der alte Client muessen nun
785                          * disconnectiert werden. */
786                         Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] );
787                         Kill_Nick( Req->argv[0] );
788                         return CONNECTED;
789                 }
790
791                 /* Server, zu dem der Client connectiert ist, suchen */
792                 intr_c = Client_GetFromToken( Client, atoi( Req->argv[4] ));
793                 if( ! intr_c )
794                 {
795                         Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] );
796                         Kill_Nick( Req->argv[0] );
797                         return CONNECTED;
798                 }
799
800                 /* Neue Client-Struktur anlegen */
801                 c = Client_NewRemoteUser( intr_c, Req->argv[0], atoi( Req->argv[1] ), Req->argv[2], Req->argv[3], atoi( Req->argv[4] ), Req->argv[5] + 1, Req->argv[6], TRUE );
802                 if( ! c )
803                 {
804                         /* Eine neue Client-Struktur konnte nicht angelegt werden.
805                          * Der Client muss disconnectiert werden, damit der Netz-
806                          * status konsistent bleibt. */
807                         Log( LOG_ALERT, "Can't create client structure! (on connection %d)", Client_Conn( Client ));
808                         Kill_Nick( Req->argv[0] );
809                         return CONNECTED;
810                 }
811
812                 modes = Client_Modes( c );
813                 if( *modes ) Log( LOG_DEBUG, "User \"%s\" (+%s) registered (via %s, on %s, %d hop%s).", Client_Mask( c ), modes, Client_ID( Client ), Client_ID( intr_c ), Client_Hops( c ), Client_Hops( c ) > 1 ? "s": "" );
814                 else Log( LOG_DEBUG, "User \"%s\" registered (via %s, on %s, %d hop%s).", Client_Mask( c ), Client_ID( Client ), Client_ID( intr_c ), Client_Hops( c ), Client_Hops( c ) > 1 ? "s": "" );
815
816                 /* Andere Server, ausser dem Introducer, informieren */
817                 IRC_WriteStrServersPrefix( Client, Client, "NICK %s %d %s %s %d %s :%s", Req->argv[0], atoi( Req->argv[1] ) + 1, Req->argv[2], Req->argv[3], Client_MyToken( intr_c ), Req->argv[5], Req->argv[6] );
818
819                 return CONNECTED;
820         }
821         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
822 } /* IRC_NICK */
823
824
825 GLOBAL BOOLEAN IRC_USER( CLIENT *Client, REQUEST *Req )
826 {
827         assert( Client != NULL );
828         assert( Req != NULL );
829
830 #ifndef STRICT_RFC
831         if( Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_UNKNOWN )
832 #else
833         if( Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTPASS )
834 #endif
835         {
836                 /* Falsche Anzahl Parameter? */
837                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
838
839                 Client_SetUser( Client, Req->argv[0], FALSE );
840                 Client_SetInfo( Client, Req->argv[3] );
841
842                 Log( LOG_DEBUG, "Connection %d: got USER command ...", Client_Conn( Client ));
843                 if( Client_Type( Client ) == CLIENT_GOTNICK ) return Hello_User( Client );
844                 else Client_SetType( Client, CLIENT_GOTUSER );
845                 return CONNECTED;
846         }
847         else if( Client_Type( Client ) == CLIENT_USER || Client_Type( Client ) == CLIENT_SERVER || Client_Type( Client ) == CLIENT_SERVICE )
848         {
849                 return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
850         }
851         else return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
852 } /* IRC_USER */
853
854
855 GLOBAL BOOLEAN IRC_QUIT( CLIENT *Client, REQUEST *Req )
856 {
857         CLIENT *target;
858         
859         assert( Client != NULL );
860         assert( Req != NULL );
861
862         if(( Client_Type( Client ) == CLIENT_USER ) || ( Client_Type( Client ) == CLIENT_SERVICE ))
863         {
864                 /* User / Service */
865                 
866                 /* Falsche Anzahl Parameter? */
867                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
868
869                 if( Req->argc == 0 ) Conn_Close( Client_Conn( Client ), "Got QUIT command.", NULL, TRUE );
870                 else Conn_Close( Client_Conn( Client ), "Got QUIT command.", Req->argv[0], TRUE );
871                 
872                 return DISCONNECTED;
873         }
874         else if ( Client_Type( Client ) == CLIENT_SERVER )
875         {
876                 /* Server */
877
878                 /* Falsche Anzahl Parameter? */
879                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
880
881                 target = Client_Search( Req->prefix );
882                 if( ! target )
883                 {
884                         Log( LOG_ERR, "Got QUIT from %s for unknown client!?", Client_ID( Client ));
885                         return CONNECTED;
886                 }
887
888                 if( Req->argc == 0 ) Client_Destroy( target, "Got QUIT command.", NULL );
889                 else Client_Destroy( target, "Got QUIT command.", Req->argv[0] );
890
891                 return CONNECTED;
892         }
893         else return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
894 } /* IRC_QUIT */
895
896
897 GLOBAL BOOLEAN IRC_SQUIT( CLIENT *Client, REQUEST *Req )
898 {
899         CLIENT *target;
900         
901         assert( Client != NULL );
902         assert( Req != NULL );
903
904         /* SQUIT ist nur fuer Server erlaubt */
905         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
906
907         /* Falsche Anzahl Parameter? */
908         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
909
910         target = Client_GetFromID( Req->argv[0] );
911         if( ! target )
912         {
913                 Log( LOG_ERR, "Got SQUIT from %s for unknown server \%s\"!?", Client_ID( Client ), Req->argv[0] );
914                 return CONNECTED;
915         }
916
917         if( target == Client ) Log( LOG_DEBUG, "Got SQUIT from %s: %s", Client_ID( Client ), Req->argv[1] );
918         else Log( LOG_DEBUG, "Got SQUIT from %s for %s: %s", Client_ID( Client ), Client_ID( target ), Req->argv[1] );
919
920         /* SQUIT an alle Server weiterleiten */
921         IRC_WriteStrServers( Client, "SQUIT %s :%s", Req->argv[0], Req->argv[1] );
922
923         if( Client_Conn( target ) > NONE )
924         {
925                 if( Req->argv[1][0] ) Conn_Close( Client_Conn( target ), "Got SQUIT command.", Req->argv[1], TRUE );
926                 else Conn_Close( Client_Conn( target ), "Got SQUIT command.", NULL, TRUE );
927                 return DISCONNECTED;
928         }
929         else
930         {
931                 Client_Destroy( target, "Got SQUIT command.", Req->argv[1] );
932                 return CONNECTED;
933         }
934 } /* IRC_SQUIT */
935
936
937 GLOBAL BOOLEAN IRC_PING( CLIENT *Client, REQUEST *Req )
938 {
939         CLIENT *target, *from;
940         
941         assert( Client != NULL );
942         assert( Req != NULL );
943
944         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
945
946         /* Falsche Anzahl Parameter? */
947         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NOORIGIN_MSG, Client_ID( Client ));
948         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
949         
950         if( Req->argc == 2 )
951         {
952                 /* es wurde ein Ziel-Client angegeben */
953                 target = Client_GetFromID( Req->argv[1] );
954                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
955                 if( target != Client_ThisServer( ))
956                 {
957                         /* ok, forwarden */
958                         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
959                         else from = Client;
960                         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
961                         return IRC_WriteStrClientPrefix( Client_NextHop( target ), from, "PING %s :%s", Client_ID( from ), Req->argv[1] );
962                 }
963         }
964
965         Log( LOG_DEBUG, "Connection %d: got PING, sending PONG ...", Client_Conn( Client ));
966         return IRC_WriteStrClient( Client, "PONG %s :%s", Client_ID( Client_ThisServer( )), Client_ID( Client ));
967 } /* IRC_PING */
968
969
970 GLOBAL BOOLEAN IRC_PONG( CLIENT *Client, REQUEST *Req )
971 {
972         CLIENT *target, *from;
973
974         assert( Client != NULL );
975         assert( Req != NULL );
976
977         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
978
979         /* Falsche Anzahl Parameter? */
980         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NOORIGIN_MSG, Client_ID( Client ));
981         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
982
983         /* forwarden? */
984         if( Req->argc == 2 )
985         {
986                 target = Client_GetFromID( Req->argv[1] );
987                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
988                 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
989                 else from = Client;
990                 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
991                 return IRC_WriteStrClientPrefix( Client_NextHop( target ), from, "PONG %s :%s", Client_ID( from ), Req->argv[1] );
992         }
993
994         /* Der Connection-Timestamp wurde schon beim Lesen aus dem Socket
995          * aktualisiert, daher muss das hier nicht mehr gemacht werden. */
996
997         if( Client_Conn( Client ) > NONE ) Log( LOG_DEBUG, "Connection %d: received PONG. Lag: %d seconds.", Client_Conn( Client ), time( NULL ) - Conn_LastPing( Client_Conn( Client )));
998         else Log( LOG_DEBUG, "Connection %d: received PONG.", Client_Conn( Client ));
999
1000         return CONNECTED;
1001 } /* IRC_PONG */
1002
1003
1004 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
1005 {
1006         assert( Client != NULL );
1007         assert( Req != NULL );
1008
1009         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1010
1011         /* Falsche Anzahl Parameter? */
1012         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1013
1014         return Show_MOTD( Client );
1015 } /* IRC_MOTD */
1016
1017
1018 GLOBAL BOOLEAN IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
1019 {
1020         CLIENT *to, *from;
1021         CHANNEL *chan;
1022         
1023         assert( Client != NULL );
1024         assert( Req != NULL );
1025
1026         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1027
1028         /* Falsche Anzahl Parameter? */
1029         if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
1030         if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
1031         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1032
1033         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1034         else from = Client;
1035         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1036
1037         to = Client_Search( Req->argv[0] );
1038         if( to )
1039         {
1040                 /* Okay, Ziel ist ein User */
1041                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
1042                 return IRC_WriteStrClientPrefix( to, from, "PRIVMSG %s :%s", Client_ID( to ), Req->argv[1] );
1043         }
1044
1045         chan = Channel_Search( Req->argv[0] );
1046         if( chan )
1047         {
1048                 /* Okay, Ziel ist ein Channel */
1049                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
1050                 return IRC_WriteStrChannelPrefix( Client, chan, from, TRUE, "PRIVMSG %s :%s", Req->argv[0], Req->argv[1] );
1051         }
1052
1053         return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
1054 } /* IRC_PRIVMSG */
1055
1056
1057 GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
1058 {
1059         CLIENT *to, *from;
1060
1061         assert( Client != NULL );
1062         assert( Req != NULL );
1063
1064         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1065
1066         /* Falsche Anzahl Parameter? */
1067         if( Req->argc != 2 ) return CONNECTED;
1068
1069         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1070         else from = Client;
1071         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1072
1073         to = Client_Search( Req->argv[0] );
1074         if( to )
1075         {
1076                 /* Okay, Ziel ist ein User */
1077                 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
1078         }
1079         else return CONNECTED;
1080 } /* IRC_NOTICE */
1081
1082
1083 GLOBAL BOOLEAN IRC_MODE( CLIENT *Client, REQUEST *Req )
1084 {
1085         CHAR *mode_ptr, the_modes[CLIENT_MODE_LEN], x[2];
1086         BOOLEAN set, ok;
1087         CHANNEL *chan;
1088         CLIENT *cl, *chan_cl;
1089         
1090         assert( Client != NULL );
1091         assert( Req != NULL );
1092
1093         cl = chan_cl = NULL;
1094         chan = NULL;
1095
1096         /* Valider Client? */
1097         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1098
1099         /* Keine Parameter? */
1100         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1101
1102         /* Ziel suchen: Client bzw. Channel */
1103         if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
1104         if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
1105
1106         /* Kein Ziel gefunden? */
1107         if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
1108
1109         assert(( cl && chan ) != TRUE );
1110
1111         /* Falsche Anzahl Parameter? */
1112         if(( cl ) && ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1113         if(( chan ) && ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1114
1115         /* Client ermitteln, wenn bei Channel-Modes mit 3 Parametern */
1116         if(( chan ) && (Req->argc == 3 ))
1117         {
1118                 chan_cl = Client_Search( Req->argv[2] );
1119                 if( ! chan_cl ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
1120         }
1121         
1122         /* Wenn Anfragender ein User ist: Zugriff erlaubt? */
1123         if( Client_Type( Client ) == CLIENT_USER )
1124         {
1125                 if( cl )
1126                 {
1127                         /* MODE ist nur fuer sich selber zulaessig! */
1128                         if( cl != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
1129                 }
1130                 if( chan )
1131                 {
1132                         /* Darf der User die Channel-Modes ermitteln? */
1133                 }
1134         }
1135
1136         /* Werden die Modes "nur" erfragt? */
1137         if(( cl ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( cl ));
1138         if(( chan ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEISCHAN_MSG, Client_ID( Client ), Channel_Name( chan ), Channel_Modes( chan ));
1139
1140         mode_ptr = Req->argv[1];
1141
1142         /* Sollen Modes gesetzt oder geloescht werden? */
1143         if( cl )
1144         {
1145                 if( *mode_ptr == '+' ) set = TRUE;
1146                 else if( *mode_ptr == '-' ) set = FALSE;
1147                 else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
1148                 mode_ptr++;
1149         }
1150         else
1151         {
1152                 if( *mode_ptr == '-' ) set = FALSE;
1153                 else set = TRUE;
1154                 if(( *mode_ptr == '-' ) || ( *mode_ptr == '+' )) mode_ptr++;
1155         }
1156
1157         /* Reply-String mit Aenderungen vorbereiten */
1158         if( set ) strcpy( the_modes, "+" );
1159         else strcpy( the_modes, "-" );
1160
1161         ok = TRUE;
1162         x[1] = '\0';
1163         while( *mode_ptr )
1164         {
1165                 x[0] = '\0';
1166                 if( Client_Type( Client ) == CLIENT_SERVER )
1167                 {
1168                         /* Befehl kommt von einem Server, daher
1169                          * trauen wir ihm "unbesehen" ... */
1170                         x[0] = *mode_ptr;
1171                 }
1172                 else
1173                 {
1174                         /* Modes validieren */
1175                         if( cl )
1176                         {
1177                                 /* User-Modes */
1178                                 switch( *mode_ptr )
1179                                 {
1180                                         case 'i':
1181                                                 /* invisible */
1182                                                 x[0] = 'i';
1183                                                 break;
1184                                         case 'r':
1185                                                 /* restricted (kann nur gesetzt werden) */
1186                                                 if( set ) x[0] = 'r';
1187                                                 else ok = IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
1188                                                 break;
1189                                         case 'o':
1190                                                 /* operator (kann nur geloescht werden) */
1191                                                 if( ! set )
1192                                                 {
1193                                                         Client_SetOperByMe( Client, FALSE );
1194                                                         x[0] = 'o';
1195                                                 }
1196                                                 else ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
1197                                                 break;
1198                                         default:
1199                                                 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
1200                                                 x[0] = '\0';
1201                                 }
1202                         }
1203                         if( chan )
1204                         {
1205                                 /* Channel-Modes oder Channel-User-Modes */
1206                                 if( chan_cl )
1207                                 {
1208                                         /* Channel-User-Modes */
1209                                         Log( LOG_DEBUG, "Channel-User-Mode '%c' not supported ...", *mode_ptr );
1210                                 }
1211                                 else
1212                                 {
1213                                         /* Channel-Modes */
1214                                         Log( LOG_DEBUG, "Channel-Mode '%c' not supported ...", *mode_ptr );
1215                                 }
1216                         }
1217                 }
1218                 if( ! ok ) break;
1219                 
1220                 mode_ptr++;
1221                 if( ! x[0] ) continue;
1222
1223                 /* Okay, gueltigen Mode gefunden */
1224                 if( cl )
1225                 {
1226                         /* Es geht um User-Modes */
1227                         if( set )
1228                         {
1229                                 /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
1230                                 if( Client_ModeAdd( cl, x[0] )) strcat( the_modes, x );
1231                         }
1232                         else
1233                         {
1234                                 /* Modes geloescht. Wenn der Client ihn hatte: merken */
1235                                 if( Client_ModeDel( cl, x[0] )) strcat( the_modes, x );
1236                         }
1237                 }
1238                 if( chan )
1239                 {
1240                         /* Es geht um Channel-Modes oder Channel-User-Modes */
1241                         if( chan_cl )
1242                         {
1243                                 /* Channel-User-Modes */
1244                                 if( set )
1245                                 {
1246                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
1247                                         if( Channel_UserModeAdd( chan, chan_cl, x[0] )) strcat( the_modes, x );
1248                                 }
1249                                 else
1250                                 {
1251                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
1252                                         if( Channel_UserModeDel( chan, chan_cl, x[0] )) strcat( the_modes, x );
1253                                 }
1254                         }
1255                         else
1256                         {
1257                                 /* Channel-Mode */
1258                                 if( set )
1259                                 {
1260                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
1261                                         if( Channel_ModeAdd( chan, x[0] )) strcat( the_modes, x );
1262                                 }
1263                                 else
1264                                 {
1265                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
1266                                         if( Channel_ModeDel( chan, x[0] )) strcat( the_modes, x );
1267                                 }
1268                         }
1269                 }
1270         }
1271
1272         /* Wurden Modes geaendert? */
1273         if( the_modes[1] )
1274         {
1275                 if( cl )
1276                 {
1277                         /* Client-Mode */
1278                         if( Client_Type( Client ) == CLIENT_SERVER )
1279                         {
1280                                 /* Modes an andere Server forwarden */
1281                                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :%s", Client_ID( cl ), the_modes );
1282                         }
1283                         else
1284                         {
1285                                 /* Bestaetigung an Client schicken & andere Server informieren */
1286                                 ok = IRC_WriteStrClient( Client, "MODE %s %s", Client_ID( cl ), the_modes );
1287                                 IRC_WriteStrServers( Client, "MODE %s :%s", Client_ID( cl ), the_modes );
1288                         }
1289                         Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
1290                 }
1291                 if( chan )
1292                 {
1293                         /* Channel-Modes oder Channel-User-Mode */
1294                         if( chan_cl )
1295                         {
1296                                 /* Channel-User-Mode */
1297                                 if( Client_Type( Client ) == CLIENT_SERVER )
1298                                 {
1299                                         /* Modes an andere Server und Channel-User forwarden */
1300                                         IRC_WriteStrServersPrefix( Client, Client, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1301                                         IRC_WriteStrChannelPrefix( Client, chan, Client, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1302                                 }
1303                                 else
1304                                 {
1305                                         /* Bestaetigung an Client schicken & andere Server informieren */
1306                                         ok = IRC_WriteStrClient( Client, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1307                                         IRC_WriteStrServersPrefix( Client, Client, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1308                                         IRC_WriteStrChannelPrefix( Client, chan, Client, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1309                                 }
1310                                 Log( LOG_DEBUG, "User \"%s\" on %s: Mode change, now \"%s\".", Client_Mask( chan_cl), Channel_Name( chan ), Channel_UserModes( chan, chan_cl ));
1311                         }
1312                         else
1313                         {
1314                                 /* Channel-Mode */
1315                                 if( Client_Type( Client ) == CLIENT_SERVER )
1316                                 {
1317                                         /* Modes an andere Server forwarden */
1318                                         IRC_WriteStrServersPrefix( Client, Client, "MODE %s :%s", Channel_Name( chan ), the_modes );
1319                                 }
1320                                 else
1321                                 {
1322                                         /* Bestaetigung an Client schicken & andere Server informieren */
1323                                         ok = IRC_WriteStrClient( Client, "MODE %s %s", Channel_Name( chan ), the_modes );
1324                                         IRC_WriteStrServers( Client, "MODE %s :%s", Channel_Name( chan ), the_modes );
1325                                 }
1326                                 Log( LOG_DEBUG, "Channel \"%s\": Mode change, now \"%s\".", Channel_Name( chan ), Channel_Modes( chan ));
1327                         }
1328                 }
1329         }
1330
1331         return ok;
1332 } /* IRC_MODE */
1333
1334
1335 GLOBAL BOOLEAN IRC_OPER( CLIENT *Client, REQUEST *Req )
1336 {
1337         INT i;
1338         
1339         assert( Client != NULL );
1340         assert( Req != NULL );
1341
1342         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1343         
1344         /* Falsche Anzahl Parameter? */
1345         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1346
1347         /* Operator suchen */
1348         for( i = 0; i < Conf_Oper_Count; i++)
1349         {
1350                 if( Conf_Oper[i].name[0] && Conf_Oper[i].pwd[0] && ( strcmp( Conf_Oper[i].name, Req->argv[0] ) == 0 )) break;
1351         }
1352         if( i >= Conf_Oper_Count )
1353         {
1354                 Log( LOG_WARNING, "Got invalid OPER from \"%s\": Name \"%s\" not configured!", Client_Mask( Client ), Req->argv[0] );
1355                 return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
1356         }
1357
1358         /* Stimmt das Passwort? */
1359         if( strcmp( Conf_Oper[i].pwd, Req->argv[1] ) != 0 )
1360         {
1361                 Log( LOG_WARNING, "Got invalid OPER from \"%s\": Bad password for \"%s\"!", Client_Mask( Client ), Conf_Oper[i].name );
1362                 return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
1363         }
1364         
1365         if( ! Client_HasMode( Client, 'o' ))
1366         {
1367                 /* noch kein o-Mode gesetzt */
1368                 Client_ModeAdd( Client, 'o' );
1369                 if( ! IRC_WriteStrClient( Client, "MODE %s :+o", Client_ID( Client ))) return DISCONNECTED;
1370                 IRC_WriteStrServersPrefix( NULL, Client, "MODE %s :+o", Client_ID( Client ));
1371         }
1372
1373         if( ! Client_OperByMe( Client )) Log( LOG_NOTICE, "Got valid OPER from \"%s\", user is an IRC operator now.", Client_Mask( Client ));
1374
1375         Client_SetOperByMe( Client, TRUE );
1376         return IRC_WriteStrClient( Client, RPL_YOUREOPER_MSG, Client_ID( Client ));
1377 } /* IRC_OPER */
1378
1379
1380 GLOBAL BOOLEAN IRC_DIE( CLIENT *Client, REQUEST *Req )
1381 {
1382         assert( Client != NULL );
1383         assert( Req != NULL );
1384
1385         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1386
1387         /* Falsche Anzahl Parameter? */
1388         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1389
1390         if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
1391
1392         Log( LOG_NOTICE, "Got DIE command from \"%s\", going down!", Client_Mask( Client ));
1393         NGIRCd_Quit = TRUE;
1394         return CONNECTED;
1395 } /* IRC_DIE */
1396
1397
1398 GLOBAL BOOLEAN IRC_RESTART( CLIENT *Client, REQUEST *Req )
1399 {
1400         assert( Client != NULL );
1401         assert( Req != NULL );
1402
1403         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1404
1405         /* Falsche Anzahl Parameter? */
1406         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1407
1408         if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
1409
1410         Log( LOG_NOTICE, "Got RESTART command from \"%s\", going down!", Client_Mask( Client ));
1411         NGIRCd_Restart = TRUE;
1412         return CONNECTED;
1413 } /* IRC_RESTART */
1414
1415
1416 GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req )
1417 {
1418         CHAR rpl[COMMAND_LEN];
1419         CLIENT *c;
1420         
1421         assert( Client != NULL );
1422         assert( Req != NULL );
1423
1424         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1425
1426         /* Falsche Anzahl Parameter? */
1427         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1428
1429         /* Noch alle User ausgeben, die in keinem Channel sind */
1430         rpl[0] = '\0';
1431         c = Client_First( );
1432         while( c )
1433         {
1434                 if( Client_Type( c ) == CLIENT_USER )
1435                 {
1436                         /* Okay, das ist ein User */
1437                         strcat( rpl, Client_ID( c ));
1438                         strcat( rpl, " " );
1439                 }
1440
1441                 /* Antwort zu lang? Splitten. */
1442                 if( strlen( rpl ) > 480 )
1443                 {
1444                         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
1445                         if( ! IRC_WriteStrClient( Client, RPL_NAMREPLY_MSG, Client_ID( Client ), "*", "*", rpl )) return DISCONNECTED;
1446                         rpl[0] = '\0';
1447                 }
1448                 
1449                 c = Client_Next( c );
1450         }
1451         if( rpl[0] )
1452         {
1453                 /* es wurden User gefunden */
1454                 if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
1455                 if( ! IRC_WriteStrClient( Client, RPL_NAMREPLY_MSG, Client_ID( Client ), "*", "*", rpl )) return DISCONNECTED;
1456         }
1457         return IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), "*" );
1458 } /* IRC_NAMES */
1459
1460
1461 GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
1462 {
1463         CHAR rpl[COMMAND_LEN];
1464         CLIENT *c;
1465         CHAR *ptr;
1466         INT i;
1467         
1468         assert( Client != NULL );
1469         assert( Req != NULL );
1470
1471         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1472
1473         /* Falsche Anzahl Parameter? */
1474         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1475
1476         strcpy( rpl, RPL_ISON_MSG );
1477         for( i = 0; i < Req->argc; i++ )
1478         {
1479                 ptr = strtok( Req->argv[i], " " );
1480                 while( ptr )
1481                 {
1482                         ngt_TrimStr( ptr );
1483                         c = Client_GetFromID( ptr );
1484                         if( c && ( Client_Type( c ) == CLIENT_USER ))
1485                         {
1486                                 /* Dieser Nick ist "online" */
1487                                 strcat( rpl, ptr );
1488                                 strcat( rpl, " " );
1489                         }
1490                         ptr = strtok( NULL, " " );
1491                 }
1492         }
1493         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
1494
1495         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
1496 } /* IRC_ISON */
1497
1498
1499 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
1500 {
1501         CLIENT *from, *target, *c;
1502         CHAR str[LINE_LEN + 1], *ptr = NULL;
1503         CL2CHAN *cl2chan;
1504         CHANNEL *chan;
1505         
1506         assert( Client != NULL );
1507         assert( Req != NULL );
1508
1509         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1510
1511         /* Falsche Anzahl Parameter? */
1512         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1513
1514         /* Client suchen */
1515         c = Client_GetFromID( Req->argv[Req->argc - 1] );
1516         if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
1517
1518         /* Empfaenger des WHOIS suchen */
1519         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1520         else from = Client;
1521         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1522         
1523         /* Forwarden an anderen Server? */
1524         if( Req->argc > 1 )
1525         {
1526                 /* angegebenen Ziel-Server suchen */
1527                 target = Client_GetFromID( Req->argv[1] );
1528                 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
1529                 ptr = Req->argv[1];
1530         }
1531 #ifndef STRICT_RFC
1532         else if( Client_Conn( c ) == NONE )
1533         {
1534                 /* Client ist nicht von uns. Ziel-Server suchen */
1535                 target = c;
1536                 ptr = Req->argv[0];
1537         }
1538 #endif
1539         else target = NULL;
1540         
1541         if( target && ( Client_NextHop( target ) != Client_ThisServer( )) && ( Client_Type( Client_NextHop( target )) == CLIENT_SERVER )) return IRC_WriteStrClientPrefix( target, from, "WHOIS %s :%s", Req->argv[0], ptr );
1542         
1543         /* Nick, User und Name */
1544         if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
1545
1546         /* Server */
1547         if( ! IRC_WriteStrClient( from, RPL_WHOISSERVER_MSG, Client_ID( from ), Client_ID( c ), Client_ID( Client_Introducer( c )), Client_Info( Client_Introducer( c )))) return DISCONNECTED;
1548
1549         /* Channels */
1550         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
1551         cl2chan = Channel_FirstChannelOf( c );
1552         while( cl2chan )
1553         {
1554                 chan = Channel_GetChannel( cl2chan );
1555                 assert( chan != NULL );
1556                 
1557                 /* Channel-Name anhaengen */
1558                 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
1559                 if( strchr( Channel_UserModes( chan, c ), 'v' )) strcat( str, "+" );
1560                 if( strchr( Channel_UserModes( chan, c ), 'o' )) strcat( str, "@" );
1561                 strcat( str, Channel_Name( chan ));
1562
1563                 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
1564                 {
1565                         /* Zeile wird zu lang: senden! */
1566                         if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
1567                         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
1568                 }
1569
1570                 /* naechstes Mitglied suchen */
1571                 cl2chan = Channel_NextChannelOf( c, cl2chan );
1572         }
1573         if( str[strlen( str ) - 1] != ':')
1574         {
1575                 /* Es sind noch Daten da, die gesendet werden muessen */
1576                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
1577         }
1578         
1579         /* IRC-Operator? */
1580         if( Client_HasMode( c, 'o' ))
1581         {
1582                 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
1583         }
1584
1585         /* Idle (nur lokale Clients) */
1586         if( Client_Conn( c ) > NONE )
1587         {
1588                 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
1589         }
1590
1591         /* End of Whois */
1592         return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
1593 } /* IRC_WHOIS */
1594
1595
1596 GLOBAL BOOLEAN IRC_USERHOST( CLIENT *Client, REQUEST *Req )
1597 {
1598         CHAR rpl[COMMAND_LEN];
1599         CLIENT *c;
1600         INT max, i;
1601
1602         assert( Client != NULL );
1603         assert( Req != NULL );
1604
1605         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1606
1607         /* Falsche Anzahl Parameter? */
1608         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1609
1610         if( Req->argc > 5 ) max = 5;
1611         else max = Req->argc;
1612         
1613         strcpy( rpl, RPL_USERHOST_MSG );
1614         for( i = 0; i < max; i++ )
1615         {
1616                 c = Client_GetFromID( Req->argv[i] );
1617                 if( c && ( Client_Type( c ) == CLIENT_USER ))
1618                 {
1619                         /* Dieser Nick ist "online" */
1620                         strcat( rpl, Client_ID( c ));
1621                         if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
1622                         strcat( rpl, "=" );
1623                         if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
1624                         else strcat( rpl, "+" );
1625                         strcat( rpl, Client_User( c ));
1626                         strcat( rpl, "@" );
1627                         strcat( rpl, Client_Hostname( c ));
1628                         strcat( rpl, " " );
1629                 }
1630         }
1631         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
1632
1633         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
1634 } /* IRC_USERHOST */
1635
1636
1637 GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req )
1638 {
1639         assert( Client != NULL );
1640         assert( Req != NULL );
1641
1642         if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
1643         else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
1644
1645         return CONNECTED;
1646 } /* IRC_ERROR */
1647
1648
1649 GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req )
1650 {
1651         CLIENT *target, *from;
1652         INT cnt;
1653         
1654         assert( Client != NULL );
1655         assert( Req != NULL );
1656
1657         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1658
1659         /* Falsche Anzahl Parameter? */
1660         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1661
1662         /* Absender ermitteln */
1663         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1664         else from = Client;
1665         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1666
1667         /* An anderen Server forwarden? */
1668         if( Req->argc == 2 )
1669         {
1670                 target = Client_GetFromID( Req->argv[1] );
1671                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
1672                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
1673         }
1674
1675         /* Wer ist der Absender? */
1676         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
1677         else target = Client;
1678         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1679         
1680         /* Users, Services und Serevr im Netz */
1681         if( ! IRC_WriteStrClient( target, RPL_LUSERCLIENT_MSG, Client_ID( target ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
1682
1683         /* IRC-Operatoren im Netz */
1684         cnt = Client_OperCount( );
1685         if( cnt > 0 )
1686         {
1687                 if( ! IRC_WriteStrClient( target, RPL_LUSEROP_MSG, Client_ID( target ), cnt )) return DISCONNECTED;
1688         }
1689
1690         /* Unbekannt Verbindungen */
1691         cnt = Client_UnknownCount( );
1692         if( cnt > 0 )
1693         {
1694                 if( ! IRC_WriteStrClient( target, RPL_LUSERUNKNOWN_MSG, Client_ID( target ), cnt )) return DISCONNECTED;
1695         }
1696
1697         /* Channels im Netz */
1698         if( ! IRC_WriteStrClient( target, RPL_LUSERCHANNELS_MSG, Client_ID( target ), Channel_Count( ))) return DISCONNECTED;
1699
1700         /* Channels im Netz */
1701         if( ! IRC_WriteStrClient( target, RPL_LUSERME_MSG, Client_ID( target ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
1702
1703         return CONNECTED;
1704 } /* IRC_LUSERS */
1705
1706
1707 GLOBAL BOOLEAN IRC_LINKS( CLIENT *Client, REQUEST *Req )
1708 {
1709         CLIENT *target, *from, *c;
1710         CHAR *mask;
1711         
1712         assert( Client != NULL );
1713         assert( Req != NULL );
1714
1715         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1716
1717         /* Falsche Anzahl Parameter? */
1718         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1719
1720         /* Server-Mask ermitteln */
1721         if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
1722         else mask = "*";
1723
1724         /* Absender ermitteln */
1725         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1726         else from = Client;
1727         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1728         
1729         /* An anderen Server forwarden? */
1730         if( Req->argc == 2 )
1731         {
1732                 target = Client_GetFromID( Req->argv[0] );
1733                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
1734                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
1735         }
1736
1737         /* Wer ist der Absender? */
1738         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
1739         else target = Client;
1740         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1741         
1742         c = Client_First( );
1743         while( c )
1744         {
1745                 if( Client_Type( c ) == CLIENT_SERVER )
1746                 {
1747                         if( ! IRC_WriteStrClient( target, RPL_LINKS_MSG, Client_ID( target ), Client_ID( c ), Client_ID( Client_TopServer( c ) ? Client_TopServer( c ) : Client_ThisServer( )), Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
1748                 }
1749                 c = Client_Next( c );
1750         }
1751         
1752         return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
1753 } /* IRC_LINKS */
1754
1755
1756 GLOBAL BOOLEAN IRC_JOIN( CLIENT *Client, REQUEST *Req )
1757 {
1758         CHAR *channame, *flags, modes[8];
1759         BOOLEAN is_new_chan;
1760         CLIENT *target;
1761         CHANNEL *chan;
1762         
1763         assert( Client != NULL );
1764         assert( Req != NULL );
1765
1766         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1767
1768         /* Falsche Anzahl Parameter? */
1769         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1770
1771         /* Wer ist der Absender? */
1772         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
1773         else target = Client;
1774         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1775         
1776         /* Channel-Namen durchgehen */
1777         channame = strtok( Req->argv[0], "," );
1778         while( channame )
1779         {
1780                 /* wird der Channel neu angelegt? */
1781                 flags = NULL;
1782
1783                 if( Channel_Search( channame )) is_new_chan = FALSE;
1784                 else is_new_chan = TRUE;
1785
1786                 /* Hat ein Server Channel-User-Modes uebergeben? */
1787                 if( Client_Type( Client ) == CLIENT_SERVER )
1788                 {
1789                         /* Channel-Flags extrahieren */
1790                         flags = strchr( channame, 0x7 );
1791                         if( flags ) *flags++ = '\0';
1792                 }
1793
1794                 /* neuer Channel udn lokaler Client? */
1795                 if( is_new_chan && ( Client_Type( Client ) == CLIENT_USER ))
1796                 {
1797                         /* Dann soll der Client Channel-Operator werden! */
1798                         flags = "o";
1799                 }
1800
1801                 /* Channel joinen (und ggf. anlegen) */
1802                 if( ! Channel_Join( target, channame ))
1803                 {
1804                         /* naechsten Namen ermitteln */
1805                         channame = strtok( NULL, "," );
1806                         continue;
1807                 }
1808                 chan = Channel_Search( channame );
1809                 assert( chan != NULL );
1810
1811                 /* Modes setzen (wenn vorhanden) */
1812                 while( flags && *flags )
1813                 {
1814                         Channel_UserModeAdd( chan, target, *flags );
1815                         flags++;
1816                 }
1817
1818                 /* Muessen Modes an andere Server gemeldet werden? */
1819                 strcpy( &modes[1], Channel_UserModes( chan, target ));
1820                 if( modes[1] ) modes[0] = 0x7;
1821                 else modes[0] = '\0';
1822
1823                 /* An andere Server weiterleiten */
1824                 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
1825
1826                 /* im Channel bekannt machen */
1827                 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
1828                 if( modes[1] )
1829                 {
1830                         /* Modes im Channel bekannt machen */
1831                         IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s %s :%s", channame, modes, Client_ID( target ));
1832                 }
1833
1834                 if( Client_Type( Client ) == CLIENT_USER )
1835                 {
1836                         /* an Client bestaetigen */
1837                         IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
1838                         /* Topic an Client schicken */
1839                         IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, "What a wonderful channel!" );
1840                         /* Mitglieder an Client Melden */
1841                         Send_NAMES( Client, chan );
1842                 }
1843                 
1844                 /* naechsten Namen ermitteln */
1845                 channame = strtok( NULL, "," );
1846         }
1847         return CONNECTED;
1848 } /* IRC_JOIN */
1849
1850
1851 GLOBAL BOOLEAN IRC_PART( CLIENT *Client, REQUEST *Req )
1852 {
1853         CLIENT *target;
1854         CHAR *chan;
1855
1856         assert( Client != NULL );
1857         assert( Req != NULL );
1858
1859         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1860
1861         /* Falsche Anzahl Parameter? */
1862         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1863
1864         /* Wer ist der Absender? */
1865         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
1866         else target = Client;
1867         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1868
1869         /* Channel-Namen durchgehen */
1870         chan = strtok( Req->argv[0], "," );
1871         while( chan )
1872         {
1873                 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
1874                 {
1875                         /* naechsten Namen ermitteln */
1876                         chan = strtok( NULL, "," );
1877                         continue;
1878                 }
1879
1880                 /* naechsten Namen ermitteln */
1881                 chan = strtok( NULL, "," );
1882         }
1883         return CONNECTED;
1884 } /* IRC_PART */
1885
1886
1887 LOCAL BOOLEAN Hello_User( CLIENT *Client )
1888 {
1889         assert( Client != NULL );
1890
1891         /* Passwort ueberpruefen */
1892         if( strcmp( Client_Password( Client ), Conf_ServerPwd ) != 0 )
1893         {
1894                 /* Falsches Passwort */
1895                 Log( LOG_ERR, "User \"%s\" rejected (connection %d): Bad password!", Client_Mask( Client ), Client_Conn( Client ));
1896                 Conn_Close( Client_Conn( Client ), NULL, "Bad password", TRUE );
1897                 return DISCONNECTED;
1898         }
1899
1900         Log( LOG_NOTICE, "User \"%s\" registered (connection %d).", Client_Mask( Client ), Client_Conn( Client ));
1901
1902         /* Andere Server informieren */
1903         IRC_WriteStrServers( NULL, "NICK %s 1 %s %s 1 +%s :%s", Client_ID( Client ), Client_User( Client ), Client_Hostname( Client ), Client_Modes( Client ), Client_Info( Client ));
1904
1905         if( ! IRC_WriteStrClient( Client, RPL_WELCOME_MSG, Client_ID( Client ), Client_Mask( Client ))) return FALSE;
1906         if( ! IRC_WriteStrClient( Client, RPL_YOURHOST_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return FALSE;
1907         if( ! IRC_WriteStrClient( Client, RPL_CREATED_MSG, Client_ID( Client ), NGIRCd_StartStr )) return FALSE;
1908         if( ! IRC_WriteStrClient( Client, RPL_MYINFO_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return FALSE;
1909
1910         Client_SetType( Client, CLIENT_USER );
1911
1912         return Show_MOTD( Client );
1913 } /* Hello_User */
1914
1915
1916 LOCAL BOOLEAN Show_MOTD( CLIENT *Client )
1917 {
1918         BOOLEAN ok;
1919         CHAR line[127];
1920         FILE *fd;
1921         
1922         assert( Client != NULL );
1923
1924         fd = fopen( Conf_MotdFile, "r" );
1925         if( ! fd )
1926         {
1927                 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
1928                 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
1929         }
1930         
1931         IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
1932         while( TRUE )
1933         {
1934                 if( ! fgets( line, 126, fd )) break;
1935                 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
1936                 if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
1937                 {
1938                         fclose( fd );
1939                         return FALSE;
1940                 }
1941         }
1942         ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
1943
1944         fclose( fd );
1945         
1946         return ok;
1947 } /* Show_MOTD */
1948
1949
1950 LOCAL VOID Kill_Nick( CHAR *Nick )
1951 {
1952         Log( LOG_ERR, "User(s) with nick \"%s\" will be disconnected!", Nick );
1953         /* FIXME */
1954         Log( LOG_ALERT, "[Kill_Nick() not implemented - OOOPS!]" );
1955 } /* Kill_Nick */
1956
1957
1958 LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan )
1959 {
1960         CHAR str[LINE_LEN + 1];
1961         CL2CHAN *cl2chan;
1962         CLIENT *cl;
1963         
1964         assert( Client != NULL );
1965         assert( Chan != NULL );
1966
1967         /* Alle Mitglieder suchen */
1968         sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
1969         cl2chan = Channel_FirstMember( Chan );
1970         while( cl2chan )
1971         {
1972                 cl = Channel_GetClient( cl2chan );
1973
1974                 /* Nick anhaengen */
1975                 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
1976                 if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" );
1977                 if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" );
1978                 strcat( str, Client_ID( cl ));
1979
1980                 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
1981                 {
1982                         /* Zeile wird zu lang: senden! */
1983                         if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
1984                         sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
1985                 }
1986
1987                 /* naechstes Mitglied suchen */
1988                 cl2chan = Channel_NextMember( Chan, cl2chan );
1989         }
1990         if( str[strlen( str ) - 1] != ':')
1991         {
1992                 /* Es sind noch Daten da, die gesendet werden muessen */
1993                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
1994         }
1995
1996         /* Ende anzeigen */
1997         IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( Chan ));
1998         
1999         return CONNECTED;
2000 } /* Send_NAMES */
2001
2002
2003 /* -eof- */