2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
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.
12 * $Id: irc.c,v 1.85 2002/03/03 19:44:30 alex Exp $
17 * Revision 1.85 2002/03/03 19:44:30 alex
18 * - WHO implementiert (bisher ohne Unterstuetzung von Masks)
20 * Revision 1.84 2002/03/03 17:15:11 alex
21 * - Source in weitere Module fuer IRC-Befehle aufgesplitted.
23 * Revision 1.83 2002/02/28 00:48:26 alex
24 * - Forwarding von TOPIC an andere Server gefixed. Hoffentlich ;-)
26 * Revision 1.82 2002/02/27 23:26:36 alex
27 * - einige Funktionen in irc-xxx-Module ausgegliedert.
29 * Revision 1.81 2002/02/27 20:55:44 alex
30 * - Channel-Topics werden nun auch korrekt von anderen Server angenommen.
32 * Revision 1.80 2002/02/27 20:33:13 alex
33 * - Channel-Topics implementiert.
35 * Revision 1.79 2002/02/27 18:57:21 alex
36 * - PRIVMSG zeugt nun bei Texten an User an, wenn diese "away" sind.
38 * Revision 1.78 2002/02/27 18:23:45 alex
39 * - IRC-Befehl "AWAY" implementert.
41 * Revision 1.77 2002/02/27 17:05:41 alex
42 * - PRIVMSG beachtet nun die Channel-Modes "n" und "m".
44 * Revision 1.76 2002/02/27 16:04:14 alex
45 * - Bug bei belegtem Nickname bei User-Registrierung (NICK-Befehl) behoben.
47 * Revision 1.75 2002/02/27 15:23:27 alex
48 * - NAMES beachtet nun das "invisible" Flag ("i") von Usern.
50 * Revision 1.74 2002/02/27 03:44:53 alex
51 * - gerade eben in SQUIT eingefuehrten Bug behoben: entfernte Server werden nun
52 * nur noch geloescht, die Verbindung, von der SQUIT kam, bleibt wieder offen.
54 * Revision 1.73 2002/02/27 03:08:05 alex
55 * - Log-Meldungen bei SQUIT erneut ueberarbeitet ...
57 * Revision 1.72 2002/02/27 02:26:58 alex
58 * - SQUIT wird auf jeden Fall geforwarded, zudem besseres Logging.
60 * Revision 1.71 2002/02/27 00:50:05 alex
61 * - einige unnoetige Client_NextHop()-Aufrufe entfernt.
62 * - NAMES korrigiert und komplett implementiert.
64 * Revision 1.70 2002/02/26 22:06:40 alex
65 * - Nick-Aenderungen werden nun wieder korrekt ins Logfile geschrieben.
84 #include "irc-write.h"
93 GLOBAL BOOLEAN IRC_MOTD( CLIENT *Client, REQUEST *Req )
95 assert( Client != NULL );
96 assert( Req != NULL );
98 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
100 /* Falsche Anzahl Parameter? */
101 if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
103 return IRC_Show_MOTD( Client );
107 GLOBAL BOOLEAN IRC_PRIVMSG( CLIENT *Client, REQUEST *Req )
109 BOOLEAN is_member, has_voice, is_op, ok;
113 assert( Client != NULL );
114 assert( Req != NULL );
116 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
118 /* Falsche Anzahl Parameter? */
119 if( Req->argc == 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command );
120 if( Req->argc == 1 ) return IRC_WriteStrClient( Client, ERR_NOTEXTTOSEND_MSG, Client_ID( Client ));
121 if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
123 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
125 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
127 cl = Client_Search( Req->argv[0] );
130 /* Okay, Ziel ist ein User */
131 if(( Client_Type( Client ) != CLIENT_SERVER ) && ( strchr( Client_Modes( cl ), 'a' )))
133 /* Ziel-User ist AWAY: Meldung verschicken */
134 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( cl ), Client_Away( cl ))) return DISCONNECTED;
138 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
139 return IRC_WriteStrClientPrefix( cl, from, "PRIVMSG %s :%s", Client_ID( cl ), Req->argv[1] );
142 chan = Channel_Search( Req->argv[0] );
145 /* Okay, Ziel ist ein Channel */
146 is_member = has_voice = is_op = FALSE;
147 if( Channel_IsMemberOf( chan, from ))
150 if( strchr( Channel_UserModes( chan, from ), 'v' )) has_voice = TRUE;
151 if( strchr( Channel_UserModes( chan, from ), 'o' )) is_op = TRUE;
154 /* pruefen, ob Client in Channel schreiben darf */
156 if( strchr( Channel_Modes( chan ), 'n' ) && ( ! is_member )) ok = FALSE;
157 if( strchr( Channel_Modes( chan ), 'm' ) && ( ! is_op ) && ( ! has_voice )) ok = FALSE;
159 if( ! ok ) return IRC_WriteStrClient( from, ERR_CANNOTSENDTOCHAN_MSG, Client_ID( from ), Req->argv[0] );
162 if( Client_Conn( from ) > NONE ) Conn_UpdateIdle( Client_Conn( from ));
163 return IRC_WriteStrChannelPrefix( Client, chan, from, TRUE, "PRIVMSG %s :%s", Req->argv[0], Req->argv[1] );
166 return IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG, Client_ID( from ), Req->argv[0] );
170 GLOBAL BOOLEAN IRC_NOTICE( CLIENT *Client, REQUEST *Req )
174 assert( Client != NULL );
175 assert( Req != NULL );
177 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
179 /* Falsche Anzahl Parameter? */
180 if( Req->argc != 2 ) return CONNECTED;
182 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
184 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
186 to = Client_Search( Req->argv[0] );
189 /* Okay, Ziel ist ein User */
190 return IRC_WriteStrClientPrefix( to, from, "NOTICE %s :%s", Client_ID( to ), Req->argv[1] );
192 else return CONNECTED;
196 GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req )
198 CHAR rpl[COMMAND_LEN], *ptr;
199 CLIENT *target, *from, *c;
202 assert( Client != NULL );
203 assert( Req != NULL );
205 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
207 /* Falsche Anzahl Parameter? */
208 if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
210 /* From aus Prefix ermitteln */
211 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
213 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
217 /* an anderen Server forwarden */
218 target = Client_GetFromID( Req->argv[1] );
219 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
221 if( target != Client_ThisServer( ))
223 /* Ok, anderer Server ist das Ziel: forwarden */
224 return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
230 /* bestimmte Channels durchgehen */
231 ptr = strtok( Req->argv[0], "," );
234 chan = Channel_Search( ptr );
238 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
240 if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
242 /* naechsten Namen ermitteln */
243 ptr = strtok( NULL, "," );
248 /* alle Channels durchgehen */
249 chan = Channel_First( );
253 if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
255 /* naechster Channel */
256 chan = Channel_Next( chan );
259 /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
261 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
264 if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
266 /* Okay, das ist ein User: anhaengen */
267 if( rpl[strlen( rpl ) - 1] != ':' ) strcat( rpl, " " );
268 strcat( rpl, Client_ID( c ));
270 if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
272 /* Zeile wird zu lang: senden! */
273 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
274 sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
278 /* naechster Client */
279 c = Client_Next( c );
281 if( rpl[strlen( rpl ) - 1] != ':')
283 /* es wurden User gefunden */
284 if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED;
287 return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
291 GLOBAL BOOLEAN IRC_ISON( CLIENT *Client, REQUEST *Req )
293 CHAR rpl[COMMAND_LEN];
298 assert( Client != NULL );
299 assert( Req != NULL );
301 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
303 /* Falsche Anzahl Parameter? */
304 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
306 strcpy( rpl, RPL_ISON_MSG );
307 for( i = 0; i < Req->argc; i++ )
309 ptr = strtok( Req->argv[i], " " );
313 c = Client_GetFromID( ptr );
314 if( c && ( Client_Type( c ) == CLIENT_USER ))
316 /* Dieser Nick ist "online" */
320 ptr = strtok( NULL, " " );
323 if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
325 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
329 GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req )
331 CLIENT *from, *target, *c;
332 CHAR str[LINE_LEN + 1], *ptr = NULL;
336 assert( Client != NULL );
337 assert( Req != NULL );
339 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
341 /* Falsche Anzahl Parameter? */
342 if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
345 c = Client_GetFromID( Req->argv[Req->argc - 1] );
346 if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
348 /* Empfaenger des WHOIS suchen */
349 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
351 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
353 /* Forwarden an anderen Server? */
356 /* angegebenen Ziel-Server suchen */
357 target = Client_GetFromID( Req->argv[1] );
358 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
361 else target = Client_ThisServer( );
363 assert( target != NULL );
365 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 );
367 /* Nick, User und Name */
368 if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
371 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;
374 sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
375 cl2chan = Channel_FirstChannelOf( c );
378 chan = Channel_GetChannel( cl2chan );
379 assert( chan != NULL );
381 /* Channel-Name anhaengen */
382 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
383 if( strchr( Channel_UserModes( chan, c ), 'v' )) strcat( str, "+" );
384 if( strchr( Channel_UserModes( chan, c ), 'o' )) strcat( str, "@" );
385 strcat( str, Channel_Name( chan ));
387 if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
389 /* Zeile wird zu lang: senden! */
390 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
391 sprintf( str, RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
394 /* naechstes Mitglied suchen */
395 cl2chan = Channel_NextChannelOf( c, cl2chan );
397 if( str[strlen( str ) - 1] != ':')
399 /* Es sind noch Daten da, die gesendet werden muessen */
400 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
404 if( Client_HasMode( c, 'o' ))
406 if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
409 /* Idle (nur lokale Clients) */
410 if( Client_Conn( c ) > NONE )
412 if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
416 if( Client_HasMode( c, 'a' ))
418 if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
422 return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
426 GLOBAL BOOLEAN IRC_WHO( CLIENT *Client, REQUEST *Req )
428 BOOLEAN ok, only_ops;
434 assert( Client != NULL );
435 assert( Req != NULL );
437 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
439 /* Falsche Anzahl Parameter? */
440 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
447 /* Nur OPs anzeigen? */
448 if( strcmp( Req->argv[1], "o" ) == 0 ) only_ops = TRUE;
450 else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
456 /* wurde ein Channel oder Nick-Mask angegeben? */
457 chan = Channel_Search( Req->argv[0] );
462 /* User eines Channels ausgeben */
463 if( ! IRC_Send_WHO( Client, chan, only_ops )) return DISCONNECTED;
469 if(( Client_Type( c ) == CLIENT_USER ) && ( ! strchr( Client_Modes( c ), 'i' )))
472 if( Req->argc == 0 ) ok = TRUE;
475 if( strcasecmp( Req->argv[0], Client_ID( c )) == 0 ) ok = TRUE;
476 else if( strcmp( Req->argv[0], "0" ) == 0 ) ok = TRUE;
479 if( ok && (( ! only_ops ) || ( strchr( Client_Modes( c ), 'o' ))))
481 /* Flags zusammenbasteln */
482 strcpy( flags, "H" );
483 if( strchr( Client_Modes( c ), 'o' )) strcat( flags, "*" );
486 cl2chan = Channel_FirstChannelOf( c );
487 if( ! IRC_WriteStrClient( Client, RPL_WHOREPLY_MSG, Client_ID( Client ), chan ? Channel_Name( Channel_GetChannel( cl2chan )) : "*", Client_User( c ), Client_Hostname( c ), Client_ID( Client_Introducer( c )), Client_ID( c ), flags, Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
491 /* naechster Client */
492 c = Client_Next( c );
495 if( chan ) return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), Channel_Name( chan ));
496 else if( Req->argc == 0 ) return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), "*" );
497 else return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), Req->argv[0] );
501 GLOBAL BOOLEAN IRC_USERHOST( CLIENT *Client, REQUEST *Req )
503 CHAR rpl[COMMAND_LEN];
507 assert( Client != NULL );
508 assert( Req != NULL );
510 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
512 /* Falsche Anzahl Parameter? */
513 if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
515 if( Req->argc > 5 ) max = 5;
516 else max = Req->argc;
518 strcpy( rpl, RPL_USERHOST_MSG );
519 for( i = 0; i < max; i++ )
521 c = Client_GetFromID( Req->argv[i] );
522 if( c && ( Client_Type( c ) == CLIENT_USER ))
524 /* Dieser Nick ist "online" */
525 strcat( rpl, Client_ID( c ));
526 if( Client_HasMode( c, 'o' )) strcat( rpl, "*" );
528 if( Client_HasMode( c, 'a' )) strcat( rpl, "-" );
529 else strcat( rpl, "+" );
530 strcat( rpl, Client_User( c ));
532 strcat( rpl, Client_Hostname( c ));
536 if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0';
538 return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
542 GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req )
544 assert( Client != NULL );
545 assert( Req != NULL );
547 if( Req->argc < 1 ) Log( LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask( Client ));
548 else Log( LOG_NOTICE, "Got ERROR from \"%s\": %s!", Client_Mask( Client ), Req->argv[0] );
554 GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req )
556 CLIENT *target, *from;
558 assert( Client != NULL );
559 assert( Req != NULL );
561 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
563 /* Falsche Anzahl Parameter? */
564 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
566 /* Absender ermitteln */
567 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
569 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
571 /* An anderen Server forwarden? */
574 target = Client_GetFromID( Req->argv[1] );
575 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
576 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
579 /* Wer ist der Absender? */
580 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
581 else target = Client;
582 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
584 IRC_Send_LUSERS( target );
590 GLOBAL BOOLEAN IRC_LINKS( CLIENT *Client, REQUEST *Req )
592 CLIENT *target, *from, *c;
595 assert( Client != NULL );
596 assert( Req != NULL );
598 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
600 /* Falsche Anzahl Parameter? */
601 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
603 /* Server-Mask ermitteln */
604 if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
607 /* Absender ermitteln */
608 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
610 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
612 /* An anderen Server forwarden? */
615 target = Client_GetFromID( Req->argv[0] );
616 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
617 else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
620 /* Wer ist der Absender? */
621 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_GetFromID( Req->prefix );
622 else target = Client;
623 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
628 if( Client_Type( c ) == CLIENT_SERVER )
630 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;
632 c = Client_Next( c );
635 return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
639 GLOBAL BOOLEAN IRC_VERSION( CLIENT *Client, REQUEST *Req )
641 CLIENT *target, *prefix;
643 assert( Client != NULL );
644 assert( Req != NULL );
646 /* Falsche Anzahl Parameter? */
647 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
650 if( Req->argc == 1 ) target = Client_GetFromID( Req->argv[0] );
651 else target = Client_ThisServer( );
653 /* Prefix ermitteln */
654 if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_GetFromID( Req->prefix );
655 else prefix = Client;
656 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
658 /* An anderen Server weiterleiten? */
659 if( target != Client_ThisServer( ))
661 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
664 IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
668 /* mit Versionsinfo antworten */
669 return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition( ));
673 GLOBAL BOOLEAN IRC_KILL( CLIENT *Client, REQUEST *Req )
677 assert( Client != NULL );
678 assert( Req != NULL );
680 if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
682 /* Falsche Anzahl Parameter? */
683 if(( Req->argc != 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
685 prefix = Client_GetFromID( Req->prefix );
688 Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", Req->prefix );
689 prefix = Client_ThisServer( );
692 Log( LOG_NOTICE, "Got KILL command from \"%s\" for \"%s\": %s", Client_Mask( prefix ), Req->argv[0], Req->argv[1] );
694 /* andere Server benachrichtigen */
695 IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", Req->argv[0], Req->argv[1] );
697 /* haben wir selber einen solchen Client? */
698 c = Client_GetFromID( Req->argv[0] );
699 if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Req->argv[1], TRUE );
705 GLOBAL BOOLEAN IRC_Show_MOTD( CLIENT *Client )
711 assert( Client != NULL );
713 fd = fopen( Conf_MotdFile, "r" );
716 Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
717 return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
720 IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )));
723 if( ! fgets( line, 126, fd )) break;
724 if( line[strlen( line ) - 1] == '\n' ) line[strlen( line ) - 1] = '\0';
725 if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
731 ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
736 } /* IRC_Show_MOTD */
739 GLOBAL BOOLEAN IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
741 BOOLEAN is_visible, is_member;
742 CHAR str[LINE_LEN + 1];
746 assert( Client != NULL );
747 assert( Chan != NULL );
749 if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
750 else is_member = FALSE;
752 /* Alle Mitglieder suchen */
753 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
754 cl2chan = Channel_FirstMember( Chan );
757 cl = Channel_GetClient( cl2chan );
759 if( strchr( Client_Modes( cl ), 'i' )) is_visible = FALSE;
760 else is_visible = TRUE;
762 if( is_member || is_visible )
765 if( str[strlen( str ) - 1] != ':' ) strcat( str, " " );
766 if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" );
767 if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" );
768 strcat( str, Client_ID( cl ));
770 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
772 /* Zeile wird zu lang: senden! */
773 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
774 sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
778 /* naechstes Mitglied suchen */
779 cl2chan = Channel_NextMember( Chan, cl2chan );
781 if( str[strlen( str ) - 1] != ':')
783 /* Es sind noch Daten da, die gesendet werden muessen */
784 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
788 } /* IRC_Send_NAMES */
791 GLOBAL BOOLEAN IRC_Send_WHO( CLIENT *Client, CHANNEL *Chan, BOOLEAN OnlyOps )
793 BOOLEAN is_visible, is_member;
798 assert( Client != NULL );
799 assert( Chan != NULL );
801 if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE;
802 else is_member = FALSE;
804 /* Alle Mitglieder suchen */
805 cl2chan = Channel_FirstMember( Chan );
808 c = Channel_GetClient( cl2chan );
810 if( strchr( Client_Modes( c ), 'i' )) is_visible = FALSE;
811 else is_visible = TRUE;
813 if( is_member || is_visible )
815 /* Flags zusammenbasteln */
816 strcpy( flags, "H" );
817 if( strchr( Client_Modes( c ), 'o' )) strcat( flags, "*" );
818 if( strchr( Channel_UserModes( Chan, c ), 'v' )) strcat( flags, "+" );
819 if( strchr( Channel_UserModes( Chan, c ), 'o' )) strcat( flags, "@" );
822 if(( ! OnlyOps ) || ( strchr( Client_Modes( c ), 'o' )))
824 if( ! IRC_WriteStrClient( Client, RPL_WHOREPLY_MSG, Client_ID( Client ), Channel_Name( Chan ), Client_User( c ), Client_Hostname( c ), Client_ID( Client_Introducer( c )), Client_ID( c ), flags, Client_Hops( c ), Client_Info( c ))) return DISCONNECTED;
828 /* naechstes Mitglied suchen */
829 cl2chan = Channel_NextMember( Chan, cl2chan );
835 GLOBAL BOOLEAN IRC_Send_LUSERS( CLIENT *Client )
839 assert( Client != NULL );
841 /* Users, Services und Serevr im Netz */
842 if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
844 /* IRC-Operatoren im Netz */
845 cnt = Client_OperCount( );
848 if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
851 /* Unbekannt Verbindungen */
852 cnt = Client_UnknownCount( );
855 if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
858 /* Channels im Netz */
859 if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
861 /* Channels im Netz */
862 if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
865 } /* IRC_Send_LUSERS */