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