- Source in weitere Module fuer IRC-Befehle aufgesplitted.
[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.84 2002/03/03 17:15:11 alex Exp $
13  *
14  * irc.c: IRC-Befehle
15  *
16  * $Log: irc.c,v $
17  * Revision 1.84  2002/03/03 17:15:11  alex
18  * - Source in weitere Module fuer IRC-Befehle aufgesplitted.
19  *
20  * Revision 1.83  2002/02/28 00:48:26  alex
21  * - Forwarding von TOPIC an andere Server gefixed. Hoffentlich ;-)
22  *
23  * Revision 1.82  2002/02/27 23:26:36  alex
24  * - einige Funktionen in irc-xxx-Module ausgegliedert.
25  *
26  * Revision 1.81  2002/02/27 20:55:44  alex
27  * - Channel-Topics werden nun auch korrekt von anderen Server angenommen.
28  *
29  * Revision 1.80  2002/02/27 20:33:13  alex
30  * - Channel-Topics implementiert.
31  *
32  * Revision 1.79  2002/02/27 18:57:21  alex
33  * - PRIVMSG zeugt nun bei Texten an User an, wenn diese "away" sind.
34  *
35  * Revision 1.78  2002/02/27 18:23:45  alex
36  * - IRC-Befehl "AWAY" implementert.
37  *
38  * Revision 1.77  2002/02/27 17:05:41  alex
39  * - PRIVMSG beachtet nun die Channel-Modes "n" und "m".
40  *
41  * Revision 1.76  2002/02/27 16:04:14  alex
42  * - Bug bei belegtem Nickname bei User-Registrierung (NICK-Befehl) behoben.
43  *
44  * Revision 1.75  2002/02/27 15:23:27  alex
45  * - NAMES beachtet nun das "invisible" Flag ("i") von Usern.
46  *
47  * Revision 1.74  2002/02/27 03:44:53  alex
48  * - gerade eben in SQUIT eingefuehrten Bug behoben: entfernte Server werden nun
49  *   nur noch geloescht, die Verbindung, von der SQUIT kam, bleibt wieder offen.
50  *
51  * Revision 1.73  2002/02/27 03:08:05  alex
52  * - Log-Meldungen bei SQUIT erneut ueberarbeitet ...
53  *
54  * Revision 1.72  2002/02/27 02:26:58  alex
55  * - SQUIT wird auf jeden Fall geforwarded, zudem besseres Logging.
56  *
57  * Revision 1.71  2002/02/27 00:50:05  alex
58  * - einige unnoetige Client_NextHop()-Aufrufe entfernt.
59  * - NAMES korrigiert und komplett implementiert.
60  *
61  * Revision 1.70  2002/02/26 22:06:40  alex
62  * - Nick-Aenderungen werden nun wieder korrekt ins Logfile geschrieben.
63  */
64
65
66 #include <portab.h>
67 #include "global.h"
68
69 #include <imp.h>
70 #include <assert.h>
71 #include <errno.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75
76 #include "ngircd.h"
77 #include "channel.h"
78 #include "client.h"
79 #include "conf.h"
80 #include "conn.h"
81 #include "irc-write.h"
82 #include "log.h"
83 #include "messages.h"
84 #include "tool.h"
85
86 #include <exp.h>
87 #include "irc.h"
88
89
90 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
91 {
92         assert( Client != NULL );
93         assert( Req != NULL );
94
95         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
96
97         /* Falsche Anzahl Parameter? */
98         if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
99
100         return IRC_Show_MOTD( Client );
101 } /* IRC_MOTD */
102
103
104 GLOBAL BOOLEAN IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
105 {
106         BOOLEAN is_member, has_voice, is_op, ok;
107         CLIENT *cl, *from;
108         CHANNEL *chan;
109         
110         assert( Client != NULL );
111         assert( Req != NULL );
112
113         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
114
115         /* Falsche Anzahl Parameter? */
116         if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
117         if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
118         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
119
120         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
121         else from = Client;
122         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
123
124         cl = Client_Search( Req->argv[0] );
125         if( cl )
126         {
127                 /* Okay, Ziel ist ein User */
128                 if(( Client_Type( Client ) != CLIENT_SERVER ) && ( strchr( Client_Modes( cl ), 'a' )))
129                 {
130                         /* Ziel-User ist AWAY: Meldung verschicken */
131                         if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( cl ), Client_Away( cl ))) return DISCONNECTED;
132                 }
133
134                 /* Text senden */
135                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
136                 return IRC_WriteStrClientPrefix( cl, from, "PRIVMSG %s :%s", Client_ID( cl ), Req->argv[1] );
137         }
138
139         chan = Channel_Search( Req->argv[0] );
140         if( chan )
141         {
142                 /* Okay, Ziel ist ein Channel */
143                 is_member = has_voice = is_op = FALSE;
144                 if( Channel_IsMemberOf( chan, from ))
145                 {
146                         is_member = TRUE;
147                         if( strchr( Channel_UserModes( chan, from ), 'v' )) has_voice = TRUE;
148                         if( strchr( Channel_UserModes( chan, from ), 'o' )) is_op = TRUE;
149                 }
150                 
151                 /* pruefen, ob Client in Channel schreiben darf */
152                 ok = TRUE;
153                 if( strchr( Channel_Modes( chan ), 'n' ) && ( ! is_member )) ok = FALSE;
154                 if( strchr( Channel_Modes( chan ), 'm' ) && ( ! is_op ) && ( ! has_voice )) ok = FALSE;
155
156                 if( ! ok ) return IRC_WriteStrClient( from, ERR_CANNOTSENDTOCHAN_MSG, Client_ID( from ), Req->argv[0] );
157
158                 /* Text senden */
159                 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
160                 return IRC_WriteStrChannelPrefix( Client, chan, from, TRUE, "PRIVMSG %s :%s", Req->argv[0], Req->argv[1] );
161         }
162
163         return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
164 } /* IRC_PRIVMSG */
165
166
167 GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
168 {
169         CLIENT *to, *from;
170
171         assert( Client != NULL );
172         assert( Req != NULL );
173
174         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
175
176         /* Falsche Anzahl Parameter? */
177         if( Req->argc != 2 ) return CONNECTED;
178
179         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
180         else from = Client;
181         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
182
183         to = Client_Search( Req->argv[0] );
184         if( to )
185         {
186                 /* Okay, Ziel ist ein User */
187                 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
188         }
189         else return CONNECTED;
190 } /* IRC_NOTICE */
191
192
193 GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req )
194 {
195         CHAR rpl[COMMAND_LEN], *ptr;
196         CLIENT *target, *from, *c;
197         CHANNEL *chan;
198         
199         assert( Client != NULL );
200         assert( Req != NULL );
201
202         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
203
204         /* Falsche Anzahl Parameter? */
205         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
206
207         /* From aus Prefix ermitteln */
208         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
209         else from = Client;
210         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
211         
212         if( Req->argc == 2 )
213         {
214                 /* an anderen Server forwarden */
215                 target = Client_GetFromID( Req->argv[1] );
216                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
217
218                 if( target != Client_ThisServer( ))
219                 {
220                         /* Ok, anderer Server ist das Ziel: forwarden */
221                         return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
222                 }
223         }
224
225         if( Req->argc > 0 )
226         {
227                 /* bestimmte Channels durchgehen */
228                 ptr = strtok( Req->argv[0], "," );
229                 while( ptr )
230                 {
231                         chan = Channel_Search( ptr );
232                         if( chan )
233                         {
234                                 /* Namen ausgeben */
235                                 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
236                         }
237                         if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
238                         
239                         /* naechsten Namen ermitteln */
240                         ptr = strtok( NULL, "," );
241                 }
242                 return CONNECTED;
243         }
244         
245         /* alle Channels durchgehen */
246         chan = Channel_First( );
247         while( chan )
248         {
249                 /* Namen ausgeben */
250                 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
251
252                 /* naechster Channel */
253                 chan = Channel_Next( chan );
254         }
255
256         /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
257         c = Client_First( );
258         sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
259         while( c )
260         {
261                 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
262                 {
263                         /* Okay, das ist ein User: anhaengen */
264                         if( rpl[strlen( rpl ) - 1] != ':' ) strcat( rpl, " " );
265                         strcat( rpl, Client_ID( c ));
266
267                         if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
268                         {
269                                 /* Zeile wird zu lang: senden! */
270                                 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
271                                 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
272                         }
273                 }
274
275                 /* naechster Client */
276                 c = Client_Next( c );
277         }
278         if( rpl[strlen( rpl ) - 1] != ':')
279         {
280                 /* es wurden User gefunden */
281                 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
282         }
283         
284         return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
285 } /* IRC_NAMES */
286
287
288 GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
289 {
290         CHAR rpl[COMMAND_LEN];
291         CLIENT *c;
292         CHAR *ptr;
293         INT i;
294         
295         assert( Client != NULL );
296         assert( Req != NULL );
297
298         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
299
300         /* Falsche Anzahl Parameter? */
301         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
302
303         strcpy( rpl, RPL_ISON_MSG );
304         for( i = 0; i < Req->argc; i++ )
305         {
306                 ptr = strtok( Req->argv[i], " " );
307                 while( ptr )
308                 {
309                         ngt_TrimStr( ptr );
310                         c = Client_GetFromID( ptr );
311                         if( c && ( Client_Type( c ) == CLIENT_USER ))
312                         {
313                                 /* Dieser Nick ist "online" */
314                                 strcat( rpl, ptr );
315                                 strcat( rpl, " " );
316                         }
317                         ptr = strtok( NULL, " " );
318                 }
319         }
320         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
321
322         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
323 } /* IRC_ISON */
324
325
326 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
327 {
328         CLIENT *from, *target, *c;
329         CHAR str[LINE_LEN + 1], *ptr = NULL;
330         CL2CHAN *cl2chan;
331         CHANNEL *chan;
332         
333         assert( Client != NULL );
334         assert( Req != NULL );
335
336         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
337
338         /* Falsche Anzahl Parameter? */
339         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
340
341         /* Client suchen */
342         c = Client_GetFromID( Req->argv[Req->argc - 1] );
343         if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
344
345         /* Empfaenger des WHOIS suchen */
346         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
347         else from = Client;
348         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
349         
350         /* Forwarden an anderen Server? */
351         if( Req->argc > 1 )
352         {
353                 /* angegebenen Ziel-Server suchen */
354                 target = Client_GetFromID( Req->argv[1] );
355                 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
356                 ptr = Req->argv[1];
357         }
358         else target = Client_ThisServer( );
359
360         assert( target != NULL );
361         
362         if(( Client_NextHop( target ) != Client_ThisServer( )) && ( Client_Type( Client_NextHop( target )) == CLIENT_SERVER )) return IRC_WriteStrClientPrefix( target, from, "WHOIS %s :%s", Req->argv[0], ptr );
363         
364         /* Nick, User und Name */
365         if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
366
367         /* Server */
368         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;
369
370         /* Channels */
371         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
372         cl2chan = Channel_FirstChannelOf( c );
373         while( cl2chan )
374         {
375                 chan = Channel_GetChannel( cl2chan );
376                 assert( chan != NULL );
377                 
378                 /* Channel-Name anhaengen */
379                 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
380                 if( strchr( Channel_UserModes( chan, c ), 'v' )) strcat( str, "+" );
381                 if( strchr( Channel_UserModes( chan, c ), 'o' )) strcat( str, "@" );
382                 strcat( str, Channel_Name( chan ));
383
384                 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
385                 {
386                         /* Zeile wird zu lang: senden! */
387                         if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
388                         sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
389                 }
390
391                 /* naechstes Mitglied suchen */
392                 cl2chan = Channel_NextChannelOf( c, cl2chan );
393         }
394         if( str[strlen( str ) - 1] != ':')
395         {
396                 /* Es sind noch Daten da, die gesendet werden muessen */
397                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
398         }
399         
400         /* IRC-Operator? */
401         if( Client_HasMode( c, 'o' ))
402         {
403                 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
404         }
405
406         /* Idle (nur lokale Clients) */
407         if( Client_Conn( c ) > NONE )
408         {
409                 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
410         }
411
412         /* Away? */
413         if( Client_HasMode( c, 'a' ))
414         {
415                 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
416         }
417
418         /* End of Whois */
419         return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
420 } /* IRC_WHOIS */
421
422
423 GLOBAL BOOLEAN IRC_WHO( CLIENT *Client, REQUEST *Req )
424 {
425         assert( Client != NULL );
426         assert( Req != NULL );
427
428         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
429
430         /* Falsche Anzahl Parameter? */
431         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
432         
433         return CONNECTED;
434 } /* IRC_WHO */
435
436
437 GLOBAL BOOLEAN IRC_USERHOST( CLIENT *Client, REQUEST *Req )
438 {
439         CHAR rpl[COMMAND_LEN];
440         CLIENT *c;
441         INT max, i;
442
443         assert( Client != NULL );
444         assert( Req != NULL );
445
446         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
447
448         /* Falsche Anzahl Parameter? */
449         if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
450
451         if( Req->argc > 5 ) max = 5;
452         else max = Req->argc;
453         
454         strcpy( rpl, RPL_USERHOST_MSG );
455         for( i = 0; i < max; i++ )
456         {
457                 c = Client_GetFromID( Req->argv[i] );
458                 if( c && ( Client_Type( c ) == CLIENT_USER ))
459                 {
460                         /* Dieser Nick ist "online" */
461                         strcat( rpl, Client_ID( c ));
462                         if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
463                         strcat( rpl, "=" );
464                         if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
465                         else strcat( rpl, "+" );
466                         strcat( rpl, Client_User( c ));
467                         strcat( rpl, "@" );
468                         strcat( rpl, Client_Hostname( c ));
469                         strcat( rpl, " " );
470                 }
471         }
472         if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
473
474         return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
475 } /* IRC_USERHOST */
476
477
478 GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req )
479 {
480         assert( Client != NULL );
481         assert( Req != NULL );
482
483         if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
484         else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
485
486         return CONNECTED;
487 } /* IRC_ERROR */
488
489
490 GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req )
491 {
492         CLIENT *target, *from;
493         
494         assert( Client != NULL );
495         assert( Req != NULL );
496
497         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
498
499         /* Falsche Anzahl Parameter? */
500         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
501
502         /* Absender ermitteln */
503         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
504         else from = Client;
505         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
506
507         /* An anderen Server forwarden? */
508         if( Req->argc == 2 )
509         {
510                 target = Client_GetFromID( Req->argv[1] );
511                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
512                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
513         }
514
515         /* Wer ist der Absender? */
516         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
517         else target = Client;
518         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
519         
520         IRC_Send_LUSERS( target );
521
522         return CONNECTED;
523 } /* IRC_LUSERS */
524
525
526 GLOBAL BOOLEAN IRC_LINKS( CLIENT *Client, REQUEST *Req )
527 {
528         CLIENT *target, *from, *c;
529         CHAR *mask;
530         
531         assert( Client != NULL );
532         assert( Req != NULL );
533
534         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
535
536         /* Falsche Anzahl Parameter? */
537         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
538
539         /* Server-Mask ermitteln */
540         if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
541         else mask = "*";
542
543         /* Absender ermitteln */
544         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
545         else from = Client;
546         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
547         
548         /* An anderen Server forwarden? */
549         if( Req->argc == 2 )
550         {
551                 target = Client_GetFromID( Req->argv[0] );
552                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
553                 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
554         }
555
556         /* Wer ist der Absender? */
557         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
558         else target = Client;
559         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
560         
561         c = Client_First( );
562         while( c )
563         {
564                 if( Client_Type( c ) == CLIENT_SERVER )
565                 {
566                         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;
567                 }
568                 c = Client_Next( c );
569         }
570         
571         return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
572 } /* IRC_LINKS */
573
574
575 GLOBAL BOOLEAN IRC_VERSION( CLIENT *Client, REQUEST *Req )
576 {
577         CLIENT *target, *prefix;
578         
579         assert( Client != NULL );
580         assert( Req != NULL );
581
582         /* Falsche Anzahl Parameter? */
583         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
584
585         /* Ziel suchen */
586         if( Req->argc == 1 ) target = Client_GetFromID( Req->argv[0] );
587         else target = Client_ThisServer( );
588
589         /* Prefix ermitteln */
590         if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_GetFromID( Req->prefix );
591         else prefix = Client;
592         if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
593         
594         /* An anderen Server weiterleiten? */
595         if( target != Client_ThisServer( ))
596         {
597                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
598
599                 /* forwarden */
600                 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
601                 return CONNECTED;
602         }
603
604         /* mit Versionsinfo antworten */
605         return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition( ));
606 } /* IRC_VERSION */
607
608
609 GLOBAL BOOLEAN IRC_KILL( CLIENT *Client, REQUEST *Req )
610 {
611         CLIENT *prefix, *c;
612         
613         assert( Client != NULL );
614         assert( Req != NULL );
615
616         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
617
618         /* Falsche Anzahl Parameter? */
619         if(( Req->argc != 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
620
621         prefix = Client_GetFromID( Req->prefix );
622         if( ! prefix )
623         {
624                 Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", Req->prefix );
625                 prefix = Client_ThisServer( );
626         }
627         
628         Log( LOG_NOTICE, "Got KILL command from \"%s\" for \"%s\": %s", Client_Mask( prefix ), Req->argv[0], Req->argv[1] );
629         
630         /* andere Server benachrichtigen */
631         IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", Req->argv[0], Req->argv[1] );
632
633         /* haben wir selber einen solchen Client? */
634         c = Client_GetFromID( Req->argv[0] );
635         if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Req->argv[1], TRUE );
636         
637         return CONNECTED;
638 } /* IRC_KILL */
639
640
641 GLOBAL BOOLEAN IRC_Show_MOTD( CLIENT *Client )
642 {
643         BOOLEAN ok;
644         CHAR line[127];
645         FILE *fd;
646         
647         assert( Client != NULL );
648
649         fd = fopen( Conf_MotdFile, "r" );
650         if( ! fd )
651         {
652                 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
653                 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
654         }
655         
656         IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
657         while( TRUE )
658         {
659                 if( ! fgets( line, 126, fd )) break;
660                 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
661                 if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
662                 {
663                         fclose( fd );
664                         return FALSE;
665                 }
666         }
667         ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
668
669         fclose( fd );
670         
671         return ok;
672 } /* IRC_Show_MOTD */
673
674
675 GLOBAL BOOLEAN IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
676 {
677         BOOLEAN is_visible, is_member;
678         CHAR str[LINE_LEN + 1];
679         CL2CHAN *cl2chan;
680         CLIENT *cl;
681         
682         assert( Client != NULL );
683         assert( Chan != NULL );
684
685         if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
686         else is_member = FALSE;
687                          
688         /* Alle Mitglieder suchen */
689         sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
690         cl2chan = Channel_FirstMember( Chan );
691         while( cl2chan )
692         {
693                 cl = Channel_GetClient( cl2chan );
694
695                 if( strchr( Client_Modes( cl ), 'i' )) is_visible = FALSE;
696                 else is_visible = TRUE;
697
698                 if( is_member || is_visible )
699                 {
700                         /* Nick anhaengen */
701                         if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
702                         if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" );
703                         if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" );
704                         strcat( str, Client_ID( cl ));
705         
706                         if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
707                         {
708                                 /* Zeile wird zu lang: senden! */
709                                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
710                                 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
711                         }
712                 }
713
714                 /* naechstes Mitglied suchen */
715                 cl2chan = Channel_NextMember( Chan, cl2chan );
716         }
717         if( str[strlen( str ) - 1] != ':')
718         {
719                 /* Es sind noch Daten da, die gesendet werden muessen */
720                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
721         }
722
723         return CONNECTED;
724 } /* IRC_Send_NAMES */
725
726
727 GLOBAL BOOLEAN IRC_Send_LUSERS( CLIENT *Client )
728 {
729         INT cnt;
730
731         assert( Client != NULL );
732
733         /* Users, Services und Serevr im Netz */
734         if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
735
736         /* IRC-Operatoren im Netz */
737         cnt = Client_OperCount( );
738         if( cnt > 0 )
739         {
740                 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
741         }
742
743         /* Unbekannt Verbindungen */
744         cnt = Client_UnknownCount( );
745         if( cnt > 0 )
746         {
747                 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
748         }
749
750         /* Channels im Netz */
751         if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
752
753         /* Channels im Netz */
754         if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
755         
756         return CONNECTED;
757 } /* IRC_Send_LUSERS */
758
759
760 /* -eof- */