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