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