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