X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc.c;h=2a8a6149f5d126eb416c4b8713a1bf8e894a8981;hp=1892951099090aa03faf58d59a582167b5e91da1;hb=93a52dfab86da096e629a8e2f86229245378ac68;hpb=84a2f8ab268412ecacca20aacc8b1727c81a6d07 diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 18929510..2a8a6149 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -9,11 +9,66 @@ * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. * - * $Id: irc.c,v 1.53 2002/02/11 16:06:21 alex Exp $ + * $Id: irc.c,v 1.70 2002/02/26 22:06:40 alex Exp $ * * irc.c: IRC-Befehle * * $Log: irc.c,v $ + * Revision 1.70 2002/02/26 22:06:40 alex + * - Nick-Aenderungen werden nun wieder korrekt ins Logfile geschrieben. + * + * Revision 1.69 2002/02/26 20:52:40 alex + * - VERSION wurde falsch weitergeleitet und beantwortet (Prefix nicht beachtet) + * + * Revision 1.68 2002/02/25 17:46:27 alex + * - an User wird nun immer ein "komplettes" Prefix verschickt. + * + * Revision 1.67 2002/02/25 13:21:25 alex + * - WHOIS wird nicht mehr automatisch an den "Original-Server" weiterge- + * leitet: war eh nicht RFC-konform und machte Probleme mit Clients. + * + * Revision 1.66 2002/02/23 21:39:48 alex + * - IRC-Befehl KILL sowie Kills bei Nick Collsisions implementiert. + * + * Revision 1.65 2002/02/23 00:03:54 alex + * - Ergebnistyp von Conn_GetIdle() und Conn_LastPing() auf "time_t" geaendert. + * + * Revision 1.64 2002/02/19 20:06:45 alex + * - User-Registrierung wird nicht mehr als Nick-Aenderung protokolliert, + * - VERSION liefert nun doch wieder den Debug-Status im Reply. + * + * Revision 1.63 2002/02/19 02:21:17 alex + * - der Debug-Level wird bei VERSION nicht mehr geliefert. Grund: a) absolut + * unnoetig und b) Compiler-Fehler, wenn ohne Debug-Code configure'd ;-)) + * + * Revision 1.62 2002/02/17 23:38:58 alex + * - neuer IRC-Befehl VERSION implementiert: IRC_VERSION(). + * + * Revision 1.61 2002/02/17 19:03:12 alex + * - NICK-Aenderungen wurden dem User selber mit dem falschen Prefix geliefert. + * + * Revision 1.60 2002/02/17 17:43:14 alex + * - Fehlerhafte Modes werden nun ausfuehrlicher an den Client gemeldet. + * + * Revision 1.59 2002/02/17 17:30:21 alex + * - NICK-Aenderungen werden an alle Server und betroffene Clients gemeldet. + * - Neue Funktion IRC_WriteStrRelatedPrefix(). + * + * Revision 1.58 2002/02/17 17:18:59 alex + * - NICK korrigiert. + * + * Revision 1.57 2002/02/13 23:05:29 alex + * - Nach Connect eines Users werden LUSERS-Informationen angezeigt. + * + * Revision 1.56 2002/02/13 17:52:27 alex + * - es werden nun Channel- und User-Modes von Usern angenommen. + * + * Revision 1.55 2002/02/12 14:40:37 alex + * - via NJOIN gemeldete Benutzer wurden nicht in Channels bekannt gemacht. + * + * Revision 1.54 2002/02/11 23:33:35 alex + * - weitere Anpassungen an Channel-Modes und Channel-User-Modes. + * * Revision 1.53 2002/02/11 16:06:21 alex * - Die Quelle von MODE-Aenderungen wird nun korrekt weitergegeben. * @@ -240,9 +295,12 @@ LOCAL BOOLEAN Hello_User( CLIENT *Client ); LOCAL BOOLEAN Show_MOTD( CLIENT *Client ); -LOCAL VOID Kill_Nick( CHAR *Nick ); +LOCAL VOID Kill_Nick( CHAR *Nick, CHAR *Reason ); LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan ); +LOCAL BOOLEAN Send_LUSERS( CLIENT *Client ); + +CHAR *Get_Prefix( CLIENT *Target, CLIENT *Client ); GLOBAL VOID IRC_Init( VOID ) @@ -290,7 +348,7 @@ GLOBAL BOOLEAN IRC_WriteStrClientPrefix( CLIENT *Client, CLIENT *Prefix, CHAR *F vsnprintf( buffer, 1000, Format, ap ); va_end( ap ); - return Conn_WriteStr( Client_Conn( Client_NextHop( Client )), ":%s %s", Client_ID( Prefix ), buffer ); + return Conn_WriteStr( Client_Conn( Client_NextHop( Client )), ":%s %s", Get_Prefix( Client_NextHop( Client ), Prefix ), buffer ); } /* IRC_WriteStrClientPrefix */ @@ -312,11 +370,11 @@ GLOBAL BOOLEAN IRC_WriteStrChannel( CLIENT *Client, CHANNEL *Chan, BOOLEAN Remot GLOBAL BOOLEAN IRC_WriteStrChannelPrefix( CLIENT *Client, CHANNEL *Chan, CLIENT *Prefix, BOOLEAN Remote, CHAR *Format, ... ) { + BOOLEAN sock[MAX_CONNECTIONS], is_server[MAX_CONNECTIONS], ok = CONNECTED; CHAR buffer[1000]; - BOOLEAN sock[MAX_CONNECTIONS], ok = CONNECTED, i; CL2CHAN *cl2chan; CLIENT *c; - INT s; + INT s, i; va_list ap; assert( Client != NULL ); @@ -350,6 +408,8 @@ GLOBAL BOOLEAN IRC_WriteStrChannelPrefix( CLIENT *Client, CHANNEL *Chan, CLIENT assert( s >= 0 ); assert( s < MAX_CONNECTIONS ); sock[s] = TRUE; + if( Client_Type( c ) == CLIENT_SERVER ) is_server[s] = TRUE; + else is_server[s] = FALSE; } cl2chan = Channel_NextMember( Chan, cl2chan ); } @@ -359,7 +419,8 @@ GLOBAL BOOLEAN IRC_WriteStrChannelPrefix( CLIENT *Client, CHANNEL *Chan, CLIENT { if( sock[i] ) { - ok = Conn_WriteStr( i, ":%s %s", Client_ID( Prefix ), buffer ); + if( is_server[i] ) ok = Conn_WriteStr( i, ":%s %s", Client_ID( Prefix ), buffer ); + else ok = Conn_WriteStr( i, ":%s %s", Client_Mask( Prefix ), buffer ); if( ! ok ) break; } } @@ -409,6 +470,77 @@ GLOBAL VOID IRC_WriteStrServersPrefix( CLIENT *ExceptOf, CLIENT *Prefix, CHAR *F } /* IRC_WriteStrServersPrefix */ +GLOBAL BOOLEAN IRC_WriteStrRelatedPrefix( CLIENT *Client, CLIENT *Prefix, BOOLEAN Remote, CHAR *Format, ... ) +{ + BOOLEAN sock[MAX_CONNECTIONS], is_server[MAX_CONNECTIONS], ok = CONNECTED; + CL2CHAN *chan_cl2chan, *cl2chan; + CHAR buffer[1000]; + CHANNEL *chan; + va_list ap; + CLIENT *c; + INT i, s; + + assert( Client != NULL ); + assert( Prefix != NULL ); + assert( Format != NULL ); + + va_start( ap, Format ); + vsnprintf( buffer, 1000, Format, ap ); + va_end( ap ); + + /* initialisieren */ + for( i = 0; i < MAX_CONNECTIONS; i++ ) sock[i] = FALSE; + + /* An alle Clients, die in einem Channel mit dem "Ausloeser" sind, + * den Text schicken. An Remote-Server aber jeweils nur einmal. */ + chan_cl2chan = Channel_FirstChannelOf( Client ); + while( chan_cl2chan ) + { + /* Channel des Users durchsuchen */ + chan = Channel_GetChannel( chan_cl2chan ); + cl2chan = Channel_FirstMember( chan ); + while( cl2chan ) + { + c = Channel_GetClient( cl2chan ); + if( ! Remote ) + { + if( Client_Conn( c ) <= NONE ) c = NULL; + else if( Client_Type( c ) == CLIENT_SERVER ) c = NULL; + } + if( c ) c = Client_NextHop( c ); + + if( c && ( c != Client )) + { + /* Ok, anderer Client */ + s = Client_Conn( c ); + assert( s >= 0 ); + assert( s < MAX_CONNECTIONS ); + sock[s] = TRUE; + if( Client_Type( c ) == CLIENT_SERVER ) is_server[s] = TRUE; + else is_server[s] = FALSE; + } + cl2chan = Channel_NextMember( chan, cl2chan ); + } + + /* naechsten Channel */ + chan_cl2chan = Channel_NextChannelOf( Client, chan_cl2chan ); + } + + /* Senden ... */ + for( i = 0; i < MAX_CONNECTIONS; i++ ) + { + if( sock[i] ) + { + if( is_server[i] ) ok = Conn_WriteStr( i, ":%s %s", Client_ID( Prefix ), buffer ); + else ok = Conn_WriteStr( i, ":%s %s", Client_Mask( Prefix ), buffer ); + if( ! ok ) break; + } + } + return ok; +} /* IRC_WriteStrRelatedPrefix */ + + + GLOBAL BOOLEAN IRC_PASS( CLIENT *Client, REQUEST *Req ) { assert( Client != NULL ); @@ -538,7 +670,7 @@ GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req ) if( Client_Conn( c ) > NONE ) { /* Dem gefundenen Server gleich den neuen - * Server bekannt machen */ + * Server bekannt machen */ if( ! IRC_WriteStrClient( c, "SERVER %s %d %d :%s", Client_ID( Client ), Client_Hops( Client ) + 1, Client_MyToken( Client ), Client_Info( Client ))) return DISCONNECTED; } @@ -652,8 +784,8 @@ GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req ) GLOBAL BOOLEAN IRC_NJOIN( CLIENT *Client, REQUEST *Req ) { + CHAR *channame, *ptr, modes[8]; BOOLEAN is_op, is_voiced; - CHAR *channame, *ptr; CHANNEL *chan; CLIENT *c; @@ -688,6 +820,17 @@ GLOBAL BOOLEAN IRC_NJOIN( CLIENT *Client, REQUEST *Req ) if( is_op ) Channel_UserModeAdd( chan, c, 'o' ); if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' ); + + /* im Channel bekannt machen */ + IRC_WriteStrChannelPrefix( Client, chan, c, FALSE, "JOIN :%s", channame ); + + /* Channel-User-Modes setzen */ + strcpy( modes, Channel_UserModes( chan, c )); + if( modes[0] ) + { + /* Modes im Channel bekannt machen */ + IRC_WriteStrChannelPrefix( Client, chan, Client, FALSE, "MODE %s +%s %s", channame, modes, Client_ID( c )); + } } else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame ); @@ -735,10 +878,10 @@ GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req ) target = Client; } +#ifndef STRICT_RFC /* Wenn der Client zu seinem eigenen Nick wechseln will, so machen * wir nichts. So macht es das Original und mind. Snak hat probleme, * wenn wir es nicht so machen. Ob es so okay ist? Hm ... */ -#ifndef STRICT_RFC if( strcmp( Client_ID( target ), Req->argv[0] ) == 0 ) return CONNECTED; #endif @@ -750,22 +893,11 @@ GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req ) if( ! Client_CheckNick( target, Req->argv[0] )) return CONNECTED; } - if( Client_Type( Client ) == CLIENT_USER ) - { - /* Nick-Aenderung: allen mitteilen! */ - Log( LOG_INFO, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] ); - IRC_WriteStrClient( Client, "NICK :%s", Req->argv[0] ); - IRC_WriteStrServersPrefix( NULL, Client, "NICK :%s", Req->argv[0] ); - } - else if( Client_Type( Client ) == CLIENT_SERVER ) - { - /* Nick-Aenderung: allen mitteilen! */ - Log( LOG_DEBUG, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] ); - IRC_WriteStrServersPrefix( Client, target, "NICK :%s", Req->argv[0] ); - } - - /* Client-Nick registrieren */ - Client_SetID( target, Req->argv[0] ); + /* Nick-Aenderung: allen mitteilen! */ + + if( Client_Type( Client ) == CLIENT_USER ) IRC_WriteStrClientPrefix( Client, Client, "NICK :%s", Req->argv[0] ); + IRC_WriteStrServersPrefix( Client, target, "NICK :%s", Req->argv[0] ); + IRC_WriteStrRelatedPrefix( target, target, FALSE, "NICK :%s", Req->argv[0] ); if(( Client_Type( target ) != CLIENT_USER ) && ( Client_Type( target ) != CLIENT_SERVER )) { @@ -774,6 +906,11 @@ GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req ) if( Client_Type( Client ) == CLIENT_GOTUSER ) return Hello_User( Client ); else Client_SetType( Client, CLIENT_GOTNICK ); } + else Log( LOG_INFO, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] ); + + /* Client-Nick registrieren */ + Client_SetID( target, Req->argv[0] ); + return CONNECTED; } else if( Client_Type( Client ) == CLIENT_SERVER ) @@ -791,7 +928,7 @@ GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req ) * sowohl der neue, als auch der alte Client muessen nun * disconnectiert werden. */ Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] ); - Kill_Nick( Req->argv[0] ); + Kill_Nick( Req->argv[0], "Nick collision" ); return CONNECTED; } @@ -800,7 +937,7 @@ GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req ) if( ! intr_c ) { Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] ); - Kill_Nick( Req->argv[0] ); + Kill_Nick( Req->argv[0], "Unknown server" ); return CONNECTED; } @@ -812,7 +949,7 @@ GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req ) * Der Client muss disconnectiert werden, damit der Netz- * status konsistent bleibt. */ Log( LOG_ALERT, "Can't create client structure! (on connection %d)", Client_Conn( Client )); - Kill_Nick( Req->argv[0] ); + Kill_Nick( Req->argv[0], "Server error" ); return CONNECTED; } @@ -1005,7 +1142,7 @@ GLOBAL BOOLEAN IRC_PONG( CLIENT *Client, REQUEST *Req ) /* Der Connection-Timestamp wurde schon beim Lesen aus dem Socket * aktualisiert, daher muss das hier nicht mehr gemacht werden. */ - 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 ))); + if( Client_Conn( Client ) > NONE ) Log( LOG_DEBUG, "Connection %d: received PONG. Lag: %ld seconds.", Client_Conn( Client ), time( NULL ) - Conn_LastPing( Client_Conn( Client ))); else Log( LOG_DEBUG, "Connection %d: received PONG.", Client_Conn( Client )); return CONNECTED; @@ -1215,22 +1352,79 @@ GLOBAL BOOLEAN IRC_MODE( CLIENT *Client, REQUEST *Req ) else ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client )); break; default: - ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client )); + Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Client )); + ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr ); x[0] = '\0'; } } if( chan ) { + /* Ist der User ein Channel Operator? */ + if( ! strchr( Channel_UserModes( chan, Client ), 'o' )) + { + Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan )); + ok = IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan )); + break; + } + /* Channel-Modes oder Channel-User-Modes */ if( chan_cl ) { /* Channel-User-Modes */ - Log( LOG_DEBUG, "Channel-User-Mode '%c' not supported ...", *mode_ptr ); + switch( *mode_ptr ) + { + case 'o': + /* Channel Operator */ + x[0] = 'o'; + break; + case 'v': + /* Voice */ + x[0] = 'v'; + break; + default: + Log( LOG_DEBUG, "Unknown channel-user-mode \"%c%c\" from \"%s\" on \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Client_ID( chan_cl ), Channel_Name( chan )); + ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr ); + x[0] = '\0'; + } } else { /* Channel-Modes */ - Log( LOG_DEBUG, "Channel-Mode '%c' not supported ...", *mode_ptr ); + switch( *mode_ptr ) + { + case 'a': + /* Anonymous */ + x[0] = 'a'; + break; + case 'm': + /* Moderated */ + x[0] = 'm'; + break; + case 'n': + /* kein Schreiben in den Channel von aussen */ + x[0] = 'n'; + break; + case 'p': + /* Private */ + x[0] = 'p'; + break; + case 'q': + /* Quite */ + x[0] = 'q'; + break; + case 's': + /* Secret */ + x[0] = 's'; + break; + case 't': + /* Topic Lock */ + x[0] = 't'; + break; + default: + Log( LOG_DEBUG, "Unknown channel-mode \"%c%c\" from \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Channel_Name( chan )); + ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr ); + x[0] = '\0'; + } } } } @@ -1549,17 +1743,11 @@ GLOBAL BOOLEAN IRC_WHOIS( CLIENT *Client, REQUEST *Req ) if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] ); ptr = Req->argv[1]; } -#ifndef STRICT_RFC - else if( Client_Conn( c ) == NONE ) - { - /* Client ist nicht von uns. Ziel-Server suchen */ - target = c; - ptr = Req->argv[0]; - } -#endif - else target = NULL; + else target = Client_ThisServer( ); + + assert( target != NULL ); - 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 ); + 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 ); /* Nick, User und Name */ if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED; @@ -1670,7 +1858,6 @@ GLOBAL BOOLEAN IRC_ERROR( CLIENT *Client, REQUEST *Req ) GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req ) { CLIENT *target, *from; - INT cnt; assert( Client != NULL ); assert( Req != NULL ); @@ -1698,28 +1885,7 @@ GLOBAL BOOLEAN IRC_LUSERS( CLIENT *Client, REQUEST *Req ) else target = Client; if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix ); - /* Users, Services und Serevr im Netz */ - if( ! IRC_WriteStrClient( target, RPL_LUSERCLIENT_MSG, Client_ID( target ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED; - - /* IRC-Operatoren im Netz */ - cnt = Client_OperCount( ); - if( cnt > 0 ) - { - if( ! IRC_WriteStrClient( target, RPL_LUSEROP_MSG, Client_ID( target ), cnt )) return DISCONNECTED; - } - - /* Unbekannt Verbindungen */ - cnt = Client_UnknownCount( ); - if( cnt > 0 ) - { - if( ! IRC_WriteStrClient( target, RPL_LUSERUNKNOWN_MSG, Client_ID( target ), cnt )) return DISCONNECTED; - } - - /* Channels im Netz */ - if( ! IRC_WriteStrClient( target, RPL_LUSERCHANNELS_MSG, Client_ID( target ), Channel_Count( ))) return DISCONNECTED; - - /* Channels im Netz */ - if( ! IRC_WriteStrClient( target, RPL_LUSERME_MSG, Client_ID( target ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED; + Send_LUSERS( target ); return CONNECTED; } /* IRC_LUSERS */ @@ -1905,6 +2071,72 @@ GLOBAL BOOLEAN IRC_PART( CLIENT *Client, REQUEST *Req ) } /* IRC_PART */ +GLOBAL BOOLEAN IRC_VERSION( CLIENT *Client, REQUEST *Req ) +{ + CLIENT *target, *prefix; + + assert( Client != NULL ); + assert( Req != NULL ); + + /* Falsche Anzahl Parameter? */ + if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + + /* Ziel suchen */ + if( Req->argc == 1 ) target = Client_GetFromID( Req->argv[0] ); + else target = Client_ThisServer( ); + + /* Prefix ermitteln */ + if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_GetFromID( Req->prefix ); + else prefix = Client; + if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix ); + + /* An anderen Server weiterleiten? */ + if( target != Client_ThisServer( )) + { + if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] ); + + /* forwarden */ + IRC_WriteStrClientPrefix( Client_NextHop( target ), prefix, "VERSION %s", Req->argv[0] ); + return CONNECTED; + } + + /* mit Versionsinfo antworten */ + return IRC_WriteStrClient( Client, RPL_VERSION_MSG, Client_ID( prefix ), NGIRCd_DebugLevel, Conf_ServerName, NGIRCd_VersionAddition( )); +} /* IRC_VERSION */ + + +GLOBAL BOOLEAN IRC_KILL( CLIENT *Client, REQUEST *Req ) +{ + CLIENT *prefix, *c; + + assert( Client != NULL ); + assert( Req != NULL ); + + if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client )); + + /* Falsche Anzahl Parameter? */ + if(( Req->argc != 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + + prefix = Client_GetFromID( Req->prefix ); + if( ! prefix ) + { + Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", Req->prefix ); + prefix = Client_ThisServer( ); + } + + Log( LOG_NOTICE, "Got KILL command from \"%s\" for \"%s\": %s", Client_Mask( prefix ), Req->argv[0], Req->argv[1] ); + + /* andere Server benachrichtigen */ + IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", Req->argv[0], Req->argv[1] ); + + /* haben wir selber einen solchen Client? */ + c = Client_GetFromID( Req->argv[0] ); + if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Req->argv[1], TRUE ); + + return CONNECTED; +} /* IRC_KILL */ + + LOCAL BOOLEAN Hello_User( CLIENT *Client ) { assert( Client != NULL ); @@ -1930,7 +2162,10 @@ LOCAL BOOLEAN Hello_User( CLIENT *Client ) Client_SetType( Client, CLIENT_USER ); - return Show_MOTD( Client ); + if( ! Send_LUSERS( Client )) return DISCONNECTED; + if( ! Show_MOTD( Client )) return DISCONNECTED; + + return CONNECTED; } /* Hello_User */ @@ -1968,11 +2203,21 @@ LOCAL BOOLEAN Show_MOTD( CLIENT *Client ) } /* Show_MOTD */ -LOCAL VOID Kill_Nick( CHAR *Nick ) +LOCAL VOID Kill_Nick( CHAR *Nick, CHAR *Reason ) { - Log( LOG_ERR, "User(s) with nick \"%s\" will be disconnected!", Nick ); - /* FIXME */ - Log( LOG_ALERT, "[Kill_Nick() not implemented - OOOPS!]" ); + CLIENT *c; + + assert( Nick != NULL ); + assert( Reason != NULL ); + + Log( LOG_ERR, "User(s) with nick \"%s\" will be disconnected: %s", Nick, Reason ); + + /* andere Server benachrichtigen */ + IRC_WriteStrServers( NULL, "KILL %s :%s", Nick, Reason ); + + /* Ggf. einen eigenen Client toeten */ + c = Client_GetFromID( Nick ); + if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Reason, TRUE ); } /* Kill_Nick */ @@ -2021,4 +2266,47 @@ LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan ) } /* Send_NAMES */ +LOCAL BOOLEAN Send_LUSERS( CLIENT *Client ) +{ + INT cnt; + + assert( Client != NULL ); + + /* Users, Services und Serevr im Netz */ + if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED; + + /* IRC-Operatoren im Netz */ + cnt = Client_OperCount( ); + if( cnt > 0 ) + { + if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED; + } + + /* Unbekannt Verbindungen */ + cnt = Client_UnknownCount( ); + if( cnt > 0 ) + { + if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED; + } + + /* Channels im Netz */ + if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED; + + /* Channels im Netz */ + if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED; + + return CONNECTED; +} /* Send_LUSERS */ + + +CHAR *Get_Prefix( CLIENT *Target, CLIENT *Client ) +{ + assert( Target != NULL ); + assert( Client != NULL ); + + if( Client_Type( Target ) == CLIENT_SERVER ) return Client_ID( Client ); + else return Client_Mask( Client ); +} /* Get_Prefix */ + + /* -eof- */