]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc.c
- WHOIS erweitert: Anfragen koennen an andere Server weitergeleitet werden.
[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.29 2002/01/05 23:24:54 alex Exp $
13  *
14  * irc.c: IRC-Befehle
15  *
16  * $Log: irc.c,v $
17  * Revision 1.29  2002/01/05 23:24:54  alex
18  * - WHOIS erweitert: Anfragen koennen an andere Server weitergeleitet werden.
19  * - Vorbereitungen fuer Ident-Abfragen bei neuen Client-Strukturen.
20  *
21  * Revision 1.28  2002/01/05 20:08:02  alex
22  * - Div. Aenderungen fuer die Server-Links (u.a. WHOIS, QUIT, NICK angepasst).
23  * - Neue Funktionen IRC_WriteStrServer() und IRC_WriteStrServerPrefix().
24  *
25  * Revision 1.27  2002/01/05 19:15:03  alex
26  * - Fehlerpruefung bei select() in der "Hauptschleife" korrigiert.
27  *
28  * Revision 1.26  2002/01/05 16:51:18  alex
29  * - das Passwort von Servern wird nun ueberprueft (PASS- und SERVER-Befehl).
30  *
31  * Revision 1.25  2002/01/05 00:48:33  alex
32  * - bei SQUIT wurde immer die Verbindung getrennt, auch bei Remote-Servern.
33  *
34  * Revision 1.24  2002/01/04 17:58:44  alex
35  * - IRC_WriteStrXXX()-Funktionen eingefuehrt, groessere Anpassungen daran.
36  * - neuer Befehl SQUIT, QUIT an Server-Links angepasst.
37  *
38  * Revision 1.23  2002/01/04 01:36:40  alex
39  * - Loglevel ein wenig angepasst.
40  *
41  * Revision 1.22  2002/01/04 01:21:47  alex
42  * - Client-Strukruren werden nur noch ueber Funktionen angesprochen.
43  * - Weitere Anpassungen und Erweiterungen der Server-Links.
44  *
45  * Revision 1.21  2002/01/03 02:26:51  alex
46  * - neue Befehle SERVER und NJOIN begonnen,
47  * - begonnen, diverse IRC-Befehle an Server-Links anzupassen.
48  *
49  * Revision 1.20  2002/01/02 12:46:41  alex
50  * - die Gross- und Kleinschreibung des Nicks kann mit NICK nun geaendert werden.
51  *
52  * Revision 1.19  2002/01/02 02:51:39  alex
53  * - Copyright-Texte angepasst.
54  * - neuer Befehl "ERROR".
55  *
56  * Revision 1.17  2001/12/31 15:33:13  alex
57  * - neuer Befehl NAMES, kleinere Bugfixes.
58  * - Bug bei PING behoben: war zu restriktiv implementiert :-)
59  *
60  * Revision 1.16  2001/12/31 02:18:51  alex
61  * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
62  * - neuen Header "defines.h" mit (fast) allen Konstanten.
63  * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
64  *
65  * Revision 1.15  2001/12/30 19:26:11  alex
66  * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
67  *
68  * Revision 1.14  2001/12/30 11:42:00  alex
69  * - der Server meldet nun eine ordentliche "Start-Zeit".
70  *
71  * Revision 1.13  2001/12/29 03:10:06  alex
72  * - Neue Funktion IRC_MODE() implementiert, div. Aenderungen.
73  * - neue configure-Optione "--enable-strict-rfc".
74  *
75  * Revision 1.12  2001/12/27 19:17:26  alex
76  * - neue Befehle PRIVMSG, NOTICE, PING.
77  *
78  * Revision 1.11  2001/12/27 16:55:41  alex
79  * - neu: IRC_WriteStrRelated(), Aenderungen auch in IRC_WriteStrClient().
80  *
81  * Revision 1.10  2001/12/26 22:48:53  alex
82  * - MOTD-Datei ist nun konfigurierbar und wird gelesen.
83  *
84  * Revision 1.9  2001/12/26 14:45:37  alex
85  * - "Code Cleanups".
86  *
87  * Revision 1.8  2001/12/26 03:21:46  alex
88  * - PING/PONG-Befehle implementiert,
89  * - Meldungen ueberarbeitet: enthalten nun (fast) immer den Nick.
90  *
91  * Revision 1.7  2001/12/25 23:25:18  alex
92  * - und nochmal Aenderungen am Logging ;-)
93  *
94  * Revision 1.6  2001/12/25 23:13:33  alex
95  * - Debug-Meldungen angepasst.
96  *
97  * Revision 1.5  2001/12/25 22:02:42  alex
98  * - neuer IRC-Befehl "/QUIT". Verbessertes Logging & Debug-Ausgaben.
99  *
100  * Revision 1.4  2001/12/25 19:19:30  alex
101  * - bessere Fehler-Abfragen, diverse Bugfixes.
102  * - Nicks werden nur einmal vergeben :-)
103  * - /MOTD wird unterstuetzt.
104  *
105  * Revision 1.3  2001/12/24 01:34:06  alex
106  * - USER und NICK wird nun in beliebiger Reihenfolge akzeptiert (wg. BitchX)
107  * - MOTD-Ausgabe begonnen zu implementieren.
108  *
109  * Revision 1.2  2001/12/23 21:57:16  alex
110  * - erste IRC-Befehle zu implementieren begonnen.
111  *
112  * Revision 1.1  2001/12/14 08:13:43  alex
113  * - neues Modul begonnen :-)
114  */
115
116
117 #include <portab.h>
118 #include "global.h"
119
120 #include <imp.h>
121 #include <assert.h>
122 #include <errno.h>
123 #include <stdarg.h>
124 #include <stdio.h>
125 #include <stdlib.h>
126 #include <string.h>
127
128 #include "ngircd.h"
129 #include "client.h"
130 #include "conf.h"
131 #include "conn.h"
132 #include "log.h"
133 #include "messages.h"
134 #include "parse.h"
135 #include "tool.h"
136
137 #include <exp.h>
138 #include "irc.h"
139
140
141 #define CONNECTED TRUE
142 #define DISCONNECTED FALSE
143
144
145 LOCAL BOOLEAN Hello_User( CLIENT *Client );
146 LOCAL BOOLEAN Show_MOTD( CLIENT *Client );
147
148 LOCAL VOID Kill_Nick( CHAR *Nick );
149
150
151 GLOBAL VOID IRC_Init( VOID )
152 {
153 } /* IRC_Init */
154
155
156 GLOBAL VOID IRC_Exit( VOID )
157 {
158 } /* IRC_Exit */
159
160
161 GLOBAL BOOLEAN IRC_WriteStrClient( CLIENT *Client, CHAR *Format, ... )
162 {
163         CHAR buffer[1000];
164         BOOLEAN ok = CONNECTED;
165         va_list ap;
166
167         assert( Client != NULL );
168         assert( Format != NULL );
169
170         va_start( ap, Format );
171         vsnprintf( buffer, 1000, Format, ap );
172         va_end( ap );
173
174         /* an den Client selber */
175         ok = IRC_WriteStrClientPrefix( Client, Client_ThisServer( ), buffer );
176
177         return ok;
178 } /* IRC_WriteStrClient */
179
180
181 GLOBAL BOOLEAN IRC_WriteStrClientPrefix( CLIENT *Client, CLIENT *Prefix, CHAR *Format, ... )
182 {
183         /* Text an Clients, lokal bzw. remote, senden. */
184
185         CHAR buffer[1000];
186         va_list ap;
187
188         assert( Client != NULL );
189         assert( Format != NULL );
190         assert( Prefix != NULL );
191
192         va_start( ap, Format );
193         vsnprintf( buffer, 1000, Format, ap );
194         va_end( ap );
195
196         return Conn_WriteStr( Client_Conn( Client_NextHop( Client )), ":%s %s", Client_ID( Prefix ), buffer );
197 } /* IRC_WriteStrClientPrefix */
198
199
200 GLOBAL BOOLEAN IRC_WriteStrRelated( CLIENT *Client, CHAR *Format, ... )
201 {
202         CHAR buffer[1000];
203         BOOLEAN ok = CONNECTED;
204         va_list ap;
205
206         assert( Client != NULL );
207         assert( Format != NULL );
208
209         va_start( ap, Format );
210         vsnprintf( buffer, 1000, Format, ap );
211         va_end( ap );
212
213         /* an den Client selber */
214         ok = IRC_WriteStrClient( Client, buffer );
215
216         /* FIXME */
217         
218         return ok;
219 } /* IRC_WriteStrRelated */
220
221
222 GLOBAL VOID IRC_WriteStrServers( CLIENT *ExceptOf, CHAR *Format, ... )
223 {
224         CHAR buffer[1000];
225         va_list ap;
226
227         assert( Format != NULL );
228
229         va_start( ap, Format );
230         vsnprintf( buffer, 1000, Format, ap );
231         va_end( ap );
232
233         /* an den Client selber */
234         return IRC_WriteStrServersPrefix( ExceptOf, Client_ThisServer( ), buffer );
235 } /* IRC_WriteStrServers */
236
237
238 GLOBAL VOID IRC_WriteStrServersPrefix( CLIENT *ExceptOf, CLIENT *Prefix, CHAR *Format, ... )
239 {
240         CHAR buffer[1000];
241         CLIENT *c;
242         va_list ap;
243         
244         assert( Format != NULL );
245         assert( Prefix != NULL );
246
247         va_start( ap, Format );
248         vsnprintf( buffer, 1000, Format, ap );
249         va_end( ap );
250         
251         c = Client_First( );
252         while( c )
253         {
254                 if(( Client_Type( c ) == CLIENT_SERVER ) && ( Client_Conn( c ) > NONE ) && ( c != Client_ThisServer( )) && ( c != ExceptOf ))
255                 {
256                         /* Ziel-Server gefunden */
257                         IRC_WriteStrClientPrefix( c, Prefix, buffer );
258                 }
259                 c = Client_Next( c );
260         }
261 } /* IRC_WriteStrServersPrefix */
262
263
264 GLOBAL BOOLEAN IRC_PASS( CLIENT *Client, REQUEST *Req )
265 {
266         assert( Client != NULL );
267         assert( Req != NULL );
268
269         /* Fehler liefern, wenn kein lokaler Client */
270         if( Client_Conn( Client ) <= NONE ) return IRC_WriteStrClient( Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID( Client ), Req->command );
271         
272         if(( Client_Type( Client ) == CLIENT_UNKNOWN ) && ( Req->argc == 1))
273         {
274                 /* noch nicht registrierte unbekannte Verbindung */
275                 Log( LOG_DEBUG, "Connection %d: got PASS command ...", Client_Conn( Client ));
276
277                 /* Passwort speichern */
278                 Client_SetPassword( Client, Req->argv[0] );
279
280                 Client_SetType( Client, CLIENT_GOTPASS );
281                 return CONNECTED;
282         }
283         else if((( Client_Type( Client ) == CLIENT_UNKNOWN ) || ( Client_Type( Client ) == CLIENT_UNKNOWNSERVER )) && (( Req->argc == 3 ) || ( Req->argc == 4 )))
284         {
285                 /* noch nicht registrierte Server-Verbindung */
286                 Log( LOG_DEBUG, "Connection %d: got PASS command (new server link) ...", Client_Conn( Client ));
287
288                 /* Passwort speichern */
289                 Client_SetPassword( Client, Req->argv[0] );
290
291                 Client_SetType( Client, CLIENT_GOTPASSSERVER );
292                 return CONNECTED;
293         }
294         else if(( Client_Type( Client ) == CLIENT_UNKNOWN  ) || ( Client_Type( Client ) == CLIENT_UNKNOWNSERVER ))
295         {
296                 /* Falsche Anzahl Parameter? */
297                 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
298         }
299         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
300 } /* IRC_PASS */
301
302
303 GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
304 {
305         CHAR str[LINE_LEN], *ptr;
306         CLIENT *c;
307         INT i;
308         
309         assert( Client != NULL );
310         assert( Req != NULL );
311
312         /* Fehler liefern, wenn kein lokaler Client */
313         if( Client_Conn( Client ) <= NONE ) return IRC_WriteStrClient( Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID( Client ), Req->command );
314
315         if( Client_Type( Client ) == CLIENT_GOTPASSSERVER )
316         {
317                 /* Verbindung soll als Server-Server-Verbindung registriert werden */
318                 Log( LOG_DEBUG, "Connection %d: got SERVER command (new server link) ...", Client_Conn( Client ));
319
320                 /* Falsche Anzahl Parameter? */
321                 if( Req->argc != 3 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
322
323                 /* Ist dieser Server bei uns konfiguriert? */
324                 for( i = 0; i < Conf_Server_Count; i++ ) if( strcasecmp( Req->argv[0], Conf_Server[i].name ) == 0 ) break;
325                 if( i >= Conf_Server_Count )
326                 {
327                         /* Server ist nicht konfiguriert! */
328                         Log( LOG_ALERT, "Connection %d: Server \"%s\" not configured here!", Client_Conn( Client ), Req->argv[0] );
329                         Conn_Close( Client_Conn( Client ), "Server not configured here!" );
330                         return DISCONNECTED;
331                 }
332                 if( strcmp( Client_Password( Client ), Conf_Server[i].pwd ) != 0 )
333                 {
334                         /* Falsches Passwort */
335                         Log( LOG_ALERT, "Connection %d: Bad password for server \"%s\"!", Client_Conn( Client ), Req->argv[0] );
336                         Conn_Close( Client_Conn( Client ), "Bad password!" );
337                         return DISCONNECTED;
338                 }
339                 
340                 /* Ist ein Server mit dieser ID bereits registriert? */
341                 if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
342
343                 /* Server-Strukturen fuellen ;-) */
344                 Client_SetID( Client, Req->argv[0] );
345                 Client_SetToken( Client, atoi( Req->argv[1] ));
346                 Client_SetInfo( Client, Req->argv[2] );
347                 Client_SetHops( Client, 1 );
348
349                 Log( LOG_NOTICE, "Server \"%s\" registered (connection %d, 1 hop - direct link).", Client_ID( Client ), Client_Conn( Client ));
350
351                 Client_SetType( Client, CLIENT_SERVER );
352                 return CONNECTED;
353         }
354         else if( Client_Type( Client ) == CLIENT_SERVER )
355         {
356                 /* Neuer Server wird im Netz angekuendigt */
357
358                 /* Falsche Anzahl Parameter? */
359                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
360
361                 /* Ist ein Server mit dieser ID bereits registriert? */
362                 if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
363
364                 /* Ueberfluessige Hostnamen aus Info-Text entfernen */
365                 ptr = strchr( Req->argv[3] + 2, '[' );
366                 if( ! ptr ) ptr = Req->argv[3];
367
368                 /* Neue Client-Struktur anlegen */
369                 c = Client_NewRemoteServer( Client, Req->argv[0], atoi( Req->argv[1] ), atoi( Req->argv[2] ), ptr, TRUE );
370                 if( ! c )
371                 {
372                         /* Neue Client-Struktur konnte nicht angelegt werden */
373                         Log( LOG_ALERT, "Can't allocate client structure for server! (on connection %d)", Client_Conn( Client ));
374                         Conn_Close( Client_Conn( Client ), "Can't allocate client structure for remote server!" );
375                         return DISCONNECTED;
376                 }
377
378                 /* Log-Meldung zusammenbauen und ausgeben */
379                 if(( Client_Hops( c ) > 1 ) && ( Req->prefix[0] )) sprintf( str, "connected to %s, ", Req->prefix );
380                 else strcpy( str, "" );
381                 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": "" );
382                 
383                 return CONNECTED;
384         }
385         else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
386 } /* IRC_SERVER */
387
388
389 GLOBAL BOOLEAN IRC_NJOIN( CLIENT *Client, REQUEST *Req )
390 {
391         assert( Client != NULL );
392         assert( Req != NULL );
393
394         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTEREDSERVER_MSG, Client_ID( Client ));
395
396         return CONNECTED;
397 } /* IRC_NJOIN */
398
399
400 GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req )
401 {
402         CLIENT *intr_c, *c;
403
404         assert( Client != NULL );
405         assert( Req != NULL );
406
407         /* Zumindest BitchX sendet NICK-USER in der falschen Reihenfolge. */
408 #ifndef STRICT_RFC
409         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 )
410 #else
411         if( Client_Type( Client ) == CLIENT_UNKNOWN || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_USER  )
412 #endif
413         {
414                 /* User-Registrierung bzw. Nick-Aenderung */
415
416                 /* Falsche Anzahl Parameter? */
417                 if( Req->argc != 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
418
419                 /* Ist der Client "restricted"? */
420                 if( Client_HasMode( Client, 'r' )) return IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
421
422                 /* Wenn der Client zu seinem eigenen Nick wechseln will, so machen
423                  * wir nichts. So macht es das Original und mind. Snak hat probleme,
424                  * wenn wir es nicht so machen. Ob es so okay ist? Hm ... */
425 #ifndef STRICT_RFC
426                 if( strcmp( Client_ID( Client ), Req->argv[0] ) == 0 ) return CONNECTED;
427 #endif
428                 
429                 /* pruefen, ob Nick bereits vergeben. Speziallfall: der Client
430                  * will nur die Gross- und Kleinschreibung aendern. Das darf
431                  * er natuerlich machen :-) */
432                 if( strcasecmp( Client_ID( Client ), Req->argv[0] ) != 0 )
433                 {
434                         if( ! Client_CheckNick( Client, Req->argv[0] )) return CONNECTED;
435                 }
436
437                 if( Client_Type( Client ) == CLIENT_USER )
438                 {
439                         /* Nick-Aenderung: allen mitteilen! */
440                         Log( LOG_INFO, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( Client ), Client_ID( Client ), Req->argv[0] );
441                         IRC_WriteStrRelated( Client, "NICK :%s", Req->argv[0] );
442                 }
443                 
444                 /* Client-Nick registrieren */
445                 Client_SetID( Client, Req->argv[0] );
446
447                 if( Client_Type( Client ) != CLIENT_USER )
448                 {
449                         /* Neuer Client */
450                         Log( LOG_DEBUG, "Connection %d: got NICK command ...", Client_Conn( Client ));
451                         if( Client_Type( Client ) == CLIENT_GOTUSER ) return Hello_User( Client );
452                         else Client_SetType( Client, CLIENT_GOTNICK );
453                 }
454                 return CONNECTED;
455         }
456         else if( Client_Type( Client ) == CLIENT_SERVER )
457         {
458                 /* Server fuehrt neuen Client ein */
459
460                 /* Falsche Anzahl Parameter? */
461                 if( Req->argc != 7 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
462
463                 /* Nick ueberpruefen */
464                 c = Client_GetFromID( Req->argv[0] );
465                 if( c )
466                 {
467                         /* Der neue Nick ist auf diesem Server bereits registriert:
468                          * sowohl der neue, als auch der alte Client muessen nun
469                          * disconnectiert werden. */
470                         Log( LOG_ALERT, "Server %s introduces already registered nick %s!", Client_ID( Client ), Req->argv[0] );
471                         Kill_Nick( Req->argv[0] );
472                         return CONNECTED;
473                 }
474
475                 /* Server, zu dem der Client connectiert ist, suchen */
476                 intr_c = Client_GetFromToken( Client, atoi( Req->argv[4] ));
477                 if( ! intr_c )
478                 {
479                         Log( LOG_ALERT, "Server %s introduces nick %s with unknown host server!?", Client_ID( Client ), Req->argv[0] );
480                         Kill_Nick( Req->argv[0] );
481                         return CONNECTED;
482                 }
483
484                 /* Neue Client-Struktur anlegen */
485                 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], Req->argv[6], TRUE );
486                 if( ! c )
487                 {
488                         /* Eine neue Client-Struktur konnte nicht angelegt werden.
489                          * Der Client muss disconnectiert werden, damit der Netz-
490                          * status konsistent bleibt. */
491                         Log( LOG_ALERT, "Can't allocate client structure! (on connection %d)", Client_Conn( Client ));
492                         Kill_Nick( Req->argv[0] );
493                         return CONNECTED;
494                 }
495
496                 Log( LOG_DEBUG, "User \"%s\" registered (via %s, on %s, %d hop%s).", Client_ID( c ), Client_ID( Client ), Client_ID( intr_c ), Client_Hops( c ), Client_Hops( c ) > 1 ? "s": "" );
497
498                 return CONNECTED;
499         }
500         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
501 } /* IRC_NICK */
502
503
504 GLOBAL BOOLEAN IRC_USER( CLIENT *Client, REQUEST *Req )
505 {
506         assert( Client != NULL );
507         assert( Req != NULL );
508
509 #ifndef STRICT_RFC
510         if( Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_UNKNOWN )
511 #else
512         if( Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTPASS )
513 #endif
514         {
515                 /* Falsche Anzahl Parameter? */
516                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
517
518                 Client_SetUser( Client, Req->argv[0], FALSE );
519                 Client_SetInfo( Client, Req->argv[3] );
520
521                 Log( LOG_DEBUG, "Connection %d: got USER command ...", Client_Conn( Client ));
522                 if( Client_Type( Client ) == CLIENT_GOTNICK ) return Hello_User( Client );
523                 else Client_SetType( Client, CLIENT_GOTUSER );
524                 return CONNECTED;
525         }
526         else if( Client_Type( Client ) == CLIENT_USER || Client_Type( Client ) == CLIENT_SERVER || Client_Type( Client ) == CLIENT_SERVICE )
527         {
528                 return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
529         }
530         else return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
531 } /* IRC_USER */
532
533
534 GLOBAL BOOLEAN IRC_QUIT( CLIENT *Client, REQUEST *Req )
535 {
536         CLIENT *target;
537         
538         assert( Client != NULL );
539         assert( Req != NULL );
540
541         if(( Client_Type( Client ) == CLIENT_USER ) || ( Client_Type( Client ) == CLIENT_SERVICE ))
542         {
543                 /* User / Service */
544                 
545                 /* Falsche Anzahl Parameter? */
546                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
547
548                 Conn_Close( Client_Conn( Client ), "Client wants to quit." );
549                 return DISCONNECTED;
550         }
551         else if ( Client_Type( Client ) == CLIENT_SERVER )
552         {
553                 /* Server */
554
555                 /* Falsche Anzahl Parameter? */
556                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
557
558                 target = Client_Search( Req->prefix );
559                 if( ! target ) Log( LOG_ALERT, "Got QUIT from %s for unknown server!?", Client_ID( Client ));
560                 else Client_Destroy( target );
561                 return CONNECTED;
562         }
563         else return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
564 } /* IRC_QUIT */
565
566
567 GLOBAL BOOLEAN IRC_SQUIT( CLIENT *Client, REQUEST *Req )
568 {
569         CLIENT *target;
570         
571         assert( Client != NULL );
572         assert( Req != NULL );
573
574         /* SQUIT ist nur fuer Server erlaubt */
575         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
576
577         /* Falsche Anzahl Parameter? */
578         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
579
580         target = Client_GetFromID( Req->argv[0] );
581         if( ! target )
582         {
583                 Log( LOG_ALERT, "Got SQUIT from %s for unknown server \%s\"!?", Client_ID( Client ), Req->argv[0] );
584                 return CONNECTED;
585         }
586
587         if( target == Client ) Log( LOG_NOTICE, "Got SQUIT from %s: %s", Client_ID( Client ), Req->argv[1] );
588         else Log( LOG_NOTICE, "Got SQUIT from %s for %s: %s", Client_ID( Client ), Client_ID( target ), Req->argv[1] );
589
590         /* FIXME: das SQUIT muss an alle Server weiter-
591          * geleitet werden ... */
592
593         if( Client_Conn( target ) > NONE )
594         {
595                 Conn_Close( Client_Conn( target ), Req->argv[1] );
596                 return DISCONNECTED;
597         }
598         else
599         {
600                 Client_Destroy( target );
601                 return CONNECTED;
602         }
603 } /* IRC_SQUIT */
604
605
606 GLOBAL BOOLEAN IRC_PING( CLIENT *Client, REQUEST *Req )
607 {
608         assert( Client != NULL );
609         assert( Req != NULL );
610
611         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
612
613         /* Falsche Anzahl Parameter? */
614         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NOORIGIN_MSG, Client_ID( Client ));
615         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
616
617         return IRC_WriteStrClient( Client, "PONG %s :%s", Client_ID( Client_ThisServer( )), Client_ID( Client ));
618 } /* IRC_PING */
619
620
621 GLOBAL BOOLEAN IRC_PONG( CLIENT *Client, REQUEST *Req )
622 {
623         assert( Client != NULL );
624         assert( Req != NULL );
625
626         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
627
628         /* Falsche Anzahl Parameter? */
629         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NOORIGIN_MSG, Client_ID( Client ));
630         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
631
632         /* Der Connection-Timestamp wurde schon beim Lesen aus dem Socket
633          * aktualisiert, daher muss das hier nicht mehr gemacht werden. */
634
635         Log( LOG_DEBUG, "Connection %d: received PONG.", Client_Conn( Client ));
636         return CONNECTED;
637 } /* IRC_PONG */
638
639
640 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
641 {
642         assert( Client != NULL );
643         assert( Req != NULL );
644
645         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
646
647         /* Falsche Anzahl Parameter? */
648         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
649
650         return Show_MOTD( Client );
651 } /* IRC_MOTD */
652
653
654 GLOBAL BOOLEAN IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
655 {
656         CLIENT *to, *from;
657         
658         assert( Client != NULL );
659         assert( Req != NULL );
660
661         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
662
663         /* Falsche Anzahl Parameter? */
664         if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
665         if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
666         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
667
668         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
669         else from = Client;
670         
671         to = Client_Search( Req->argv[0] );
672         if( to )
673         {
674                 /* Okay, Ziel ist ein User */
675                 if( Client_Conn( from ) >= 0 ) Conn_UpdateIdle( Client_Conn( from ));
676                 return IRC_WriteStrClientPrefix( to, from, "PRIVMSG %s :%s", Client_ID( to ), Req->argv[1] );
677         }
678         else return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
679 } /* IRC_PRIVMSG */
680
681
682 GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
683 {
684         CLIENT *to, *from;
685
686         assert( Client != NULL );
687         assert( Req != NULL );
688
689         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
690
691         /* Falsche Anzahl Parameter? */
692         if( Req->argc != 2 ) return CONNECTED;
693
694         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
695         else from = Client;
696
697         to = Client_Search( Req->argv[0] );
698         if( to )
699         {
700                 /* Okay, Ziel ist ein User */
701                 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
702         }
703         else return CONNECTED;
704 } /* IRC_NOTICE */
705
706
707 GLOBAL BOOLEAN IRC_MODE( CLIENT *Client, REQUEST *Req )
708 {
709         CHAR x[2], new_modes[CLIENT_MODE_LEN], *ptr;
710         BOOLEAN set, ok;
711         CLIENT *target;
712         
713         assert( Client != NULL );
714         assert( Req != NULL );
715
716         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
717
718         /* Falsche Anzahl Parameter? */
719         if(( Req->argc > 2 ) || ( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
720
721         /* "Ziel-Client" suchen */
722         target = Client_Search( Req->argv[0] );
723
724         /* Wer ist der Anfragende? */
725         if( Client_Type( Client ) == CLIENT_USER )
726         {
727                 /* User: MODE ist nur fuer sich selber zulaessig */
728                 if( target != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
729         }
730         else
731         {
732                 /* Server: gibt es den Client ueberhaupt? */
733                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
734         }
735
736         /* Werden die Modes erfragt? */
737         if( Req->argc == 1 ) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( Client ));
738
739         ptr = Req->argv[1];
740
741         /* Sollen Modes gesetzt oder geloescht werden? */
742         if( *ptr == '+' ) set = TRUE;
743         else if( *ptr == '-' ) set = FALSE;
744         else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
745
746         /* Reply-String mit Aenderungen vorbereiten */
747         if( set ) strcpy( new_modes, "+" );
748         else strcpy( new_modes, "-" );
749
750         ptr++;
751         ok = TRUE;
752         x[1] = '\0';
753         while( *ptr )
754         {
755                 x[0] = '\0';
756                 if( Client_Type( Client ) == CLIENT_SERVER )
757                 {
758                         x[0] = *ptr;
759                         ok = TRUE;
760                 }
761                 else
762                 {
763                         switch( *ptr )
764                         {
765                                 case 'i':
766                                         /* invisible */
767                                         x[0] = 'i';
768                                         break;
769                                 case 'r':
770                                         /* restricted (kann nur gesetzt werden) */
771                                         if( set ) x[0] = 'r';
772                                         else ok = IRC_WriteStrClient( target, ERR_RESTRICTED_MSG, Client_ID( target ));
773                                         break;
774                                 case 'o':
775                                         /* operator (kann nur geloescht werden) */
776                                         if( ! set )
777                                         {
778                                                 Client_SetOperByMe( target, FALSE );
779                                                 x[0] = 'o';
780                                         }
781                                         else ok = IRC_WriteStrClient( target, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( target ));
782                                         break;
783                                 default:
784                                         ok = IRC_WriteStrClient( target, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( target ));
785                                         x[0] = '\0';
786                         }
787                 }
788                 if( ! ok ) break;
789
790                 ptr++;
791                 if( ! x[0] ) continue;
792
793                 /* Okay, gueltigen Mode gefunden */
794                 if( set )
795                 {
796                         /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
797                         if( Client_ModeAdd( target, x[0] )) strcat( new_modes, x );
798                 }
799                 else
800                 {
801                         /* Modes geloescht. Wenn der Client ihn hatte: merken */
802                         if( Client_ModeDel( target, x[0] )) strcat( new_modes, x );
803                 }
804         }
805         
806         /* Geanderte Modes? */
807         if( new_modes[1] )
808         {
809                 if( Client_Type( Client ) == CLIENT_SERVER )
810                 {
811                         /* Modes an andere Server forwarden */
812                         /* FIXME */
813                 }
814                 else
815                 {
816                         /* Bestaetigung an Client schicken */
817                         ok = IRC_WriteStrRelated( Client, "MODE %s :%s", Client_ID( target ), new_modes );
818                 }
819                 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( target ), Client_Modes( target ));
820         }
821         return ok;
822 } /* IRC_MODE */
823
824
825 GLOBAL BOOLEAN IRC_OPER( CLIENT *Client, REQUEST *Req )
826 {
827         INT i;
828         
829         assert( Client != NULL );
830         assert( Req != NULL );
831
832         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
833         
834         /* Falsche Anzahl Parameter? */
835         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
836
837         /* Operator suchen */
838         for( i = 0; i < Conf_Oper_Count; i++)
839         {
840                 if( Conf_Oper[i].name[0] && Conf_Oper[i].pwd[0] && ( strcmp( Conf_Oper[i].name, Req->argv[0] ) == 0 )) break;
841         }
842         if( i >= Conf_Oper_Count ) return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
843
844         /* Stimmt der Name und das Passwort? */
845         if(( strcmp( Conf_Oper[i].name, Req->argv[0] ) != 0 ) || ( strcmp( Conf_Oper[i].pwd, Req->argv[1] ) != 0 )) return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
846         
847         if( ! Client_HasMode( Client, 'o' ))
848         {
849                 /* noch kein o-Mode gesetzt */
850                 Client_ModeAdd( Client, 'o' );
851                 if( ! IRC_WriteStrRelated( Client, "MODE %s :+o", Client_ID( Client ))) return DISCONNECTED;
852         }
853
854         if( ! Client_OperByMe( Client )) Log( LOG_NOTICE, "User \"%s\" is now an IRC Operator.", Client_Mask( Client ));
855
856         Client_SetOperByMe( Client, TRUE );
857         return IRC_WriteStrClient( Client, RPL_YOUREOPER_MSG, Client_ID( Client ));
858 } /* IRC_OPER */
859
860
861 GLOBAL BOOLEAN IRC_DIE( CLIENT *Client, REQUEST *Req )
862 {
863         assert( Client != NULL );
864         assert( Req != NULL );
865
866         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
867
868         /* Falsche Anzahl Parameter? */
869         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
870
871         if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
872
873         Log( LOG_NOTICE, "Got DIE command from \"%s\", going down!", Client_Mask( Client ));
874         NGIRCd_Quit = TRUE;
875         return CONNECTED;
876 } /* IRC_DIE */
877
878
879 GLOBAL BOOLEAN IRC_RESTART( CLIENT *Client, REQUEST *Req )
880 {
881         assert( Client != NULL );
882         assert( Req != NULL );
883
884         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
885
886         /* Falsche Anzahl Parameter? */
887         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
888
889         if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
890
891         Log( LOG_NOTICE, "Got RESTART command from \"%s\", going down!", Client_Mask( Client ));
892         NGIRCd_Restart = TRUE;
893         return CONNECTED;
894 } /* IRC_RESTART */
895
896
897 GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req )
898 {
899         CHAR rpl[COMMAND_LEN];
900         CLIENT *c;
901         
902         assert( Client != NULL );
903         assert( Req != NULL );
904
905         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
906
907         /* Falsche Anzahl Parameter? */
908         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
909
910         /* Noch alle User ausgeben, die in keinem Channel sind */
911         rpl[0] = '\0';
912         c = Client_First( );
913         while( c )
914         {
915                 if( Client_Type( c ) == CLIENT_USER )
916                 {
917                         /* Okay, das ist ein User */
918                         strcat( rpl, Client_ID( c ));
919                         strcat( rpl, " " );
920                 }
921
922                 /* Antwort zu lang? Splitten. */
923                 if( strlen( rpl ) > 480 )
924                 {
925                         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
926                         if( ! IRC_WriteStrClient( Client, RPL_NAMREPLY_MSG, Client_ID( Client ), "*", "*", rpl )) return DISCONNECTED;
927                         rpl[0] = '\0';
928                 }
929                 
930                 c = Client_Next( c );
931         }
932         if( rpl[0] )
933         {
934                 /* es wurden User gefunden */
935                 if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
936                 if( ! IRC_WriteStrClient( Client, RPL_NAMREPLY_MSG, Client_ID( Client ), "*", "*", rpl )) return DISCONNECTED;
937         }
938         return IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), "*" );
939 } /* IRC_NAMES */
940
941
942 GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
943 {
944         CHAR rpl[COMMAND_LEN];
945         CLIENT *c;
946         CHAR *ptr;
947         INT i;
948         
949         assert( Client != NULL );
950         assert( Req != NULL );
951
952         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
953
954         /* Falsche Anzahl Parameter? */
955         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
956
957         strcpy( rpl, RPL_ISON_MSG );
958         for( i = 0; i < Req->argc; i++ )
959         {
960                 ptr = strtok( Req->argv[i], " " );
961                 while( ptr )
962                 {
963                         ngt_TrimStr( ptr );
964                         c = Client_GetFromID( ptr );
965                         if( c && ( Client_Type( c ) == CLIENT_USER ))
966                         {
967                                 /* Dieser Nick ist "online" */
968                                 strcat( rpl, ptr );
969                                 strcat( rpl, " " );
970                         }
971                         ptr = strtok( NULL, " " );
972                 }
973         }
974         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
975
976         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
977 } /* IRC_ISON */
978
979
980 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
981 {
982         CLIENT *from, *target, *c;
983         
984         assert( Client != NULL );
985         assert( Req != NULL );
986
987         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
988
989         /* Falsche Anzahl Parameter? */
990         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
991
992         /* Client suchen */
993         c = Client_GetFromID( Req->argv[Req->argc - 1] );
994         if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
995
996         /* Empfaenger des WHOIS suchen */
997         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
998         else from = Client;
999         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1000         
1001         /* Forwarden an anderen Server? */
1002         if( Req->argc > 1 )
1003         {
1004                 /* Ziel-Server suchen */
1005                 target = Client_GetFromID( Req->argv[1] );
1006                 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
1007                 else return IRC_WriteStrClientPrefix( target, from, "WHOIS %s :%s", Req->argv[0], Req->argv[1] );
1008         }
1009         
1010         /* Nick, User und Name */
1011         if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
1012
1013         /* Server */
1014         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;
1015
1016         /* IRC-Operator? */
1017         if( Client_HasMode( c, 'o' ))
1018         {
1019                 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
1020         }
1021
1022         /* Idle (nur lokale Clients) */
1023         if( Client_Conn( c ) > NONE )
1024         {
1025                 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
1026         }
1027
1028         /* End of Whois */
1029         return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
1030 } /* IRC_WHOIS */
1031
1032
1033 GLOBAL BOOLEAN IRC_USERHOST( CLIENT *Client, REQUEST *Req )
1034 {
1035         CHAR rpl[COMMAND_LEN];
1036         CLIENT *c;
1037         INT max, i;
1038
1039         assert( Client != NULL );
1040         assert( Req != NULL );
1041
1042         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1043
1044         /* Falsche Anzahl Parameter? */
1045         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1046
1047         if( Req->argc > 5 ) max = 5;
1048         else max = Req->argc;
1049         
1050         strcpy( rpl, RPL_USERHOST_MSG );
1051         for( i = 0; i < max; i++ )
1052         {
1053                 c = Client_GetFromID( Req->argv[i] );
1054                 if( c && ( Client_Type( c ) == CLIENT_USER ))
1055                 {
1056                         /* Dieser Nick ist "online" */
1057                         strcat( rpl, Client_ID( c ));
1058                         if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
1059                         strcat( rpl, "=" );
1060                         if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
1061                         else strcat( rpl, "+" );
1062                         strcat( rpl, Client_User( c ));
1063                         strcat( rpl, "@" );
1064                         strcat( rpl, Client_Hostname( c ));
1065                         strcat( rpl, " " );
1066                 }
1067         }
1068         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
1069
1070         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
1071 } /* IRC_USERHOST */
1072
1073
1074 GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req )
1075 {
1076         assert( Client != NULL );
1077         assert( Req != NULL );
1078
1079         if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
1080         else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
1081
1082         return CONNECTED;
1083 } /* IRC_ERROR */
1084
1085
1086 LOCAL BOOLEAN Hello_User( CLIENT *Client )
1087 {
1088         assert( Client != NULL );
1089
1090         /* Passwort ueberpruefen */
1091         if( strcmp( Client_Password( Client ), Conf_ServerPwd ) != 0 )
1092         {
1093                 /* Falsches Passwort */
1094                 Log( LOG_ALERT, "User \"%s\" rejected (connection %d): Bad password!", Client_Mask( Client ), Client_Conn( Client ));
1095                 Conn_Close( Client_Conn( Client ), "Bad password!" );
1096                 return DISCONNECTED;
1097         }
1098
1099         Log( LOG_NOTICE, "User \"%s\" registered (connection %d).", Client_Mask( Client ), Client_Conn( Client ));
1100
1101         /* Andere Server informieren */
1102         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 ));
1103
1104         if( ! IRC_WriteStrClient( Client, RPL_WELCOME_MSG, Client_ID( Client ), Client_Mask( Client ))) return FALSE;
1105         if( ! IRC_WriteStrClient( Client, RPL_YOURHOST_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return FALSE;
1106         if( ! IRC_WriteStrClient( Client, RPL_CREATED_MSG, Client_ID( Client ), NGIRCd_StartStr )) return FALSE;
1107         if( ! IRC_WriteStrClient( Client, RPL_MYINFO_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return FALSE;
1108
1109         Client_SetType( Client, CLIENT_USER );
1110
1111         return Show_MOTD( Client );
1112 } /* Hello_User */
1113
1114
1115 LOCAL BOOLEAN Show_MOTD( CLIENT *Client )
1116 {
1117         BOOLEAN ok;
1118         CHAR line[127];
1119         FILE *fd;
1120         
1121         assert( Client != NULL );
1122
1123         fd = fopen( Conf_MotdFile, "r" );
1124         if( ! fd )
1125         {
1126                 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
1127                 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
1128         }
1129         
1130         IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
1131         while( TRUE )
1132         {
1133                 if( ! fgets( line, 126, fd )) break;
1134                 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
1135                 if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
1136                 {
1137                         fclose( fd );
1138                         return FALSE;
1139                 }
1140         }
1141         ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
1142
1143         fclose( fd );
1144         
1145         return ok;
1146 } /* Show_MOTD */
1147
1148
1149 LOCAL VOID Kill_Nick( CHAR *Nick )
1150 {
1151         Log( LOG_ALERT, "User(s) with nick \"%s\" will be disconnected!", Nick );
1152         /* FIXME */
1153         Log( LOG_ALERT, "[Kill_Nick() not implemented - OOOPS!]" );
1154 } /* Kill_Nick */
1155
1156
1157 /* -eof- */