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