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