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