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