X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc.c;h=f58dda6f0ded37c6323471ae9d6ad4e3cf79f0ad;hp=08cd090404dbd31334fb8242801ef21e45775e42;hb=c147ebef0dfa701922c09df6bd93d77e93c80136;hpb=b60f369266d895009642fab4c8cef3953938f0d3 diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 08cd0904..f58dda6f 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -9,11 +9,61 @@ * 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.60 2002/02/17 17:43:14 alex Exp $ + * $Id: irc.c,v 1.75 2002/02/27 15:23:27 alex Exp $ * * irc.c: IRC-Befehle * * $Log: irc.c,v $ + * Revision 1.75 2002/02/27 15:23:27 alex + * - NAMES beachtet nun das "invisible" Flag ("i") von Usern. + * + * Revision 1.74 2002/02/27 03:44:53 alex + * - gerade eben in SQUIT eingefuehrten Bug behoben: entfernte Server werden nun + * nur noch geloescht, die Verbindung, von der SQUIT kam, bleibt wieder offen. + * + * Revision 1.73 2002/02/27 03:08:05 alex + * - Log-Meldungen bei SQUIT erneut ueberarbeitet ... + * + * Revision 1.72 2002/02/27 02:26:58 alex + * - SQUIT wird auf jeden Fall geforwarded, zudem besseres Logging. + * + * Revision 1.71 2002/02/27 00:50:05 alex + * - einige unnoetige Client_NextHop()-Aufrufe entfernt. + * - NAMES korrigiert und komplett implementiert. + * + * 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. * @@ -262,11 +312,13 @@ 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 ) { @@ -313,7 +365,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 */ @@ -335,8 +387,8 @@ 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; CL2CHAN *cl2chan; CLIENT *c; INT s, i; @@ -373,6 +425,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 ); } @@ -382,7 +436,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; } } @@ -434,7 +489,7 @@ GLOBAL VOID IRC_WriteStrServersPrefix( CLIENT *ExceptOf, CLIENT *Prefix, CHAR *F GLOBAL BOOLEAN IRC_WriteStrRelatedPrefix( CLIENT *Client, CLIENT *Prefix, BOOLEAN Remote, CHAR *Format, ... ) { - BOOLEAN sock[MAX_CONNECTIONS], ok = CONNECTED; + BOOLEAN sock[MAX_CONNECTIONS], is_server[MAX_CONNECTIONS], ok = CONNECTED; CL2CHAN *chan_cl2chan, *cl2chan; CHAR buffer[1000]; CHANNEL *chan; @@ -478,6 +533,8 @@ GLOBAL BOOLEAN IRC_WriteStrRelatedPrefix( CLIENT *Client, CLIENT *Prefix, BOOLEA 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 ); } @@ -491,7 +548,8 @@ GLOBAL BOOLEAN IRC_WriteStrRelatedPrefix( CLIENT *Client, CLIENT *Prefix, BOOLEA { 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; } } @@ -853,13 +911,10 @@ GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req ) } /* Nick-Aenderung: allen mitteilen! */ - Log( LOG_INFO, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] ); - if( Client_Type( Client ) == CLIENT_USER ) IRC_WriteStrClient( Client, "NICK :%s", Req->argv[0] ); + + 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] ); - - /* Client-Nick registrieren */ - Client_SetID( target, Req->argv[0] ); if(( Client_Type( target ) != CLIENT_USER ) && ( Client_Type( target ) != CLIENT_SERVER )) { @@ -868,6 +923,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 ) @@ -885,7 +945,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; } @@ -894,7 +954,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; } @@ -906,7 +966,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; } @@ -998,6 +1058,7 @@ GLOBAL BOOLEAN IRC_QUIT( CLIENT *Client, REQUEST *Req ) GLOBAL BOOLEAN IRC_SQUIT( CLIENT *Client, REQUEST *Req ) { CLIENT *target; + CHAR msg[LINE_LEN + 64]; assert( Client != NULL ); assert( Req != NULL ); @@ -1008,28 +1069,36 @@ GLOBAL BOOLEAN IRC_SQUIT( CLIENT *Client, REQUEST *Req ) /* Falsche Anzahl Parameter? */ if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + Log( LOG_DEBUG, "Got SQUIT from %s for \"%s\": \"%s\" ...", Client_ID( Client ), Req->argv[0], Req->argv[1] ); + + /* SQUIT an alle Server weiterleiten */ + IRC_WriteStrServers( Client, "SQUIT %s :%s", Req->argv[0], Req->argv[1] ); + target = Client_GetFromID( Req->argv[0] ); if( ! target ) { - Log( LOG_ERR, "Got SQUIT from %s for unknown server \%s\"!?", Client_ID( Client ), Req->argv[0] ); + Log( LOG_ERR, "Got SQUIT from %s for unknown server \"%s\"!?", Client_ID( Client ), Req->argv[0] ); return CONNECTED; } - if( target == Client ) Log( LOG_DEBUG, "Got SQUIT from %s: %s", Client_ID( Client ), Req->argv[1] ); - else Log( LOG_DEBUG, "Got SQUIT from %s for %s: %s", Client_ID( Client ), Client_ID( target ), Req->argv[1] ); - - /* SQUIT an alle Server weiterleiten */ - IRC_WriteStrServers( Client, "SQUIT %s :%s", Req->argv[0], Req->argv[1] ); + if( Req->argv[1][0] ) + { + if( strlen( Req->argv[1] ) > LINE_LEN ) Req->argv[1][LINE_LEN] = '\0'; + sprintf( msg, "%s (SQUIT from %s).", Req->argv[1], Client_ID( Client )); + } + else sprintf( msg, "Got SQUIT from %s.", Client_ID( Client )); if( Client_Conn( target ) > NONE ) { - if( Req->argv[1][0] ) Conn_Close( Client_Conn( target ), "Got SQUIT command.", Req->argv[1], TRUE ); - else Conn_Close( Client_Conn( target ), "Got SQUIT command.", NULL, TRUE ); + /* dieser Server hat die Connection */ + if( Req->argv[1][0] ) Conn_Close( Client_Conn( target ), msg, Req->argv[1], TRUE ); + else Conn_Close( Client_Conn( target ), msg, NULL, TRUE ); return DISCONNECTED; } else { - Client_Destroy( target, "Got SQUIT command.", Req->argv[1] ); + /* Verbindung hielt anderer Server */ + Client_Destroy( target, msg, Req->argv[1] ); return CONNECTED; } } /* IRC_SQUIT */ @@ -1059,7 +1128,7 @@ GLOBAL BOOLEAN IRC_PING( CLIENT *Client, REQUEST *Req ) if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix ); else from = Client; if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix ); - return IRC_WriteStrClientPrefix( Client_NextHop( target ), from, "PING %s :%s", Client_ID( from ), Req->argv[1] ); + return IRC_WriteStrClientPrefix( target, from, "PING %s :%s", Client_ID( from ), Req->argv[1] ); } } @@ -1092,14 +1161,14 @@ GLOBAL BOOLEAN IRC_PONG( CLIENT *Client, REQUEST *Req ) if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix ); else from = Client; if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix ); - return IRC_WriteStrClientPrefix( Client_NextHop( target ), from, "PONG %s :%s", Client_ID( from ), Req->argv[1] ); + return IRC_WriteStrClientPrefix( target, from, "PONG %s :%s", Client_ID( from ), Req->argv[1] ); } } /* 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; @@ -1587,46 +1656,96 @@ GLOBAL BOOLEAN IRC_RESTART( CLIENT *Client, REQUEST *Req ) GLOBAL BOOLEAN IRC_NAMES( CLIENT *Client, REQUEST *Req ) { - CHAR rpl[COMMAND_LEN]; - CLIENT *c; + CHAR rpl[COMMAND_LEN], *ptr; + CLIENT *target, *from, *c; + CHANNEL *chan; assert( Client != NULL ); assert( Req != NULL ); - if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client )); + if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client )); /* Falsche Anzahl Parameter? */ - if( Req->argc != 0 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + + /* From aus Prefix ermitteln */ + if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix ); + else from = Client; + if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix ); + + if( Req->argc == 2 ) + { + /* an anderen Server forwarden */ + target = Client_GetFromID( Req->argv[1] ); + if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] ); + + if( target != Client_ThisServer( )) + { + /* Ok, anderer Server ist das Ziel: forwarden */ + return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] ); + } + } + + if( Req->argc > 0 ) + { + /* bestimmte Channels durchgehen */ + ptr = strtok( Req->argv[0], "," ); + while( ptr ) + { + chan = Channel_Search( ptr ); + if( chan ) + { + /* Namen ausgeben */ + if( ! Send_NAMES( from, chan )) return DISCONNECTED; + } + if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED; + + /* naechsten Namen ermitteln */ + ptr = strtok( NULL, "," ); + } + return CONNECTED; + } + + /* alle Channels durchgehen */ + chan = Channel_First( ); + while( chan ) + { + /* Namen ausgeben */ + if( ! Send_NAMES( from, chan )) return DISCONNECTED; + + /* naechster Channel */ + chan = Channel_Next( chan ); + } - /* Noch alle User ausgeben, die in keinem Channel sind */ - rpl[0] = '\0'; + /* Nun noch alle Clients ausgeben, die in keinem Channel sind */ c = Client_First( ); + sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" ); while( c ) { - if( Client_Type( c ) == CLIENT_USER ) + if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' ))) { - /* Okay, das ist ein User */ + /* Okay, das ist ein User: anhaengen */ + if( rpl[strlen( rpl ) - 1] != ':' ) strcat( rpl, " " ); strcat( rpl, Client_ID( c )); - strcat( rpl, " " ); - } - /* Antwort zu lang? Splitten. */ - if( strlen( rpl ) > 480 ) - { - if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0'; - if( ! IRC_WriteStrClient( Client, RPL_NAMREPLY_MSG, Client_ID( Client ), "*", "*", rpl )) return DISCONNECTED; - rpl[0] = '\0'; + if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 )) + { + /* Zeile wird zu lang: senden! */ + if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED; + sprintf( rpl, RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" ); + } } - + + /* naechster Client */ c = Client_Next( c ); } - if( rpl[0] ) + if( rpl[strlen( rpl ) - 1] != ':') { /* es wurden User gefunden */ - if( rpl[strlen( rpl ) - 1] == ' ' ) rpl[strlen( rpl ) - 1] = '\0'; - if( ! IRC_WriteStrClient( Client, RPL_NAMREPLY_MSG, Client_ID( Client ), "*", "*", rpl )) return DISCONNECTED; + if( ! IRC_WriteStrClient( from, rpl )) return DISCONNECTED; } - return IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), "*" ); + + return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" ); } /* IRC_NAMES */ @@ -1700,17 +1819,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; @@ -1985,10 +2098,13 @@ GLOBAL BOOLEAN IRC_JOIN( CLIENT *Client, REQUEST *Req ) { /* an Client bestaetigen */ IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame ); + /* Topic an Client schicken */ IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, "What a wonderful channel!" ); + /* Mitglieder an Client Melden */ Send_NAMES( Client, chan ); + IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan )); } /* naechsten Namen ermitteln */ @@ -2034,6 +2150,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( 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 ); @@ -2100,16 +2282,27 @@ 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 */ LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan ) { + BOOLEAN is_visible, is_member; CHAR str[LINE_LEN + 1]; CL2CHAN *cl2chan; CLIENT *cl; @@ -2117,6 +2310,9 @@ LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan ) assert( Client != NULL ); assert( Chan != NULL ); + if( Channel_IsMemberOf( Chan, Client )) is_member = TRUE; + else is_member = FALSE; + /* Alle Mitglieder suchen */ sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan )); cl2chan = Channel_FirstMember( Chan ); @@ -2124,17 +2320,23 @@ LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan ) { cl = Channel_GetClient( cl2chan ); - /* Nick anhaengen */ - if( str[strlen( str ) - 1] != ':' ) strcat( str, " " ); - if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" ); - if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" ); - strcat( str, Client_ID( cl )); + if( strchr( Client_Modes( cl ), 'i' )) is_visible = FALSE; + else is_visible = TRUE; - if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 )) + if( is_member || is_visible ) { - /* Zeile wird zu lang: senden! */ - if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED; - sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan )); + /* Nick anhaengen */ + if( str[strlen( str ) - 1] != ':' ) strcat( str, " " ); + if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strcat( str, "+" ); + if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strcat( str, "@" ); + strcat( str, Client_ID( cl )); + + if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 )) + { + /* Zeile wird zu lang: senden! */ + if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED; + sprintf( str, RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan )); + } } /* naechstes Mitglied suchen */ @@ -2146,9 +2348,6 @@ LOCAL BOOLEAN Send_NAMES( CLIENT *Client, CHANNEL *Chan ) if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED; } - /* Ende anzeigen */ - IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( Chan )); - return CONNECTED; } /* Send_NAMES */ @@ -2186,4 +2385,14 @@ LOCAL BOOLEAN Send_LUSERS( CLIENT *Client ) } /* 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- */