X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc.c;h=efc34d4b2e087f8e3742c1d44ea6a820e2073f92;hp=67ad2a633a16747f49511154f205e47204263e45;hb=808c291c76b7ecb4ae13b6ee12e8afe658b627c1;hpb=e1de769ab9958f6debbd884a1555de09d1191d32 diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 67ad2a63..efc34d4b 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -1,20 +1,20 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2004 Alexander Barton + * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. - * - * IRC commands */ - #include "portab.h" -static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $"; +/** + * @file + * IRC commands + */ #include "imp.h" #include @@ -22,10 +22,8 @@ static char UNUSED id[] = "$Id: irc.c,v 1.132 2008/01/15 22:28:14 fw Exp $"; #include #include "ngircd.h" -#include "resolve.h" #include "conn-func.h" #include "conf.h" -#include "client.h" #include "channel.h" #include "defines.h" #include "irc-write.h" @@ -47,6 +45,35 @@ static bool Send_Message_Mask PARAMS((CLIENT *from, char *command, bool SendErrors)); +/** + * Check if a list limit is reached and inform client accordingly. + * + * @param From The client. + * @param Count Reply item count. + * @param Limit Reply limit. + * @param Name Name of the list. + * @return true if list limit has been reached; false otherwise. + */ +GLOBAL bool +IRC_CheckListTooBig(CLIENT *From, const int Count, const int Limit, + const char *Name) +{ + assert(From != NULL); + assert(Count >= 0); + assert(Limit > 0); + assert(Name != NULL); + + if (Count < Limit) + return false; + + (void)IRC_WriteStrClient(From, + "NOTICE %s :%s list limit (%d) reached!", + Client_ID(From), Name, Limit); + IRC_SetPenalty(From, 2); + return true; +} + + GLOBAL bool IRC_ERROR( CLIENT *Client, REQUEST *Req ) { @@ -65,13 +92,21 @@ IRC_ERROR( CLIENT *Client, REQUEST *Req ) /** - * Kill client on request. + * Handler for the IRC "KILL" command. + * * This function implements the IRC command "KILL" wich is used to selectively * disconnect clients. It can be used by IRC operators and servers, for example - * to "solve" nick collisions after netsplits. + * to "solve" nick collisions after netsplits. See RFC 2812 section 3.7.1. + * * Please note that this function is also called internally, without a real - * KILL command beeing received over the network! Client is Client_ThisServer() - * in this case. */ + * KILL command being received over the network! Client is Client_ThisServer() + * in this case, and the prefix in Req is NULL. + * + * @param Client The client from which this command has been received + * or Client_ThisServer() when generated interanlly. + * @param Req Request structure with prefix and all parameters. + * @returns CONNECTED or DISCONNECTED. + */ GLOBAL bool IRC_KILL( CLIENT *Client, REQUEST *Req ) { @@ -79,55 +114,47 @@ IRC_KILL( CLIENT *Client, REQUEST *Req ) char reason[COMMAND_LEN], *msg; CONN_ID my_conn, conn; - assert( Client != NULL ); - assert( Req != NULL ); + assert (Client != NULL); + assert (Req != NULL); - if(( Client_Type( Client ) != CLIENT_SERVER ) && - ( ! Client_OperByMe( Client ))) - { - /* The originator of the KILL is neither an IRC operator of - * this server nor a server. */ - return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, - Client_ID( Client )); - } + if (Client_Type(Client) != CLIENT_SERVER && !Client_OperByMe(Client)) + return IRC_WriteStrClient(Client, ERR_NOPRIVILEGES_MSG, + Client_ID(Client)); - if( Req->argc != 2 ) - { - /* This command requires exactly 2 parameters! */ - 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); - if( Req->prefix ) prefix = Client_Search( Req->prefix ); - else prefix = Client; - if( ! prefix ) - { - Log( LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", - Req->prefix ); - prefix = Client_ThisServer( ); + /* Get prefix (origin); use the client if no prefix is given. */ + if (Req->prefix) + prefix = Client_Search(Req->prefix); + else + prefix = Client; + + /* Log a warning message and use this server as origin when the + * prefix (origin) is invalid. */ + if (!prefix) { + Log(LOG_WARNING, "Got KILL with invalid prefix: \"%s\"!", + Req->prefix ); + prefix = Client_ThisServer(); } - if( Client != Client_ThisServer( )) - { - /* This is a "real" KILL received from the network. */ - Log( LOG_NOTICE|LOG_snotice, "Got KILL command from \"%s\" for \"%s\": %s", - Client_Mask( prefix ), Req->argv[0], Req->argv[1] ); - } + if (Client != Client_ThisServer()) + Log(LOG_NOTICE|LOG_snotice, + "Got KILL command from \"%s\" for \"%s\": %s", + Client_Mask(prefix), Req->argv[0], Req->argv[1]); - /* Build reason string */ - if( Client_Type( Client ) == CLIENT_USER ) - { - /* Prefix the "reason" if the originator is a regular user, - * so users can't spoof KILLs of servers. */ - snprintf( reason, sizeof( reason ), "KILLed by %s: %s", - Client_ID( Client ), Req->argv[1] ); - } + /* Build reason string: Prefix the "reason" if the originator is a + * regular user, so users can't spoof KILLs of servers. */ + if (Client_Type(Client) == CLIENT_USER) + snprintf(reason, sizeof(reason), "KILLed by %s: %s", + Client_ID(Client), Req->argv[1]); else - strlcpy( reason, Req->argv[1], sizeof( reason )); + strlcpy(reason, Req->argv[1], sizeof(reason)); /* Inform other servers */ - IRC_WriteStrServersPrefix( Client, prefix, "KILL %s :%s", - Req->argv[0], reason ); + IRC_WriteStrServersPrefix(Client, prefix, "KILL %s :%s", + Req->argv[0], reason); /* Save ID of this connection */ my_conn = Client_Conn( Client ); @@ -160,11 +187,15 @@ IRC_KILL( CLIENT *Client, REQUEST *Req ) Client_Type( c ), Req->argv[0] ); } - /* Kill client NOW! */ + /* Kill the client NOW: + * - Close the local connection (if there is one), + * - Destroy the CLIENT structure for remote clients. + * Note: Conn_Close() removes the CLIENT structure as well. */ conn = Client_Conn( c ); - Client_Destroy( c, NULL, reason, false ); - if( conn > NONE ) - Conn_Close( conn, NULL, reason, true ); + if(conn > NONE) + Conn_Close(conn, NULL, reason, true); + else + Client_Destroy(c, NULL, reason, false); } else Log( LOG_NOTICE, "Client with nick \"%s\" is unknown here.", Req->argv[0] ); @@ -296,12 +327,18 @@ IRC_HELP( CLIENT *Client, REQUEST *Req ) static char * -Option_String( CONN_ID Idx ) +#ifdef ZLIB +Option_String(CONN_ID Idx) +#else +Option_String(UNUSED CONN_ID Idx) +#endif { static char option_txt[8]; +#ifdef ZLIB UINT16 options; options = Conn_Options(Idx); +#endif strcpy(option_txt, "F"); /* No idea what this means, but the * original ircd sends it ... */ @@ -318,6 +355,7 @@ static bool Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) { CLIENT *cl, *from; + CL2CHAN *cl2chan; CHANNEL *chan; char *currentTarget = Req->argv[0]; char *lastCurrentTarget = NULL; @@ -408,9 +446,9 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) Client_Type(cl) != CLIENT_SERVICE) continue; if (nick != NULL && host != NULL) { - if (strcmp(nick, Client_ID(cl)) == 0 && - strcmp(user, Client_User(cl)) == 0 && - strcasecmp(host, Client_Hostname(cl)) == 0) + if (strcasecmp(nick, Client_ID(cl)) == 0 && + strcasecmp(user, Client_User(cl)) == 0 && + strcasecmp(host, Client_HostnameCloaked(cl)) == 0) break; else continue; @@ -418,7 +456,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) if (strcasecmp(user, Client_User(cl)) != 0) continue; if (host != NULL && strcasecmp(host, - Client_Hostname(cl)) != 0) + Client_HostnameCloaked(cl)) != 0) continue; if (server != NULL && strcasecmp(server, Client_ID(Client_Introducer(cl))) != 0) @@ -437,11 +475,11 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) #else if (Client_Type(cl) != ForceType) { #endif - if (!SendErrors) - return CONNECTED; - return IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG, - Client_ID(from), - currentTarget); + if (SendErrors && !IRC_WriteStrClient( + from, ERR_NOSUCHNICK_MSG,Client_ID(from), + currentTarget)) + return DISCONNECTED; + goto send_next_target; } #ifndef STRICT_RFC @@ -454,6 +492,23 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) } #endif + if (Client_HasMode(cl, 'C')) { + cl2chan = Channel_FirstChannelOf(cl); + while (cl2chan) { + chan = Channel_GetChannel(cl2chan); + if (Channel_IsMemberOf(chan, from)) + break; + cl2chan = Channel_NextChannelOf(cl, cl2chan); + } + if (!cl2chan) { + if (SendErrors && !IRC_WriteStrClient( + from, ERR_NOTONSAMECHANNEL_MSG, + Client_ID(from), Client_ID(cl))) + return DISCONNECTED; + goto send_next_target; + } + } + if (SendErrors && (Client_Type(Client) != CLIENT_SERVER) && strchr(Client_Modes(cl), 'a')) { /* Target is away */ @@ -491,7 +546,10 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) return DISCONNECTED; } + send_next_target: currentTarget = strtok_r(NULL, ",", &lastCurrentTarget); + if (currentTarget) + Conn_SetPenalty(Client_Conn(Client), 1); } return CONNECTED;