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