]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc.c
- NAMES beachtet nun das "invisible" Flag ("i") von Usern.
[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.75 2002/02/27 15:23:27 alex Exp $
13  *
14  * irc.c: IRC-Befehle
15  *
16  * $Log: irc.c,v $
17  * Revision 1.75  2002/02/27 15:23:27  alex
18  * - NAMES beachtet nun das "invisible" Flag ("i") von Usern.
19  *
20  * Revision 1.74  2002/02/27 03:44:53  alex
21  * - gerade eben in SQUIT eingefuehrten Bug behoben: entfernte Server werden nun
22  *   nur noch geloescht, die Verbindung, von der SQUIT kam, bleibt wieder offen.
23  *
24  * Revision 1.73  2002/02/27 03:08:05  alex
25  * - Log-Meldungen bei SQUIT erneut ueberarbeitet ...
26  *
27  * Revision 1.72  2002/02/27 02:26:58  alex
28  * - SQUIT wird auf jeden Fall geforwarded, zudem besseres Logging.
29  *
30  * Revision 1.71  2002/02/27 00:50:05  alex
31  * - einige unnoetige Client_NextHop()-Aufrufe entfernt.
32  * - NAMES korrigiert und komplett implementiert.
33  *
34  * Revision 1.70  2002/02/26 22:06:40  alex
35  * - Nick-Aenderungen werden nun wieder korrekt ins Logfile geschrieben.
36  *
37  * Revision 1.69  2002/02/26 20:52:40  alex
38  * - VERSION wurde falsch weitergeleitet und beantwortet (Prefix nicht beachtet)
39  *
40  * Revision 1.68  2002/02/25 17:46:27  alex
41  * - an User wird nun immer ein "komplettes" Prefix verschickt.
42  *
43  * Revision 1.67  2002/02/25 13:21:25  alex
44  * - WHOIS wird nicht mehr automatisch an den "Original-Server" weiterge-
45  *   leitet: war eh nicht RFC-konform und machte Probleme mit Clients.
46  *
47  * Revision 1.66  2002/02/23 21:39:48  alex
48  * - IRC-Befehl KILL sowie Kills bei Nick Collsisions implementiert.
49  *
50  * Revision 1.65  2002/02/23 00:03:54  alex
51  * - Ergebnistyp von Conn_GetIdle() und Conn_LastPing() auf "time_t" geaendert.
52  *
53  * Revision 1.64  2002/02/19 20:06:45  alex
54  * - User-Registrierung wird nicht mehr als Nick-Aenderung protokolliert,
55  * - VERSION liefert nun doch wieder den Debug-Status im Reply.
56  *
57  * Revision 1.63  2002/02/19 02:21:17  alex
58  * - der Debug-Level wird bei VERSION nicht mehr geliefert. Grund: a) absolut
59  *   unnoetig und b) Compiler-Fehler, wenn ohne Debug-Code configure'd ;-))
60  *
61  * Revision 1.62  2002/02/17 23:38:58  alex
62  * - neuer IRC-Befehl VERSION implementiert: IRC_VERSION().
63  *
64  * Revision 1.61  2002/02/17 19:03:12  alex
65  * - NICK-Aenderungen wurden dem User selber mit dem falschen Prefix geliefert.
66  *
67  * Revision 1.60  2002/02/17 17:43:14  alex
68  * - Fehlerhafte Modes werden nun ausfuehrlicher an den Client gemeldet.
69  *
70  * Revision 1.59  2002/02/17 17:30:21  alex
71  * - NICK-Aenderungen werden an alle Server und betroffene Clients gemeldet.
72  * - Neue Funktion IRC_WriteStrRelatedPrefix().
73  *
74  * Revision 1.58  2002/02/17 17:18:59  alex
75  * - NICK korrigiert.
76  *
77  * Revision 1.57  2002/02/13 23:05:29  alex
78  * - Nach Connect eines Users werden LUSERS-Informationen angezeigt.
79  *
80  * Revision 1.56  2002/02/13 17:52:27  alex
81  * - es werden nun Channel- und User-Modes von Usern angenommen.
82  *
83  * Revision 1.55  2002/02/12 14:40:37  alex
84  * - via NJOIN gemeldete Benutzer wurden nicht in Channels bekannt gemacht.
85  *
86  * Revision 1.54  2002/02/11 23:33:35  alex
87  * - weitere Anpassungen an Channel-Modes und Channel-User-Modes.
88  *
89  * Revision 1.53  2002/02/11 16:06:21  alex
90  * - Die Quelle von MODE-Aenderungen wird nun korrekt weitergegeben.
91  *
92  * Revision 1.52  2002/02/11 15:52:21  alex
93  * - PONG an den Server selber wurde faelschlicherweise versucht zu forwarden.
94  * - Channel-Modes wurden falsch geliefert (als User-Modes).
95  *
96  * Revision 1.51  2002/02/11 15:15:53  alex
97  * - PING und PONG werden nun auch korrekt an andere Server geforwarded.
98  * - bei MODE-Meldungen wird der letzte Parameter nicht mehr mit ":" getrennt.
99  *
100  * Revision 1.50  2002/02/11 01:03:20  alex
101  * - Aenderungen und Anpassungen an Channel-Modes und Channel-User-Modes:
102  *   Modes werden besser geforwarded, lokale User, fuer die ein Channel
103  *   angelegt wird, werden Channel-Operator, etc. pp. ...
104  * - NJOIN's von Servern werden nun korrekt an andere Server weitergeleitet.
105  *
106  * Revision 1.49  2002/02/06 16:51:22  alex
107  * - neue Funktion zur MODE-Behandlung, fuer Channel-Modes vorbereitet.
108  *
109  * Revision 1.48  2002/01/29 00:13:45  alex
110  * - WHOIS zeigt nun auch die Channels an, in denen der jeweilige User Mitglied ist.
111  * - zu jedem Server wird nun der "Top-Server" gespeichert, somit funktioniert
112  *   LINKS wieder korrekt.
113  *
114  * Revision 1.47  2002/01/28 13:05:48  alex
115  * - nach einem JOIN wird die Liste der Mitglieder an den Client geschickt.
116  * - MODE fuer Channels wird nun komplett ignoriert (keine Fehlermeldung mehr).
117  *
118  * Revision 1.46  2002/01/28 01:45:43  alex
119  * - SERVER-Meldungen an neue Server sind nun in der richtigen Reihenfolge.
120  *
121  * Revision 1.45  2002/01/28 01:18:14  alex
122  * - connectierenden Servern werden Channels nun mit NJOIN bekannt gemacht.
123  *
124  * Revision 1.44  2002/01/28 00:55:08  alex
125  * - ein neu connectierender Server wird nun korrekt im Netz bekannt gemacht.
126  *
127  * Revision 1.43  2002/01/27 21:56:39  alex
128  * - IRC_WriteStrServersPrefixID() und IRC_WriteStrClientPrefixID() wieder entfernt.
129  * - einige kleinere Fixes bezueglich Channels ...
130  *
131  * Revision 1.42  2002/01/27 18:28:01  alex
132  * - bei NICK wurde das falsche Prefix an andere Server weitergegeben.
133  *
134  * Revision 1.41  2002/01/27 17:15:49  alex
135  * - anderungen an den Funktions-Prototypen von IRC_WriteStrChannel() und
136  *   IRC_WriteStrChannelPrefix(),
137  * - neue: IRC_WriteStrClientPrefixID() und IRC_WriteStrServersPrefixID().
138  *
139  * Revision 1.40  2002/01/26 18:43:11  alex
140  * - neue Funktionen IRC_WriteStrChannelPrefix() und IRC_WriteStrChannel(),
141  *   die IRC_Write_xxx_Related() sind dafuer entfallen.
142  * - IRC_PRIVMSG() kann nun auch mit Channels als Ziel umgehen.
143  *
144  * Revision 1.39  2002/01/21 00:05:11  alex
145  * - neue Funktionen IRC_JOIN und IRC_PART begonnen, ebenso die Funktionen
146  *   IRC_WriteStrRelatedPrefix und IRC_WriteStrRelatedChannelPrefix().
147  * - diverse Aenderungen im Zusammenhang mit Channels.
148  *
149  * Revision 1.38  2002/01/18 15:31:32  alex
150  * - die User-Modes bei einem NICK von einem Server wurden falsch uebernommen.
151  *
152  * Revision 1.37  2002/01/16 22:10:18  alex
153  * - IRC_LUSERS() implementiert.
154  *
155  * Revision 1.36  2002/01/11 23:50:55  alex
156  * - LINKS implementiert, LUSERS begonnen.
157  *
158  * Revision 1.35  2002/01/09 21:30:45  alex
159  * - WHOIS wurde faelschlicherweise an User geforwarded statt vom Server beantwortet.
160  *
161  * Revision 1.34  2002/01/09 01:09:58  alex
162  * - WHOIS wird im "Strict-RFC-Mode" nicht mehr automatisch geforwarded,
163  * - andere Server werden nun ueber bisherige Server und User informiert.
164  *
165  * Revision 1.33  2002/01/07 23:42:12  alex
166  * - Es werden fuer alle Server eigene Token generiert,
167  * - QUIT von einem Server fuer einen User wird an andere Server geforwarded,
168  * - ebenso NICK-Befehle, die "fremde" User einfuehren.
169  *
170  * Revision 1.32  2002/01/07 16:02:36  alex
171  * - Loglevel von Remote-Mode-Aenderungen angepasst (nun Debug).
172  * - Im Debug-Mode werden nun auch PING's protokolliert.
173  *
174  * Revision 1.31  2002/01/07 15:39:46  alex
175  * - Server nimmt nun Server-Links an: PASS und SERVER entsprechend angepasst.
176  * - MODE und NICK melden nun die Aenderungen an andere Server.
177  *
178  * Revision 1.30  2002/01/06 15:21:29  alex
179  * - Loglevel und Meldungen nochmals ueberarbeitet.
180  * - QUIT und SQUIT forwarden nun den Grund der Trennung,
181  * - WHOIS wird nun immer an den "Original-Server" weitergeleitet.
182  *
183  * Revision 1.29  2002/01/05 23:24:54  alex
184  * - WHOIS erweitert: Anfragen koennen an andere Server weitergeleitet werden.
185  * - Vorbereitungen fuer Ident-Abfragen bei neuen Client-Strukturen.
186  *
187  * Revision 1.28  2002/01/05 20:08:02  alex
188  * - Div. Aenderungen fuer die Server-Links (u.a. WHOIS, QUIT, NICK angepasst).
189  * - Neue Funktionen IRC_WriteStrServer() und IRC_WriteStrServerPrefix().
190  *
191  * Revision 1.27  2002/01/05 19:15:03  alex
192  * - Fehlerpruefung bei select() in der "Hauptschleife" korrigiert.
193  *
194  * Revision 1.26  2002/01/05 16:51:18  alex
195  * - das Passwort von Servern wird nun ueberprueft (PASS- und SERVER-Befehl).
196  *
197  * Revision 1.25  2002/01/05 00:48:33  alex
198  * - bei SQUIT wurde immer die Verbindung getrennt, auch bei Remote-Servern.
199  *
200  * Revision 1.24  2002/01/04 17:58:44  alex
201  * - IRC_WriteStrXXX()-Funktionen eingefuehrt, groessere Anpassungen daran.
202  * - neuer Befehl SQUIT, QUIT an Server-Links angepasst.
203  *
204  * Revision 1.23  2002/01/04 01:36:40  alex
205  * - Loglevel ein wenig angepasst.
206  *
207  * Revision 1.22  2002/01/04 01:21:47  alex
208  * - Client-Strukruren werden nur noch ueber Funktionen angesprochen.
209  * - Weitere Anpassungen und Erweiterungen der Server-Links.
210  *
211  * Revision 1.21  2002/01/03 02:26:51  alex
212  * - neue Befehle SERVER und NJOIN begonnen,
213  * - begonnen, diverse IRC-Befehle an Server-Links anzupassen.
214  *
215  * Revision 1.20  2002/01/02 12:46:41  alex
216  * - die Gross- und Kleinschreibung des Nicks kann mit NICK nun geaendert werden.
217  *
218  * Revision 1.19  2002/01/02 02:51:39  alex
219  * - Copyright-Texte angepasst.
220  * - neuer Befehl "ERROR".
221  *
222  * Revision 1.17  2001/12/31 15:33:13  alex
223  * - neuer Befehl NAMES, kleinere Bugfixes.
224  * - Bug bei PING behoben: war zu restriktiv implementiert :-)
225  *
226  * Revision 1.16  2001/12/31 02:18:51  alex
227  * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
228  * - neuen Header "defines.h" mit (fast) allen Konstanten.
229  * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
230  *
231  * Revision 1.15  2001/12/30 19:26:11  alex
232  * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
233  *
234  * Revision 1.14  2001/12/30 11:42:00  alex
235  * - der Server meldet nun eine ordentliche "Start-Zeit".
236  *
237  * Revision 1.13  2001/12/29 03:10:06  alex
238  * - Neue Funktion IRC_MODE() implementiert, div. Aenderungen.
239  * - neue configure-Optione "--enable-strict-rfc".
240  *
241  * Revision 1.12  2001/12/27 19:17:26  alex
242  * - neue Befehle PRIVMSG, NOTICE, PING.
243  *
244  * Revision 1.11  2001/12/27 16:55:41  alex
245  * - neu: IRC_WriteStrRelated(), Aenderungen auch in IRC_WriteStrClient().
246  *
247  * Revision 1.10  2001/12/26 22:48:53  alex
248  * - MOTD-Datei ist nun konfigurierbar und wird gelesen.
249  *
250  * Revision 1.9  2001/12/26 14:45:37  alex
251  * - "Code Cleanups".
252  *
253  * Revision 1.8  2001/12/26 03:21:46  alex
254  * - PING/PONG-Befehle implementiert,
255  * - Meldungen ueberarbeitet: enthalten nun (fast) immer den Nick.
256  *
257  * Revision 1.7  2001/12/25 23:25:18  alex
258  * - und nochmal Aenderungen am Logging ;-)
259  *
260  * Revision 1.6  2001/12/25 23:13:33  alex
261  * - Debug-Meldungen angepasst.
262  *
263  * Revision 1.5  2001/12/25 22:02:42  alex
264  * - neuer IRC-Befehl "/QUIT". Verbessertes Logging & Debug-Ausgaben.
265  *
266  * Revision 1.4  2001/12/25 19:19:30  alex
267  * - bessere Fehler-Abfragen, diverse Bugfixes.
268  * - Nicks werden nur einmal vergeben :-)
269  * - /MOTD wird unterstuetzt.
270  *
271  * Revision 1.3  2001/12/24 01:34:06  alex
272  * - USER und NICK wird nun in beliebiger Reihenfolge akzeptiert (wg. BitchX)
273  * - MOTD-Ausgabe begonnen zu implementieren.
274  *
275  * Revision 1.2  2001/12/23 21:57:16  alex
276  * - erste IRC-Befehle zu implementieren begonnen.
277  *
278  * Revision 1.1  2001/12/14 08:13:43  alex
279  * - neues Modul begonnen :-)
280  */
281
282
283 #include <portab.h>
284 #include "global.h"
285
286 #include <imp.h>
287 #include <assert.h>
288 #include <errno.h>
289 #include <stdarg.h>
290 #include <stdio.h>
291 #include <stdlib.h>
292 #include <string.h>
293
294 #include "ngircd.h"
295 #include "channel.h"
296 #include "client.h"
297 #include "conf.h"
298 #include "conn.h"
299 #include "log.h"
300 #include "messages.h"
301 #include "parse.h"
302 #include "tool.h"
303
304 #include <exp.h>
305 #include "irc.h"
306
307
308 #define CONNECTED TRUE
309 #define DISCONNECTED FALSE
310
311
312 LOCAL BOOLEAN Hello_User( CLIENT *Client );
313 LOCAL BOOLEAN Show_MOTD( CLIENT *Client );
314
315 LOCAL VOID Kill_Nick( CHAR *Nick, CHAR *Reason );
316
317 LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan );
318 LOCAL BOOLEAN Send_LUSERS( CLIENT *Client );
319
320 CHAR *Get_Prefix( CLIENT *Target, CLIENT *Client );
321
322
323 GLOBAL VOID IRC_Init( VOID )
324 {
325 } /* IRC_Init */
326
327
328 GLOBAL VOID IRC_Exit( VOID )
329 {
330 } /* IRC_Exit */
331
332
333 GLOBAL BOOLEAN IRC_WriteStrClient( CLIENT *Client, CHAR *Format, ... )
334 {
335         CHAR buffer[1000];
336         BOOLEAN ok = CONNECTED;
337         va_list ap;
338
339         assert( Client != NULL );
340         assert( Format != NULL );
341
342         va_start( ap, Format );
343         vsnprintf( buffer, 1000, Format, ap );
344         va_end( ap );
345
346         /* an den Client selber */
347         ok = IRC_WriteStrClientPrefix( Client, Client_ThisServer( ), buffer );
348
349         return ok;
350 } /* IRC_WriteStrClient */
351
352
353 GLOBAL BOOLEAN IRC_WriteStrClientPrefix( CLIENT *Client, CLIENT *Prefix, CHAR *Format, ... )
354 {
355         /* Text an Clients, lokal bzw. remote, senden. */
356
357         CHAR buffer[1000];
358         va_list ap;
359
360         assert( Client != NULL );
361         assert( Format != NULL );
362         assert( Prefix != NULL );
363
364         va_start( ap, Format );
365         vsnprintf( buffer, 1000, Format, ap );
366         va_end( ap );
367
368         return Conn_WriteStr( Client_Conn( Client_NextHop( Client )), ":%s %s", Get_Prefix( Client_NextHop( Client ), Prefix ), buffer );
369 } /* IRC_WriteStrClientPrefix */
370
371
372 GLOBAL BOOLEAN IRC_WriteStrChannel( CLIENT *Client, CHANNEL *Chan, BOOLEAN Remote, CHAR *Format, ... )
373 {
374         CHAR buffer[1000];
375         va_list ap;
376
377         assert( Client != NULL );
378         assert( Format != NULL );
379
380         va_start( ap, Format );
381         vsnprintf( buffer, 1000, Format, ap );
382         va_end( ap );
383
384         return IRC_WriteStrChannelPrefix( Client, Chan, Client_ThisServer( ), Remote, buffer );
385 } /* IRC_WriteStrChannel */
386
387
388 GLOBAL BOOLEAN IRC_WriteStrChannelPrefix( CLIENT *Client, CHANNEL *Chan, CLIENT *Prefix, BOOLEAN Remote, CHAR *Format, ... )
389 {
390         BOOLEAN sock[MAX_CONNECTIONS], is_server[MAX_CONNECTIONS], ok = CONNECTED;
391         CHAR buffer[1000];
392         CL2CHAN *cl2chan;
393         CLIENT *c;
394         INT s, i;
395         va_list ap;
396
397         assert( Client != NULL );
398         assert( Chan != NULL );
399         assert( Prefix != NULL );
400         assert( Format != NULL );
401
402         va_start( ap, Format );
403         vsnprintf( buffer, 1000, Format, ap );
404         va_end( ap );
405
406         for( i = 0; i < MAX_CONNECTIONS; i++ ) sock[i] = FALSE;
407
408         /* An alle Clients, die in den selben Channels sind.
409          * Dabei aber nur einmal je Remote-Server */
410         cl2chan = Channel_FirstMember( Chan );
411         while( cl2chan )
412         {
413                 c = Channel_GetClient( cl2chan );
414                 if( ! Remote )
415                 {
416                         if( Client_Conn( c ) <= NONE ) c = NULL;
417                         else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
418                 }
419                 if( c ) c = Client_NextHop( c );
420                         
421                 if( c && ( c != Client ))
422                 {
423                         /* Ok, anderer Client */
424                         s = Client_Conn( c );
425                         assert( s >= 0 );
426                         assert( s < MAX_CONNECTIONS );
427                         sock[s] = TRUE;
428                         if( Client_Type( c ) == CLIENT_SERVER ) is_server[s] = TRUE;
429                         else is_server[s] = FALSE;
430                 }
431                 cl2chan = Channel_NextMember( Chan, cl2chan );
432         }
433
434         /* Senden ... */
435         for( i = 0; i < MAX_CONNECTIONS; i++ )
436         {
437                 if( sock[i] )
438                 {
439                         if( is_server[i] ) ok = Conn_WriteStr( i, ":%s %s", Client_ID( Prefix ), buffer );
440                         else ok = Conn_WriteStr( i, ":%s %s", Client_Mask( Prefix ), buffer );
441                         if( ! ok ) break;
442                 }
443         }
444         return ok;
445 } /* IRC_WriteStrChannelPrefix */
446
447
448 GLOBAL VOID IRC_WriteStrServers( CLIENT *ExceptOf, CHAR *Format, ... )
449 {
450         CHAR buffer[1000];
451         va_list ap;
452
453         assert( Format != NULL );
454
455         va_start( ap, Format );
456         vsnprintf( buffer, 1000, Format, ap );
457         va_end( ap );
458
459         /* an den Client selber */
460         return IRC_WriteStrServersPrefix( ExceptOf, Client_ThisServer( ), buffer );
461 } /* IRC_WriteStrServers */
462
463
464 GLOBAL VOID IRC_WriteStrServersPrefix( CLIENT *ExceptOf, CLIENT *Prefix, CHAR *Format, ... )
465 {
466         CHAR buffer[1000];
467         CLIENT *c;
468         va_list ap;
469         
470         assert( Format != NULL );
471         assert( Prefix != NULL );
472
473         va_start( ap, Format );
474         vsnprintf( buffer, 1000, Format, ap );
475         va_end( ap );
476         
477         c = Client_First( );
478         while( c )
479         {
480                 if(( Client_Type( c ) == CLIENT_SERVER ) && ( Client_Conn( c ) > NONE ) && ( c != Client_ThisServer( )) && ( c != ExceptOf ))
481                 {
482                         /* Ziel-Server gefunden */
483                         IRC_WriteStrClientPrefix( c, Prefix, buffer );
484                 }
485                 c = Client_Next( c );
486         }
487 } /* IRC_WriteStrServersPrefix */
488
489
490 GLOBAL BOOLEAN IRC_WriteStrRelatedPrefix( CLIENT *Client, CLIENT *Prefix, BOOLEAN Remote, CHAR *Format, ... )
491 {
492         BOOLEAN sock[MAX_CONNECTIONS], is_server[MAX_CONNECTIONS], ok = CONNECTED;
493         CL2CHAN *chan_cl2chan, *cl2chan;
494         CHAR buffer[1000];
495         CHANNEL *chan;
496         va_list ap;
497         CLIENT *c;
498         INT i, s;
499
500         assert( Client != NULL );
501         assert( Prefix != NULL );
502         assert( Format != NULL );
503
504         va_start( ap, Format );
505         vsnprintf( buffer, 1000, Format, ap );
506         va_end( ap );
507
508         /* initialisieren */
509         for( i = 0; i < MAX_CONNECTIONS; i++ ) sock[i] = FALSE;
510
511         /* An alle Clients, die in einem Channel mit dem "Ausloeser" sind,
512          * den Text schicken. An Remote-Server aber jeweils nur einmal. */
513         chan_cl2chan = Channel_FirstChannelOf( Client );
514         while( chan_cl2chan )
515         {
516                 /* Channel des Users durchsuchen */
517                 chan = Channel_GetChannel( chan_cl2chan );
518                 cl2chan = Channel_FirstMember( chan );
519                 while( cl2chan )
520                 {
521                         c = Channel_GetClient( cl2chan );
522                         if( ! Remote )
523                         {
524                                 if( Client_Conn( c ) <= NONE ) c = NULL;
525                                 else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL;
526                         }
527                         if( c ) c = Client_NextHop( c );
528
529                         if( c && ( c != Client ))
530                         {
531                                 /* Ok, anderer Client */
532                                 s = Client_Conn( c );
533                                 assert( s >= 0 );
534                                 assert( s < MAX_CONNECTIONS );
535                                 sock[s] = TRUE;
536                                 if( Client_Type( c ) == CLIENT_SERVER ) is_server[s] = TRUE;
537                                 else is_server[s] = FALSE;
538                         }
539                         cl2chan = Channel_NextMember( chan, cl2chan );
540                 }
541                 
542                 /* naechsten Channel */
543                 chan_cl2chan = Channel_NextChannelOf( Client, chan_cl2chan );
544         }
545
546         /* Senden ... */
547         for( i = 0; i < MAX_CONNECTIONS; i++ )
548         {
549                 if( sock[i] )
550                 {
551                         if( is_server[i] ) ok = Conn_WriteStr( i, ":%s %s", Client_ID( Prefix ), buffer );
552                         else ok = Conn_WriteStr( i, ":%s %s", Client_Mask( Prefix ), buffer );
553                         if( ! ok ) break;
554                 }
555         }
556         return ok;
557 } /* IRC_WriteStrRelatedPrefix */
558
559
560
561 GLOBAL BOOLEAN IRC_PASS( CLIENT *Client, REQUEST *Req )
562 {
563         assert( Client != NULL );
564         assert( Req != NULL );
565
566         /* Fehler liefern, wenn kein lokaler Client */
567         if( Client_Conn( Client ) <= NONE ) return IRC_WriteStrClient( Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID( Client ), Req->command );
568         
569         if(( Client_Type( Client ) == CLIENT_UNKNOWN ) && ( Req->argc == 1))
570         {
571                 /* noch nicht registrierte unbekannte Verbindung */
572                 Log( LOG_DEBUG, "Connection %d: got PASS command ...", Client_Conn( Client ));
573
574                 /* Passwort speichern */
575                 Client_SetPassword( Client, Req->argv[0] );
576
577                 Client_SetType( Client, CLIENT_GOTPASS );
578                 return CONNECTED;
579         }
580         else if((( Client_Type( Client ) == CLIENT_UNKNOWN ) || ( Client_Type( Client ) == CLIENT_UNKNOWNSERVER )) && (( Req->argc == 3 ) || ( Req->argc == 4 )))
581         {
582                 /* noch nicht registrierte Server-Verbindung */
583                 Log( LOG_DEBUG, "Connection %d: got PASS command (new server link) ...", Client_Conn( Client ));
584
585                 /* Passwort speichern */
586                 Client_SetPassword( Client, Req->argv[0] );
587
588                 Client_SetType( Client, CLIENT_GOTPASSSERVER );
589                 return CONNECTED;
590         }
591         else if(( Client_Type( Client ) == CLIENT_UNKNOWN  ) || ( Client_Type( Client ) == CLIENT_UNKNOWNSERVER ))
592         {
593                 /* Falsche Anzahl Parameter? */
594                 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
595         }
596         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
597 } /* IRC_PASS */
598
599
600 GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
601 {
602         CHAR str[LINE_LEN], *ptr;
603         CLIENT *from, *c, *cl;
604         CL2CHAN *cl2chan;
605         INT max_hops, i;
606         CHANNEL *chan;
607         BOOLEAN ok;
608         
609         assert( Client != NULL );
610         assert( Req != NULL );
611
612         /* Fehler liefern, wenn kein lokaler Client */
613         if( Client_Conn( Client ) <= NONE ) return IRC_WriteStrClient( Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID( Client ), Req->command );
614
615         if( Client_Type( Client ) == CLIENT_GOTPASSSERVER )
616         {
617                 /* Verbindung soll als Server-Server-Verbindung registriert werden */
618                 Log( LOG_DEBUG, "Connection %d: got SERVER command (new server link) ...", Client_Conn( Client ));
619
620                 /* Falsche Anzahl Parameter? */
621                 if(( Req->argc != 2 ) && ( Req->argc != 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
622
623                 /* Ist dieser Server bei uns konfiguriert? */
624                 for( i = 0; i < Conf_Server_Count; i++ ) if( strcasecmp( Req->argv[0], Conf_Server[i].name ) == 0 ) break;
625                 if( i >= Conf_Server_Count )
626                 {
627                         /* Server ist nicht konfiguriert! */
628                         Log( LOG_ERR, "Connection %d: Server \"%s\" not configured here!", Client_Conn( Client ), Req->argv[0] );
629                         Conn_Close( Client_Conn( Client ), NULL, "Server not configured here", TRUE );
630                         return DISCONNECTED;
631                 }
632                 if( strcmp( Client_Password( Client ), Conf_Server[i].pwd ) != 0 )
633                 {
634                         /* Falsches Passwort */
635                         Log( LOG_ERR, "Connection %d: Bad password for server \"%s\"!", Client_Conn( Client ), Req->argv[0] );
636                         Conn_Close( Client_Conn( Client ), NULL, "Bad password", TRUE );
637                         return DISCONNECTED;
638                 }
639                 
640                 /* Ist ein Server mit dieser ID bereits registriert? */
641                 if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
642
643                 /* Server-Strukturen fuellen ;-) */
644                 Client_SetID( Client, Req->argv[0] );
645                 Client_SetHops( Client, 1 );
646                 Client_SetInfo( Client, Req->argv[Req->argc - 1] );
647                 
648                 /* Meldet sich der Server bei uns an? */
649                 if( Req->argc == 2 )
650                 {
651                         /* Unseren SERVER- und PASS-Befehl senden */
652                         ok = TRUE;
653                         if( ! IRC_WriteStrClient( Client, "PASS %s "PASSSERVERADD, Conf_Server[i].pwd )) ok = FALSE;
654                         else ok = IRC_WriteStrClient( Client, "SERVER %s 1 :%s", Conf_ServerName, Conf_ServerInfo );
655                         if( ! ok )
656                         {
657                                 Conn_Close( Client_Conn( Client ), "Unexpected server behavior!", NULL, FALSE );
658                                 return DISCONNECTED;
659                         }
660                         Client_SetIntroducer( Client, Client );
661                         Client_SetToken( Client, 1 );
662                 }
663                 else  Client_SetToken( Client, atoi( Req->argv[1] ));
664
665                 Log( LOG_NOTICE, "Server \"%s\" registered (connection %d, 1 hop - direct link).", Client_ID( Client ), Client_Conn( Client ));
666
667                 Client_SetType( Client, CLIENT_SERVER );
668
669                 /* maximalen Hop Count ermitteln */
670                 max_hops = 0;
671                 c = Client_First( );
672                 while( c )
673                 {
674                         if( Client_Hops( c ) > max_hops ) max_hops = Client_Hops( c );
675                         c = Client_Next( c );
676                 }
677                 
678                 /* Alle bisherigen Server dem neuen Server bekannt machen,
679                  * die bisherigen Server ueber den neuen informierenn */
680                 for( i = 0; i < ( max_hops + 1 ); i++ )
681                 {
682                         c = Client_First( );
683                         while( c )
684                         {
685                                 if(( Client_Type( c ) == CLIENT_SERVER ) && ( c != Client ) && ( c != Client_ThisServer( )) && ( Client_Hops( c ) == i ))
686                                 {
687                                         if( Client_Conn( c ) > NONE )
688                                         {
689                                                 /* Dem gefundenen Server gleich den neuen
690                                                  * Server bekannt machen */
691                                                 if( ! IRC_WriteStrClient( c, "SERVER %s %d %d :%s", Client_ID( Client ), Client_Hops( Client ) + 1, Client_MyToken( Client ), Client_Info( Client ))) return DISCONNECTED;
692                                         }
693                                         
694                                         /* Den neuen Server ueber den alten informieren */
695                                         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;
696                                 }
697                                 c = Client_Next( c );
698                         }
699                 }
700
701                 /* alle User dem neuen Server bekannt machen */
702                 c = Client_First( );
703                 while( c )
704                 {
705                         if( Client_Type( c ) == CLIENT_USER )
706                         {
707                                 /* User an neuen Server melden */
708                                 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;
709                         }
710                         c = Client_Next( c );
711                 }
712
713                 /* Channels dem neuen Server bekannt machen */
714                 chan = Channel_First( );
715                 while( chan )
716                 {
717                         sprintf( str, "NJOIN %s :", Channel_Name( chan ));
718
719                         /* alle Member suchen */
720                         cl2chan = Channel_FirstMember( chan );
721                         while( cl2chan )
722                         {
723                                 cl = Channel_GetClient( cl2chan );
724                                 assert( cl != NULL );
725
726                                 /* Nick, ggf. mit Modes, anhaengen */
727                                 if( str[strlen( str ) - 1] != ':' ) strcat( str, "," );
728                                 if( strchr( Channel_UserModes( chan, cl ), 'v' )) strcat( str, "+" );
729                                 if( strchr( Channel_UserModes( chan, cl ), 'o' )) strcat( str, "@" );
730                                 strcat( str, Client_ID( cl ));
731
732                                 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
733                                 {
734                                         /* Zeile senden */
735                                         if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
736                                         sprintf( str, "NJOIN %s :", Channel_Name( chan ));
737                                 }
738                                 
739                                 cl2chan = Channel_NextMember( chan, cl2chan );
740                         }
741
742                         /* noch Daten da? */
743                         if( str[strlen( str ) - 1] != ':')
744                         {
745                                 /* Ja; Also senden ... */
746                                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
747                         }
748
749                         /* naechsten Channel suchen */
750                         chan = Channel_Next( chan );
751                 }
752                 
753                 return CONNECTED;
754         }
755         else if( Client_Type( Client ) == CLIENT_SERVER )
756         {
757                 /* Neuer Server wird im Netz angekuendigt */
758
759                 /* Falsche Anzahl Parameter? */
760                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
761
762                 /* Ist ein Server mit dieser ID bereits registriert? */
763                 if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
764
765                 /* Ueberfluessige Hostnamen aus Info-Text entfernen */
766                 ptr = strchr( Req->argv[3] + 2, '[' );
767                 if( ! ptr ) ptr = Req->argv[3];
768
769                 from = Client_GetFromID( Req->prefix );
770                 if( ! from )
771                 {
772                         /* Hm, Server, der diesen einfuehrt, ist nicht bekannt!? */
773                         Log( LOG_ALERT, "Unknown ID in prefix of SERVER: \"%s\"! (on connection %d)", Req->prefix, Client_Conn( Client ));
774                         Conn_Close( Client_Conn( Client ), NULL, "Unknown ID in prefix of SERVER", TRUE );
775                         return DISCONNECTED;
776                 }
777
778                 /* Neue Client-Struktur anlegen */
779                 c = Client_NewRemoteServer( Client, Req->argv[0], from, atoi( Req->argv[1] ), atoi( Req->argv[2] ), ptr, TRUE );
780                 if( ! c )
781                 {
782                         /* Neue Client-Struktur konnte nicht angelegt werden */
783                         Log( LOG_ALERT, "Can't create client structure for server! (on connection %d)", Client_Conn( Client ));
784                         Conn_Close( Client_Conn( Client ), NULL, "Can't allocate client structure for remote server", TRUE );
785                         return DISCONNECTED;
786                 }
787
788                 /* Log-Meldung zusammenbauen und ausgeben */
789                 if(( Client_Hops( c ) > 1 ) && ( Req->prefix[0] )) sprintf( str, "connected to %s, ", Client_ID( from ));
790                 else strcpy( str, "" );
791                 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": "" );
792
793                 /* Andere Server informieren */
794                 IRC_WriteStrServersPrefix( Client, from, "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ));
795
796                 return CONNECTED;
797         }
798         else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
799 } /* IRC_SERVER */
800
801
802 GLOBAL BOOLEAN IRC_NJOIN( CLIENT *Client, REQUEST *Req )
803 {
804         CHAR *channame, *ptr, modes[8];
805         BOOLEAN is_op, is_voiced;
806         CHANNEL *chan;
807         CLIENT *c;
808         
809         assert( Client != NULL );
810         assert( Req != NULL );
811
812         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTEREDSERVER_MSG, Client_ID( Client ));
813
814         /* Falsche Anzahl Parameter? */
815         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
816
817         channame = Req->argv[0];
818         ptr = strtok( Req->argv[1], "," );
819         while( ptr )
820         {
821                 is_op = is_voiced = FALSE;
822                 
823                 /* Prefixe abschneiden */
824                 while(( *ptr == '@' ) || ( *ptr == '+' ))
825                 {
826                         if( *ptr == '@' ) is_op = TRUE;
827                         if( *ptr == '+' ) is_voiced = TRUE;
828                         ptr++;
829                 }
830
831                 c = Client_GetFromID( ptr );
832                 if( c )
833                 {
834                         Channel_Join( c, channame );
835                         chan = Channel_Search( channame );
836                         assert( chan != NULL );
837                         
838                         if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
839                         if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );
840
841                         /* im Channel bekannt machen */
842                         IRC_WriteStrChannelPrefix( Client, chan, c, FALSE, "JOIN :%s", channame );
843
844                         /* Channel-User-Modes setzen */
845                         strcpy( modes, Channel_UserModes( chan, c ));
846                         if( modes[0] )
847                         {
848                                 /* Modes im Channel bekannt machen */
849                                 IRC_WriteStrChannelPrefix( Client, chan, Client, FALSE, "MODE %s +%s %s", channame, modes, Client_ID( c ));
850                         }
851                 }
852                 else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame );
853                 
854                 /* naechsten Nick suchen */
855                 ptr = strtok( NULL, "," );
856         }
857
858         /* an andere Server weiterleiten */
859         IRC_WriteStrServersPrefix( Client, Client_ThisServer( ), "NJOIN %s :%s", Req->argv[0], Req->argv[1] );
860
861         return CONNECTED;
862 } /* IRC_NJOIN */
863
864
865 GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req )
866 {
867         CLIENT *intr_c, *target, *c;
868         CHAR *modes;
869
870         assert( Client != NULL );
871         assert( Req != NULL );
872
873         /* Zumindest BitchX sendet NICK-USER in der falschen Reihenfolge. */
874 #ifndef STRICT_RFC
875         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 ))
876 #else
877         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 ))
878 #endif
879         {
880                 /* User-Registrierung bzw. Nick-Aenderung */
881
882                 /* Falsche Anzahl Parameter? */
883                 if( Req->argc != 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
884
885                 /* "Ziel-Client" ermitteln */
886                 if( Client_Type( Client ) == CLIENT_SERVER )
887                 {
888                         target = Client_GetFromID( Req->prefix );
889                         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
890                 }
891                 else
892                 {
893                         /* Ist der Client "restricted"? */
894                         if( Client_HasMode( Client, 'r' )) return IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
895                         target = Client;
896                 }
897
898 #ifndef STRICT_RFC
899                 /* Wenn der Client zu seinem eigenen Nick wechseln will, so machen
900                  * wir nichts. So macht es das Original und mind. Snak hat probleme,
901                  * wenn wir es nicht so machen. Ob es so okay ist? Hm ... */
902                 if( strcmp( Client_ID( target ), Req->argv[0] ) == 0 ) return CONNECTED;
903 #endif
904                 
905                 /* pruefen, ob Nick bereits vergeben. Speziallfall: der Client
906                  * will nur die Gross- und Kleinschreibung aendern. Das darf
907                  * er natuerlich machen :-) */
908                 if( strcasecmp( Client_ID( target ), Req->argv[0] ) != 0 )
909                 {
910                         if( ! Client_CheckNick( target, Req->argv[0] )) return CONNECTED;
911                 }
912
913                 /* Nick-Aenderung: allen mitteilen! */
914                 
915                 if( Client_Type( Client ) == CLIENT_USER ) IRC_WriteStrClientPrefix( Client, Client, "NICK :%s", Req->argv[0] );
916                 IRC_WriteStrServersPrefix( Client, target, "NICK :%s", Req->argv[0] );
917                 IRC_WriteStrRelatedPrefix( target, target, FALSE, "NICK :%s", Req->argv[0] );
918
919                 if(( Client_Type( target ) != CLIENT_USER ) && ( Client_Type( target ) != CLIENT_SERVER ))
920                 {
921                         /* Neuer Client */
922                         Log( LOG_DEBUG, "Connection %d: got NICK command ...", Client_Conn( Client ));
923                         if( Client_Type( Client ) == CLIENT_GOTUSER ) return Hello_User( Client );
924                         else Client_SetType( Client, CLIENT_GOTNICK );
925                 }
926                 else Log( LOG_INFO, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] );
927
928                 /* Client-Nick registrieren */
929                 Client_SetID( target, Req->argv[0] );
930
931                 return CONNECTED;
932         }
933         else if( Client_Type( Client ) == CLIENT_SERVER )
934         {
935                 /* Server fuehrt neuen Client ein */
936
937                 /* Falsche Anzahl Parameter? */
938                 if( Req->argc != 7 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
939
940                 /* Nick ueberpruefen */
941                 c = Client_GetFromID( Req->argv[0] );
942                 if( c )
943                 {
944                         /* Der neue Nick ist auf diesem Server bereits registriert:
945                          * sowohl der neue, als auch der alte Client muessen nun
946                          * disconnectiert werden. */
947                         Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] );
948                         Kill_Nick( Req->argv[0], "Nick collision" );
949                         return CONNECTED;
950                 }
951
952                 /* Server, zu dem der Client connectiert ist, suchen */
953                 intr_c = Client_GetFromToken( Client, atoi( Req->argv[4] ));
954                 if( ! intr_c )
955                 {
956                         Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] );
957                         Kill_Nick( Req->argv[0], "Unknown server" );
958                         return CONNECTED;
959                 }
960
961                 /* Neue Client-Struktur anlegen */
962                 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 );
963                 if( ! c )
964                 {
965                         /* Eine neue Client-Struktur konnte nicht angelegt werden.
966                          * Der Client muss disconnectiert werden, damit der Netz-
967                          * status konsistent bleibt. */
968                         Log( LOG_ALERT, "Can't create client structure! (on connection %d)", Client_Conn( Client ));
969                         Kill_Nick( Req->argv[0], "Server error" );
970                         return CONNECTED;
971                 }
972
973                 modes = Client_Modes( c );
974                 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": "" );
975                 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": "" );
976
977                 /* Andere Server, ausser dem Introducer, informieren */
978                 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] );
979
980                 return CONNECTED;
981         }
982         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
983 } /* IRC_NICK */
984
985
986 GLOBAL BOOLEAN IRC_USER( CLIENT *Client, REQUEST *Req )
987 {
988         assert( Client != NULL );
989         assert( Req != NULL );
990
991 #ifndef STRICT_RFC
992         if( Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_UNKNOWN )
993 #else
994         if( Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTPASS )
995 #endif
996         {
997                 /* Falsche Anzahl Parameter? */
998                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
999
1000                 Client_SetUser( Client, Req->argv[0], FALSE );
1001                 Client_SetInfo( Client, Req->argv[3] );
1002
1003                 Log( LOG_DEBUG, "Connection %d: got USER command ...", Client_Conn( Client ));
1004                 if( Client_Type( Client ) == CLIENT_GOTNICK ) return Hello_User( Client );
1005                 else Client_SetType( Client, CLIENT_GOTUSER );
1006                 return CONNECTED;
1007         }
1008         else if( Client_Type( Client ) == CLIENT_USER || Client_Type( Client ) == CLIENT_SERVER || Client_Type( Client ) == CLIENT_SERVICE )
1009         {
1010                 return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
1011         }
1012         else return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1013 } /* IRC_USER */
1014
1015
1016 GLOBAL BOOLEAN IRC_QUIT( CLIENT *Client, REQUEST *Req )
1017 {
1018         CLIENT *target;
1019         
1020         assert( Client != NULL );
1021         assert( Req != NULL );
1022
1023         if(( Client_Type( Client ) == CLIENT_USER ) || ( Client_Type( Client ) == CLIENT_SERVICE ))
1024         {
1025                 /* User / Service */
1026                 
1027                 /* Falsche Anzahl Parameter? */
1028                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1029
1030                 if( Req->argc == 0 ) Conn_Close( Client_Conn( Client ), "Got QUIT command.", NULL, TRUE );
1031                 else Conn_Close( Client_Conn( Client ), "Got QUIT command.", Req->argv[0], TRUE );
1032                 
1033                 return DISCONNECTED;
1034         }
1035         else if ( Client_Type( Client ) == CLIENT_SERVER )
1036         {
1037                 /* Server */
1038
1039                 /* Falsche Anzahl Parameter? */
1040                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1041
1042                 target = Client_Search( Req->prefix );
1043                 if( ! target )
1044                 {
1045                         Log( LOG_ERR, "Got QUIT from %s for unknown client!?", Client_ID( Client ));
1046                         return CONNECTED;
1047                 }
1048
1049                 if( Req->argc == 0 ) Client_Destroy( target, "Got QUIT command.", NULL );
1050                 else Client_Destroy( target, "Got QUIT command.", Req->argv[0] );
1051
1052                 return CONNECTED;
1053         }
1054         else return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1055 } /* IRC_QUIT */
1056
1057
1058 GLOBAL BOOLEAN IRC_SQUIT( CLIENT *Client, REQUEST *Req )
1059 {
1060         CLIENT *target;
1061         CHAR msg[LINE_LEN + 64];
1062         
1063         assert( Client != NULL );
1064         assert( Req != NULL );
1065
1066         /* SQUIT ist nur fuer Server erlaubt */
1067         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1068
1069         /* Falsche Anzahl Parameter? */
1070         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1071
1072         Log( LOG_DEBUG, "Got SQUIT from %s for \"%s\": \"%s\" ...", Client_ID( Client ), Req->argv[0], Req->argv[1] );
1073         
1074         /* SQUIT an alle Server weiterleiten */
1075         IRC_WriteStrServers( Client, "SQUIT %s :%s", Req->argv[0], Req->argv[1] );
1076
1077         target = Client_GetFromID( Req->argv[0] );
1078         if( ! target )
1079         {
1080                 Log( LOG_ERR, "Got SQUIT from %s for unknown server \"%s\"!?", Client_ID( Client ), Req->argv[0] );
1081                 return CONNECTED;
1082         }
1083
1084         if( Req->argv[1][0] )
1085         {
1086                 if( strlen( Req->argv[1] ) > LINE_LEN ) Req->argv[1][LINE_LEN] = '\0';
1087                 sprintf( msg, "%s (SQUIT from %s).", Req->argv[1], Client_ID( Client ));
1088         }
1089         else sprintf( msg, "Got SQUIT from %s.", Client_ID( Client ));
1090
1091         if( Client_Conn( target ) > NONE )
1092         {
1093                 /* dieser Server hat die Connection */
1094                 if( Req->argv[1][0] ) Conn_Close( Client_Conn( target ), msg, Req->argv[1], TRUE );
1095                 else Conn_Close( Client_Conn( target ), msg, NULL, TRUE );
1096                 return DISCONNECTED;
1097         }
1098         else
1099         {
1100                 /* Verbindung hielt anderer Server */
1101                 Client_Destroy( target, msg, Req->argv[1] );
1102                 return CONNECTED;
1103         }
1104 } /* IRC_SQUIT */
1105
1106
1107 GLOBAL BOOLEAN IRC_PING( CLIENT *Client, REQUEST *Req )
1108 {
1109         CLIENT *target, *from;
1110         
1111         assert( Client != NULL );
1112         assert( Req != NULL );
1113
1114         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1115
1116         /* Falsche Anzahl Parameter? */
1117         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NOORIGIN_MSG, Client_ID( Client ));
1118         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1119         
1120         if( Req->argc == 2 )
1121         {
1122                 /* es wurde ein Ziel-Client angegeben */
1123                 target = Client_GetFromID( Req->argv[1] );
1124                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
1125                 if( target != Client_ThisServer( ))
1126                 {
1127                         /* ok, forwarden */
1128                         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1129                         else from = Client;
1130                         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
1131                         return IRC_WriteStrClientPrefix( target, from, "PING %s :%s", Client_ID( from ), Req->argv[1] );
1132                 }
1133         }
1134
1135         Log( LOG_DEBUG, "Connection %d: got PING, sending PONG ...", Client_Conn( Client ));
1136         return IRC_WriteStrClient( Client, "PONG %s :%s", Client_ID( Client_ThisServer( )), Client_ID( Client ));
1137 } /* IRC_PING */
1138
1139
1140 GLOBAL BOOLEAN IRC_PONG( CLIENT *Client, REQUEST *Req )
1141 {
1142         CLIENT *target, *from;
1143
1144         assert( Client != NULL );
1145         assert( Req != NULL );
1146
1147         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1148
1149         /* Falsche Anzahl Parameter? */
1150         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NOORIGIN_MSG, Client_ID( Client ));
1151         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1152
1153         /* forwarden? */
1154         if( Req->argc == 2 )
1155         {
1156                 target = Client_GetFromID( Req->argv[1] );
1157                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
1158                 if( target != Client_ThisServer( ))
1159                 {
1160                         /* ok, forwarden */
1161                         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1162                         else from = Client;
1163                         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
1164                         return IRC_WriteStrClientPrefix( target, from, "PONG %s :%s", Client_ID( from ), Req->argv[1] );
1165                 }
1166         }
1167
1168         /* Der Connection-Timestamp wurde schon beim Lesen aus dem Socket
1169          * aktualisiert, daher muss das hier nicht mehr gemacht werden. */
1170
1171         if( Client_Conn( Client ) > NONE ) Log( LOG_DEBUG, "Connection %d: received PONG. Lag: %ld seconds.", Client_Conn( Client ), time( NULL ) - Conn_LastPing( Client_Conn( Client )));
1172         else Log( LOG_DEBUG, "Connection %d: received PONG.", Client_Conn( Client ));
1173
1174         return CONNECTED;
1175 } /* IRC_PONG */
1176
1177
1178 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
1179 {
1180         assert( Client != NULL );
1181         assert( Req != NULL );
1182
1183         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1184
1185         /* Falsche Anzahl Parameter? */
1186         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1187
1188         return Show_MOTD( Client );
1189 } /* IRC_MOTD */
1190
1191
1192 GLOBAL BOOLEAN IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
1193 {
1194         CLIENT *to, *from;
1195         CHANNEL *chan;
1196         
1197         assert( Client != NULL );
1198         assert( Req != NULL );
1199
1200         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1201
1202         /* Falsche Anzahl Parameter? */
1203         if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
1204         if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
1205         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1206
1207         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1208         else from = Client;
1209         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1210
1211         to = Client_Search( Req->argv[0] );
1212         if( to )
1213         {
1214                 /* Okay, Ziel ist ein User */
1215                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
1216                 return IRC_WriteStrClientPrefix( to, from, "PRIVMSG %s :%s", Client_ID( to ), Req->argv[1] );
1217         }
1218
1219         chan = Channel_Search( Req->argv[0] );
1220         if( chan )
1221         {
1222                 /* Okay, Ziel ist ein Channel */
1223                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
1224                 return IRC_WriteStrChannelPrefix( Client, chan, from, TRUE, "PRIVMSG %s :%s", Req->argv[0], Req->argv[1] );
1225         }
1226
1227         return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
1228 } /* IRC_PRIVMSG */
1229
1230
1231 GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
1232 {
1233         CLIENT *to, *from;
1234
1235         assert( Client != NULL );
1236         assert( Req != NULL );
1237
1238         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1239
1240         /* Falsche Anzahl Parameter? */
1241         if( Req->argc != 2 ) return CONNECTED;
1242
1243         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1244         else from = Client;
1245         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1246
1247         to = Client_Search( Req->argv[0] );
1248         if( to )
1249         {
1250                 /* Okay, Ziel ist ein User */
1251                 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
1252         }
1253         else return CONNECTED;
1254 } /* IRC_NOTICE */
1255
1256
1257 GLOBAL BOOLEAN IRC_MODE( CLIENT *Client, REQUEST *Req )
1258 {
1259         CHAR *mode_ptr, the_modes[CLIENT_MODE_LEN], x[2];
1260         CLIENT *cl, *chan_cl, *prefix;
1261         BOOLEAN set, ok;
1262         CHANNEL *chan;
1263         
1264         assert( Client != NULL );
1265         assert( Req != NULL );
1266
1267         cl = chan_cl = prefix = NULL;
1268         chan = NULL;
1269
1270         /* Valider Client? */
1271         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1272
1273         /* Keine Parameter? */
1274         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1275
1276         /* Ziel suchen: Client bzw. Channel */
1277         if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
1278         if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
1279
1280         /* Kein Ziel gefunden? */
1281         if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
1282
1283         assert(( cl && chan ) != TRUE );
1284
1285         /* Falsche Anzahl Parameter? */
1286         if(( cl ) && ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1287         if(( chan ) && ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1288
1289         /* Client ermitteln, wenn bei Channel-Modes mit 3 Parametern */
1290         if(( chan ) && (Req->argc == 3 ))
1291         {
1292                 chan_cl = Client_Search( Req->argv[2] );
1293                 if( ! chan_cl ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
1294         }
1295         
1296         /* Wenn Anfragender ein User ist: Zugriff erlaubt? */
1297         if( Client_Type( Client ) == CLIENT_USER )
1298         {
1299                 if( cl )
1300                 {
1301                         /* MODE ist nur fuer sich selber zulaessig! */
1302                         if( cl != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
1303                 }
1304                 if( chan )
1305                 {
1306                         /* Darf der User die Channel-Modes ermitteln? */
1307                 }
1308         }
1309
1310         /* Werden die Modes "nur" erfragt? */
1311         if(( cl ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( cl ));
1312         if(( chan ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_CHANNELMODEIS_MSG, Client_ID( Client ), Channel_Name( chan ), Channel_Modes( chan ));
1313
1314         mode_ptr = Req->argv[1];
1315
1316         /* Sollen Modes gesetzt oder geloescht werden? */
1317         if( cl )
1318         {
1319                 if( *mode_ptr == '+' ) set = TRUE;
1320                 else if( *mode_ptr == '-' ) set = FALSE;
1321                 else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
1322                 mode_ptr++;
1323         }
1324         else
1325         {
1326                 if( *mode_ptr == '-' ) set = FALSE;
1327                 else set = TRUE;
1328                 if(( *mode_ptr == '-' ) || ( *mode_ptr == '+' )) mode_ptr++;
1329         }
1330         
1331         /* Prefix fuer Antworten etc. ermitteln */
1332         if( Client_Type( Client ) == CLIENT_SERVER )
1333         {
1334                 prefix = Client_GetFromID( Req->prefix );
1335                 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1336         }
1337         else prefix = Client;
1338
1339         /* Reply-String mit Aenderungen vorbereiten */
1340         if( set ) strcpy( the_modes, "+" );
1341         else strcpy( the_modes, "-" );
1342
1343         ok = TRUE;
1344         x[1] = '\0';
1345         while( *mode_ptr )
1346         {
1347                 x[0] = '\0';
1348                 if( Client_Type( Client ) == CLIENT_SERVER )
1349                 {
1350                         /* Befehl kommt von einem Server, daher
1351                          * trauen wir ihm "unbesehen" ... */
1352                         x[0] = *mode_ptr;
1353                 }
1354                 else
1355                 {
1356                         /* Modes validieren */
1357                         if( cl )
1358                         {
1359                                 /* User-Modes */
1360                                 switch( *mode_ptr )
1361                                 {
1362                                         case 'i':
1363                                                 /* invisible */
1364                                                 x[0] = 'i';
1365                                                 break;
1366                                         case 'r':
1367                                                 /* restricted (kann nur gesetzt werden) */
1368                                                 if( set ) x[0] = 'r';
1369                                                 else ok = IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
1370                                                 break;
1371                                         case 'o':
1372                                                 /* operator (kann nur geloescht werden) */
1373                                                 if( ! set )
1374                                                 {
1375                                                         Client_SetOperByMe( Client, FALSE );
1376                                                         x[0] = 'o';
1377                                                 }
1378                                                 else ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
1379                                                 break;
1380                                         default:
1381                                                 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ));
1382                                                 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
1383                                                 x[0] = '\0';
1384                                 }
1385                         }
1386                         if( chan )
1387                         {
1388                                 /* Ist der User ein Channel Operator? */
1389                                 if( ! strchr( Channel_UserModes( chan, Client ), 'o' ))
1390                                 {
1391                                         Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan ));
1392                                         ok = IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan ));
1393                                         break;
1394                                 }
1395                                 
1396                                 /* Channel-Modes oder Channel-User-Modes */
1397                                 if( chan_cl )
1398                                 {
1399                                         /* Channel-User-Modes */
1400                                         switch( *mode_ptr )
1401                                         {
1402                                                 case 'o':
1403                                                         /* Channel Operator */
1404                                                         x[0] = 'o';
1405                                                         break;
1406                                                 case 'v':
1407                                                         /* Voice */
1408                                                         x[0] = 'v';
1409                                                         break;
1410                                                 default:
1411                                                         Log( LOG_DEBUG, "Unknown channel-user-mode \"%c%c\" from \"%s\" on \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Client_ID( chan_cl ), Channel_Name( chan ));
1412                                                         ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
1413                                                         x[0] = '\0';
1414                                         }
1415                                 }
1416                                 else
1417                                 {
1418                                         /* Channel-Modes */
1419                                         switch( *mode_ptr )
1420                                         {
1421                                                 case 'a':
1422                                                         /* Anonymous */
1423                                                         x[0] = 'a';
1424                                                         break;
1425                                                 case 'm':
1426                                                         /* Moderated */
1427                                                         x[0] = 'm';
1428                                                         break;
1429                                                 case 'n':
1430                                                         /* kein Schreiben in den Channel von aussen */
1431                                                         x[0] = 'n';
1432                                                         break;
1433                                                 case 'p':
1434                                                         /* Private */
1435                                                         x[0] = 'p';
1436                                                         break;
1437                                                 case 'q':
1438                                                         /* Quite */
1439                                                         x[0] = 'q';
1440                                                         break;
1441                                                 case 's':
1442                                                         /* Secret */
1443                                                         x[0] = 's';
1444                                                         break;
1445                                                 case 't':
1446                                                         /* Topic Lock */
1447                                                         x[0] = 't';
1448                                                         break;
1449                                                 default:
1450                                                         Log( LOG_DEBUG, "Unknown channel-mode \"%c%c\" from \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Channel_Name( chan ));
1451                                                         ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
1452                                                         x[0] = '\0';
1453                                         }
1454                                 }
1455                         }
1456                 }
1457                 if( ! ok ) break;
1458                 
1459                 mode_ptr++;
1460                 if( ! x[0] ) continue;
1461
1462                 /* Okay, gueltigen Mode gefunden */
1463                 if( cl )
1464                 {
1465                         /* Es geht um User-Modes */
1466                         if( set )
1467                         {
1468                                 /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
1469                                 if( Client_ModeAdd( cl, x[0] )) strcat( the_modes, x );
1470                         }
1471                         else
1472                         {
1473                                 /* Modes geloescht. Wenn der Client ihn hatte: merken */
1474                                 if( Client_ModeDel( cl, x[0] )) strcat( the_modes, x );
1475                         }
1476                 }
1477                 if( chan )
1478                 {
1479                         /* Es geht um Channel-Modes oder Channel-User-Modes */
1480                         if( chan_cl )
1481                         {
1482                                 /* Channel-User-Modes */
1483                                 if( set )
1484                                 {
1485                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
1486                                         if( Channel_UserModeAdd( chan, chan_cl, x[0] )) strcat( the_modes, x );
1487                                 }
1488                                 else
1489                                 {
1490                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
1491                                         if( Channel_UserModeDel( chan, chan_cl, x[0] )) strcat( the_modes, x );
1492                                 }
1493                         }
1494                         else
1495                         {
1496                                 /* Channel-Mode */
1497                                 if( set )
1498                                 {
1499                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
1500                                         if( Channel_ModeAdd( chan, x[0] )) strcat( the_modes, x );
1501                                 }
1502                                 else
1503                                 {
1504                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
1505                                         if( Channel_ModeDel( chan, x[0] )) strcat( the_modes, x );
1506                                 }
1507                         }
1508                 }
1509         }
1510
1511         /* Wurden Modes geaendert? */
1512         if( the_modes[1] )
1513         {
1514                 if( cl )
1515                 {
1516                         /* Client-Mode */
1517                         if( Client_Type( Client ) == CLIENT_SERVER )
1518                         {
1519                                 /* Modes an andere Server forwarden */
1520                                 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
1521                         }
1522                         else
1523                         {
1524                                 /* Bestaetigung an Client schicken & andere Server informieren */
1525                                 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Client_ID( cl ), the_modes );
1526                                 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
1527                         }
1528                         Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
1529                 }
1530                 if( chan )
1531                 {
1532                         /* Channel-Modes oder Channel-User-Mode */
1533                         if( chan_cl )
1534                         {
1535                                 /* Channel-User-Mode */
1536                                 if( Client_Type( Client ) == CLIENT_SERVER )
1537                                 {
1538                                         /* Modes an andere Server und Channel-User forwarden */
1539                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1540                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1541                                 }
1542                                 else
1543                                 {
1544                                         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
1545                                         ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1546                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1547                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
1548                                 }
1549                                 Log( LOG_DEBUG, "User \"%s\" on %s: Mode change, now \"%s\".", Client_Mask( chan_cl), Channel_Name( chan ), Channel_UserModes( chan, chan_cl ));
1550                         }
1551                         else
1552                         {
1553                                 /* Channel-Mode */
1554                                 if( Client_Type( Client ) == CLIENT_SERVER )
1555                                 {
1556                                         /* Modes an andere Server und Channel-User forwarden */
1557                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
1558                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
1559                                 }
1560                                 else
1561                                 {
1562                                         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
1563                                         ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Channel_Name( chan ), the_modes );
1564                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
1565                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
1566                                 }
1567                                 Log( LOG_DEBUG, "Channel \"%s\": Mode change, now \"%s\".", Channel_Name( chan ), Channel_Modes( chan ));
1568                         }
1569                 }
1570         }
1571
1572         return ok;
1573 } /* IRC_MODE */
1574
1575
1576 GLOBAL BOOLEAN IRC_OPER( CLIENT *Client, REQUEST *Req )
1577 {
1578         INT i;
1579         
1580         assert( Client != NULL );
1581         assert( Req != NULL );
1582
1583         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1584         
1585         /* Falsche Anzahl Parameter? */
1586         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1587
1588         /* Operator suchen */
1589         for( i = 0; i < Conf_Oper_Count; i++)
1590         {
1591                 if( Conf_Oper[i].name[0] && Conf_Oper[i].pwd[0] && ( strcmp( Conf_Oper[i].name, Req->argv[0] ) == 0 )) break;
1592         }
1593         if( i >= Conf_Oper_Count )
1594         {
1595                 Log( LOG_WARNING, "Got invalid OPER from \"%s\": Name \"%s\" not configured!", Client_Mask( Client ), Req->argv[0] );
1596                 return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
1597         }
1598
1599         /* Stimmt das Passwort? */
1600         if( strcmp( Conf_Oper[i].pwd, Req->argv[1] ) != 0 )
1601         {
1602                 Log( LOG_WARNING, "Got invalid OPER from \"%s\": Bad password for \"%s\"!", Client_Mask( Client ), Conf_Oper[i].name );
1603                 return IRC_WriteStrClient( Client, ERR_PASSWDMISMATCH_MSG, Client_ID( Client ));
1604         }
1605         
1606         if( ! Client_HasMode( Client, 'o' ))
1607         {
1608                 /* noch kein o-Mode gesetzt */
1609                 Client_ModeAdd( Client, 'o' );
1610                 if( ! IRC_WriteStrClient( Client, "MODE %s :+o", Client_ID( Client ))) return DISCONNECTED;
1611                 IRC_WriteStrServersPrefix( NULL, Client, "MODE %s :+o", Client_ID( Client ));
1612         }
1613
1614         if( ! Client_OperByMe( Client )) Log( LOG_NOTICE, "Got valid OPER from \"%s\", user is an IRC operator now.", Client_Mask( Client ));
1615
1616         Client_SetOperByMe( Client, TRUE );
1617         return IRC_WriteStrClient( Client, RPL_YOUREOPER_MSG, Client_ID( Client ));
1618 } /* IRC_OPER */
1619
1620
1621 GLOBAL BOOLEAN IRC_DIE( CLIENT *Client, REQUEST *Req )
1622 {
1623         assert( Client != NULL );
1624         assert( Req != NULL );
1625
1626         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1627
1628         /* Falsche Anzahl Parameter? */
1629         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1630
1631         if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
1632
1633         Log( LOG_NOTICE, "Got DIE command from \"%s\", going down!", Client_Mask( Client ));
1634         NGIRCd_Quit = TRUE;
1635         return CONNECTED;
1636 } /* IRC_DIE */
1637
1638
1639 GLOBAL BOOLEAN IRC_RESTART( CLIENT *Client, REQUEST *Req )
1640 {
1641         assert( Client != NULL );
1642         assert( Req != NULL );
1643
1644         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1645
1646         /* Falsche Anzahl Parameter? */
1647         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1648
1649         if(( ! Client_HasMode( Client, 'o' )) || ( ! Client_OperByMe( Client ))) return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
1650
1651         Log( LOG_NOTICE, "Got RESTART command from \"%s\", going down!", Client_Mask( Client ));
1652         NGIRCd_Restart = TRUE;
1653         return CONNECTED;
1654 } /* IRC_RESTART */
1655
1656
1657 GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req )
1658 {
1659         CHAR rpl[COMMAND_LEN], *ptr;
1660         CLIENT *target, *from, *c;
1661         CHANNEL *chan;
1662         
1663         assert( Client != NULL );
1664         assert( Req != NULL );
1665
1666         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1667
1668         /* Falsche Anzahl Parameter? */
1669         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1670
1671         /* From aus Prefix ermitteln */
1672         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1673         else from = Client;
1674         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
1675         
1676         if( Req->argc == 2 )
1677         {
1678                 /* an anderen Server forwarden */
1679                 target = Client_GetFromID( Req->argv[1] );
1680                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
1681
1682                 if( target != Client_ThisServer( ))
1683                 {
1684                         /* Ok, anderer Server ist das Ziel: forwarden */
1685                         return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
1686                 }
1687         }
1688
1689         if( Req->argc > 0 )
1690         {
1691                 /* bestimmte Channels durchgehen */
1692                 ptr = strtok( Req->argv[0], "," );
1693                 while( ptr )
1694                 {
1695                         chan = Channel_Search( ptr );
1696                         if( chan )
1697                         {
1698                                 /* Namen ausgeben */
1699                                 if( ! Send_NAMES( from, chan )) return DISCONNECTED;
1700                         }
1701                         if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
1702                         
1703                         /* naechsten Namen ermitteln */
1704                         ptr = strtok( NULL, "," );
1705                 }
1706                 return CONNECTED;
1707         }
1708         
1709         /* alle Channels durchgehen */
1710         chan = Channel_First( );
1711         while( chan )
1712         {
1713                 /* Namen ausgeben */
1714                 if( ! Send_NAMES( from, chan )) return DISCONNECTED;
1715
1716                 /* naechster Channel */
1717                 chan = Channel_Next( chan );
1718         }
1719
1720         /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
1721         c = Client_First( );
1722         sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
1723         while( c )
1724         {
1725                 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
1726                 {
1727                         /* Okay, das ist ein User: anhaengen */
1728                         if( rpl[strlen( rpl ) - 1] != ':' ) strcat( rpl, " " );
1729                         strcat( rpl, Client_ID( c ));
1730
1731                         if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
1732                         {
1733                                 /* Zeile wird zu lang: senden! */
1734                                 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
1735                                 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
1736                         }
1737                 }
1738
1739                 /* naechster Client */
1740                 c = Client_Next( c );
1741         }
1742         if( rpl[strlen( rpl ) - 1] != ':')
1743         {
1744                 /* es wurden User gefunden */
1745                 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
1746         }
1747         
1748         return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
1749 } /* IRC_NAMES */
1750
1751
1752 GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
1753 {
1754         CHAR rpl[COMMAND_LEN];
1755         CLIENT *c;
1756         CHAR *ptr;
1757         INT i;
1758         
1759         assert( Client != NULL );
1760         assert( Req != NULL );
1761
1762         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1763
1764         /* Falsche Anzahl Parameter? */
1765         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1766
1767         strcpy( rpl, RPL_ISON_MSG );
1768         for( i = 0; i < Req->argc; i++ )
1769         {
1770                 ptr = strtok( Req->argv[i], " " );
1771                 while( ptr )
1772                 {
1773                         ngt_TrimStr( ptr );
1774                         c = Client_GetFromID( ptr );
1775                         if( c && ( Client_Type( c ) == CLIENT_USER ))
1776                         {
1777                                 /* Dieser Nick ist "online" */
1778                                 strcat( rpl, ptr );
1779                                 strcat( rpl, " " );
1780                         }
1781                         ptr = strtok( NULL, " " );
1782                 }
1783         }
1784         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
1785
1786         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
1787 } /* IRC_ISON */
1788
1789
1790 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
1791 {
1792         CLIENT *from, *target, *c;
1793         CHAR str[LINE_LEN + 1], *ptr = NULL;
1794         CL2CHAN *cl2chan;
1795         CHANNEL *chan;
1796         
1797         assert( Client != NULL );
1798         assert( Req != NULL );
1799
1800         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1801
1802         /* Falsche Anzahl Parameter? */
1803         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1804
1805         /* Client suchen */
1806         c = Client_GetFromID( Req->argv[Req->argc - 1] );
1807         if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
1808
1809         /* Empfaenger des WHOIS suchen */
1810         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1811         else from = Client;
1812         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1813         
1814         /* Forwarden an anderen Server? */
1815         if( Req->argc > 1 )
1816         {
1817                 /* angegebenen Ziel-Server suchen */
1818                 target = Client_GetFromID( Req->argv[1] );
1819                 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
1820                 ptr = Req->argv[1];
1821         }
1822         else target = Client_ThisServer( );
1823
1824         assert( target != NULL );
1825         
1826         if(( Client_NextHop( target ) != Client_ThisServer( )) && ( Client_Type( Client_NextHop( target )) == CLIENT_SERVER )) return IRC_WriteStrClientPrefix( target, from, "WHOIS %s :%s", Req->argv[0], ptr );
1827         
1828         /* Nick, User und Name */
1829         if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
1830
1831         /* Server */
1832         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;
1833
1834         /* Channels */
1835         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
1836         cl2chan = Channel_FirstChannelOf( c );
1837         while( cl2chan )
1838         {
1839                 chan = Channel_GetChannel( cl2chan );
1840                 assert( chan != NULL );
1841                 
1842                 /* Channel-Name anhaengen */
1843                 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
1844                 if( strchr( Channel_UserModes( chan, c ), 'v' )) strcat( str, "+" );
1845                 if( strchr( Channel_UserModes( chan, c ), 'o' )) strcat( str, "@" );
1846                 strcat( str, Channel_Name( chan ));
1847
1848                 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
1849                 {
1850                         /* Zeile wird zu lang: senden! */
1851                         if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
1852                         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
1853                 }
1854
1855                 /* naechstes Mitglied suchen */
1856                 cl2chan = Channel_NextChannelOf( c, cl2chan );
1857         }
1858         if( str[strlen( str ) - 1] != ':')
1859         {
1860                 /* Es sind noch Daten da, die gesendet werden muessen */
1861                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
1862         }
1863         
1864         /* IRC-Operator? */
1865         if( Client_HasMode( c, 'o' ))
1866         {
1867                 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
1868         }
1869
1870         /* Idle (nur lokale Clients) */
1871         if( Client_Conn( c ) > NONE )
1872         {
1873                 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
1874         }
1875
1876         /* End of Whois */
1877         return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
1878 } /* IRC_WHOIS */
1879
1880
1881 GLOBAL BOOLEAN IRC_USERHOST( CLIENT *Client, REQUEST *Req )
1882 {
1883         CHAR rpl[COMMAND_LEN];
1884         CLIENT *c;
1885         INT max, i;
1886
1887         assert( Client != NULL );
1888         assert( Req != NULL );
1889
1890         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1891
1892         /* Falsche Anzahl Parameter? */
1893         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1894
1895         if( Req->argc > 5 ) max = 5;
1896         else max = Req->argc;
1897         
1898         strcpy( rpl, RPL_USERHOST_MSG );
1899         for( i = 0; i < max; i++ )
1900         {
1901                 c = Client_GetFromID( Req->argv[i] );
1902                 if( c && ( Client_Type( c ) == CLIENT_USER ))
1903                 {
1904                         /* Dieser Nick ist "online" */
1905                         strcat( rpl, Client_ID( c ));
1906                         if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
1907                         strcat( rpl, "=" );
1908                         if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
1909                         else strcat( rpl, "+" );
1910                         strcat( rpl, Client_User( c ));
1911                         strcat( rpl, "@" );
1912                         strcat( rpl, Client_Hostname( c ));
1913                         strcat( rpl, " " );
1914                 }
1915         }
1916         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
1917
1918         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
1919 } /* IRC_USERHOST */
1920
1921
1922 GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req )
1923 {
1924         assert( Client != NULL );
1925         assert( Req != NULL );
1926
1927         if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
1928         else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
1929
1930         return CONNECTED;
1931 } /* IRC_ERROR */
1932
1933
1934 GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req )
1935 {
1936         CLIENT *target, *from;
1937         
1938         assert( Client != NULL );
1939         assert( Req != NULL );
1940
1941         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1942
1943         /* Falsche Anzahl Parameter? */
1944         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1945
1946         /* Absender ermitteln */
1947         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1948         else from = Client;
1949         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1950
1951         /* An anderen Server forwarden? */
1952         if( Req->argc == 2 )
1953         {
1954                 target = Client_GetFromID( Req->argv[1] );
1955                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
1956                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
1957         }
1958
1959         /* Wer ist der Absender? */
1960         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
1961         else target = Client;
1962         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1963         
1964         Send_LUSERS( target );
1965
1966         return CONNECTED;
1967 } /* IRC_LUSERS */
1968
1969
1970 GLOBAL BOOLEAN IRC_LINKS( CLIENT *Client, REQUEST *Req )
1971 {
1972         CLIENT *target, *from, *c;
1973         CHAR *mask;
1974         
1975         assert( Client != NULL );
1976         assert( Req != NULL );
1977
1978         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
1979
1980         /* Falsche Anzahl Parameter? */
1981         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
1982
1983         /* Server-Mask ermitteln */
1984         if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
1985         else mask = "*";
1986
1987         /* Absender ermitteln */
1988         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
1989         else from = Client;
1990         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
1991         
1992         /* An anderen Server forwarden? */
1993         if( Req->argc == 2 )
1994         {
1995                 target = Client_GetFromID( Req->argv[0] );
1996                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
1997                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
1998         }
1999
2000         /* Wer ist der Absender? */
2001         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
2002         else target = Client;
2003         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
2004         
2005         c = Client_First( );
2006         while( c )
2007         {
2008                 if( Client_Type( c ) == CLIENT_SERVER )
2009                 {
2010                         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;
2011                 }
2012                 c = Client_Next( c );
2013         }
2014         
2015         return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
2016 } /* IRC_LINKS */
2017
2018
2019 GLOBAL BOOLEAN IRC_JOIN( CLIENT *Client, REQUEST *Req )
2020 {
2021         CHAR *channame, *flags, modes[8];
2022         BOOLEAN is_new_chan;
2023         CLIENT *target;
2024         CHANNEL *chan;
2025         
2026         assert( Client != NULL );
2027         assert( Req != NULL );
2028
2029         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
2030
2031         /* Falsche Anzahl Parameter? */
2032         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
2033
2034         /* Wer ist der Absender? */
2035         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
2036         else target = Client;
2037         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
2038         
2039         /* Channel-Namen durchgehen */
2040         channame = strtok( Req->argv[0], "," );
2041         while( channame )
2042         {
2043                 /* wird der Channel neu angelegt? */
2044                 flags = NULL;
2045
2046                 if( Channel_Search( channame )) is_new_chan = FALSE;
2047                 else is_new_chan = TRUE;
2048
2049                 /* Hat ein Server Channel-User-Modes uebergeben? */
2050                 if( Client_Type( Client ) == CLIENT_SERVER )
2051                 {
2052                         /* Channel-Flags extrahieren */
2053                         flags = strchr( channame, 0x7 );
2054                         if( flags ) *flags++ = '\0';
2055                 }
2056
2057                 /* neuer Channel udn lokaler Client? */
2058                 if( is_new_chan && ( Client_Type( Client ) == CLIENT_USER ))
2059                 {
2060                         /* Dann soll der Client Channel-Operator werden! */
2061                         flags = "o";
2062                 }
2063
2064                 /* Channel joinen (und ggf. anlegen) */
2065                 if( ! Channel_Join( target, channame ))
2066                 {
2067                         /* naechsten Namen ermitteln */
2068                         channame = strtok( NULL, "," );
2069                         continue;
2070                 }
2071                 chan = Channel_Search( channame );
2072                 assert( chan != NULL );
2073
2074                 /* Modes setzen (wenn vorhanden) */
2075                 while( flags && *flags )
2076                 {
2077                         Channel_UserModeAdd( chan, target, *flags );
2078                         flags++;
2079                 }
2080
2081                 /* Muessen Modes an andere Server gemeldet werden? */
2082                 strcpy( &modes[1], Channel_UserModes( chan, target ));
2083                 if( modes[1] ) modes[0] = 0x7;
2084                 else modes[0] = '\0';
2085
2086                 /* An andere Server weiterleiten */
2087                 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
2088
2089                 /* im Channel bekannt machen */
2090                 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
2091                 if( modes[1] )
2092                 {
2093                         /* Modes im Channel bekannt machen */
2094                         IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s %s :%s", channame, modes, Client_ID( target ));
2095                 }
2096
2097                 if( Client_Type( Client ) == CLIENT_USER )
2098                 {
2099                         /* an Client bestaetigen */
2100                         IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
2101
2102                         /* Topic an Client schicken */
2103                         IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, "What a wonderful channel!" );
2104
2105                         /* Mitglieder an Client Melden */
2106                         Send_NAMES( Client, chan );
2107                         IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
2108                 }
2109                 
2110                 /* naechsten Namen ermitteln */
2111                 channame = strtok( NULL, "," );
2112         }
2113         return CONNECTED;
2114 } /* IRC_JOIN */
2115
2116
2117 GLOBAL BOOLEAN IRC_PART( CLIENT *Client, REQUEST *Req )
2118 {
2119         CLIENT *target;
2120         CHAR *chan;
2121
2122         assert( Client != NULL );
2123         assert( Req != NULL );
2124
2125         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
2126
2127         /* Falsche Anzahl Parameter? */
2128         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
2129
2130         /* Wer ist der Absender? */
2131         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
2132         else target = Client;
2133         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
2134
2135         /* Channel-Namen durchgehen */
2136         chan = strtok( Req->argv[0], "," );
2137         while( chan )
2138         {
2139                 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
2140                 {
2141                         /* naechsten Namen ermitteln */
2142                         chan = strtok( NULL, "," );
2143                         continue;
2144                 }
2145
2146                 /* naechsten Namen ermitteln */
2147                 chan = strtok( NULL, "," );
2148         }
2149         return CONNECTED;
2150 } /* IRC_PART */
2151
2152
2153 GLOBAL BOOLEAN IRC_VERSION( CLIENT *Client, REQUEST *Req )
2154 {
2155         CLIENT *target, *prefix;
2156         
2157         assert( Client != NULL );
2158         assert( Req != NULL );
2159
2160         /* Falsche Anzahl Parameter? */
2161         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
2162
2163         /* Ziel suchen */
2164         if( Req->argc == 1 ) target = Client_GetFromID( Req->argv[0] );
2165         else target = Client_ThisServer( );
2166
2167         /* Prefix ermitteln */
2168         if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_GetFromID( Req->prefix );
2169         else prefix = Client;
2170         if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
2171         
2172         /* An anderen Server weiterleiten? */
2173         if( target != Client_ThisServer( ))
2174         {
2175                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
2176
2177                 /* forwarden */
2178                 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
2179                 return CONNECTED;
2180         }
2181
2182         /* mit Versionsinfo antworten */
2183         return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition( ));
2184 } /* IRC_VERSION */
2185
2186
2187 GLOBAL BOOLEAN IRC_KILL( CLIENT *Client, REQUEST *Req )
2188 {
2189         CLIENT *prefix, *c;
2190         
2191         assert( Client != NULL );
2192         assert( Req != NULL );
2193
2194         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
2195
2196         /* Falsche Anzahl Parameter? */
2197         if(( Req->argc != 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
2198
2199         prefix = Client_GetFromID( Req->prefix );
2200         if( ! prefix )
2201         {
2202                 Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", Req->prefix );
2203                 prefix = Client_ThisServer( );
2204         }
2205         
2206         Log( LOG_NOTICE, "Got KILL command from \"%s\" for \"%s\": %s", Client_Mask( prefix ), Req->argv[0], Req->argv[1] );
2207         
2208         /* andere Server benachrichtigen */
2209         IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", Req->argv[0], Req->argv[1] );
2210
2211         /* haben wir selber einen solchen Client? */
2212         c = Client_GetFromID( Req->argv[0] );
2213         if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Req->argv[1], TRUE );
2214         
2215         return CONNECTED;
2216 } /* IRC_KILL */
2217
2218
2219 LOCAL BOOLEAN Hello_User( CLIENT *Client )
2220 {
2221         assert( Client != NULL );
2222
2223         /* Passwort ueberpruefen */
2224         if( strcmp( Client_Password( Client ), Conf_ServerPwd ) != 0 )
2225         {
2226                 /* Falsches Passwort */
2227                 Log( LOG_ERR, "User \"%s\" rejected (connection %d): Bad password!", Client_Mask( Client ), Client_Conn( Client ));
2228                 Conn_Close( Client_Conn( Client ), NULL, "Bad password", TRUE );
2229                 return DISCONNECTED;
2230         }
2231
2232         Log( LOG_NOTICE, "User \"%s\" registered (connection %d).", Client_Mask( Client ), Client_Conn( Client ));
2233
2234         /* Andere Server informieren */
2235         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 ));
2236
2237         if( ! IRC_WriteStrClient( Client, RPL_WELCOME_MSG, Client_ID( Client ), Client_Mask( Client ))) return FALSE;
2238         if( ! IRC_WriteStrClient( Client, RPL_YOURHOST_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return FALSE;
2239         if( ! IRC_WriteStrClient( Client, RPL_CREATED_MSG, Client_ID( Client ), NGIRCd_StartStr )) return FALSE;
2240         if( ! IRC_WriteStrClient( Client, RPL_MYINFO_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return FALSE;
2241
2242         Client_SetType( Client, CLIENT_USER );
2243
2244         if( ! Send_LUSERS( Client )) return DISCONNECTED;
2245         if( ! Show_MOTD( Client )) return DISCONNECTED;
2246         
2247         return CONNECTED;
2248 } /* Hello_User */
2249
2250
2251 LOCAL BOOLEAN Show_MOTD( CLIENT *Client )
2252 {
2253         BOOLEAN ok;
2254         CHAR line[127];
2255         FILE *fd;
2256         
2257         assert( Client != NULL );
2258
2259         fd = fopen( Conf_MotdFile, "r" );
2260         if( ! fd )
2261         {
2262                 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
2263                 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
2264         }
2265         
2266         IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
2267         while( TRUE )
2268         {
2269                 if( ! fgets( line, 126, fd )) break;
2270                 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
2271                 if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
2272                 {
2273                         fclose( fd );
2274                         return FALSE;
2275                 }
2276         }
2277         ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
2278
2279         fclose( fd );
2280         
2281         return ok;
2282 } /* Show_MOTD */
2283
2284
2285 LOCAL VOID Kill_Nick( CHAR *Nick, CHAR *Reason )
2286 {
2287         CLIENT *c;
2288
2289         assert( Nick != NULL );
2290         assert( Reason != NULL );
2291         
2292         Log( LOG_ERR, "User(s) with nick \"%s\" will be disconnected: %s", Nick, Reason );
2293
2294         /* andere Server benachrichtigen */
2295         IRC_WriteStrServers( NULL, "KILL %s :%s", Nick, Reason );
2296
2297         /* Ggf. einen eigenen Client toeten */
2298         c = Client_GetFromID( Nick );
2299         if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Reason, TRUE );
2300 } /* Kill_Nick */
2301
2302
2303 LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan )
2304 {
2305         BOOLEAN is_visible, is_member;
2306         CHAR str[LINE_LEN + 1];
2307         CL2CHAN *cl2chan;
2308         CLIENT *cl;
2309         
2310         assert( Client != NULL );
2311         assert( Chan != NULL );
2312
2313         if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
2314         else is_member = FALSE;
2315                          
2316         /* Alle Mitglieder suchen */
2317         sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
2318         cl2chan = Channel_FirstMember( Chan );
2319         while( cl2chan )
2320         {
2321                 cl = Channel_GetClient( cl2chan );
2322
2323                 if( strchr( Client_Modes( cl ), 'i' )) is_visible = FALSE;
2324                 else is_visible = TRUE;
2325
2326                 if( is_member || is_visible )
2327                 {
2328                         /* Nick anhaengen */
2329                         if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
2330                         if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" );
2331                         if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" );
2332                         strcat( str, Client_ID( cl ));
2333         
2334                         if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
2335                         {
2336                                 /* Zeile wird zu lang: senden! */
2337                                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
2338                                 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
2339                         }
2340                 }
2341
2342                 /* naechstes Mitglied suchen */
2343                 cl2chan = Channel_NextMember( Chan, cl2chan );
2344         }
2345         if( str[strlen( str ) - 1] != ':')
2346         {
2347                 /* Es sind noch Daten da, die gesendet werden muessen */
2348                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
2349         }
2350
2351         return CONNECTED;
2352 } /* Send_NAMES */
2353
2354
2355 LOCAL BOOLEAN Send_LUSERS( CLIENT *Client )
2356 {
2357         INT cnt;
2358
2359         assert( Client != NULL );
2360
2361         /* Users, Services und Serevr im Netz */
2362         if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
2363
2364         /* IRC-Operatoren im Netz */
2365         cnt = Client_OperCount( );
2366         if( cnt > 0 )
2367         {
2368                 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
2369         }
2370
2371         /* Unbekannt Verbindungen */
2372         cnt = Client_UnknownCount( );
2373         if( cnt > 0 )
2374         {
2375                 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
2376         }
2377
2378         /* Channels im Netz */
2379         if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
2380
2381         /* Channels im Netz */
2382         if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
2383         
2384         return CONNECTED;
2385 } /* Send_LUSERS */
2386
2387
2388 CHAR *Get_Prefix( CLIENT *Target, CLIENT *Client )
2389 {
2390         assert( Target != NULL );
2391         assert( Client != NULL );
2392
2393         if( Client_Type( Target ) == CLIENT_SERVER ) return Client_ID( Client );
2394         else return Client_Mask( Client );
2395 } /* Get_Prefix */
2396
2397
2398 /* -eof- */