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