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