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