X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc.c;h=37df06873bb30e99c78d91c360d23a09b9bbfec1;hp=69dd61a797994886c63bf0426a6d4434192a993c;hb=d38d153f;hpb=456e55921dddb4ae24bfc887b668c0e6407caace diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c index 69dd61a7..37df0687 100644 --- a/src/ngircd/irc.c +++ b/src/ngircd/irc.c @@ -1,6 +1,6 @@ /* * 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 @@ -25,6 +25,7 @@ #include "conn-func.h" #include "conf.h" #include "channel.h" +#include "conn-encoding.h" #include "defines.h" #include "irc-write.h" #include "log.h" @@ -43,6 +44,36 @@ static bool Send_Message PARAMS((CLIENT *Client, REQUEST *Req, int ForceType, static bool Send_Message_Mask PARAMS((CLIENT *from, char *command, char *targetMask, char *message, bool SendErrors)); +static bool Help PARAMS((CLIENT *Client, const char *Topic)); + + +/** + * 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 @@ -51,6 +82,17 @@ IRC_ERROR( CLIENT *Client, REQUEST *Req ) assert( Client != NULL ); assert( Req != NULL ); + if (Client_Type(Client) != CLIENT_GOTPASS + && Client_Type(Client) != CLIENT_GOTPASS_2813 + && Client_Type(Client) != CLIENT_UNKNOWNSERVER + && Client_Type(Client) != CLIENT_SERVER + && Client_Type(Client) != CLIENT_SERVICE) { + LogDebug("Ignored ERROR command from \"%s\" ...", + Client_Mask(Client)); + IRC_SetPenalty(Client, 2); + return CONNECTED; + } + if (Req->argc < 1) Log(LOG_NOTICE, "Got ERROR from \"%s\"!", Client_Mask(Client)); @@ -112,7 +154,7 @@ IRC_KILL( CLIENT *Client, REQUEST *Req ) if (Client != Client_ThisServer()) Log(LOG_NOTICE|LOG_snotice, - "Got KILL command from \"%s\" for \"%s\": %s", + "Got KILL command from \"%s\" for \"%s\": \"%s\".", Client_Mask(prefix), Req->argv[0], Req->argv[1]); /* Build reason string: Prefix the "reason" if the originator is a @@ -274,36 +316,129 @@ IRC_TRACE( CLIENT *Client, REQUEST *Req ) } /* IRC_TRACE */ +/** + * Handler for the IRC "HELP" command. + * + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. + */ GLOBAL bool -IRC_HELP( CLIENT *Client, REQUEST *Req ) +IRC_HELP(CLIENT *Client, REQUEST *Req) { COMMAND *cmd; - assert( Client != NULL ); - assert( Req != NULL ); + assert(Client != NULL); + assert(Req != NULL); /* Bad number of arguments? */ - if( Req->argc > 0 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command ); + if (Req->argc > 1) + return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG, + Client_ID(Client), Req->command); - cmd = Parse_GetCommandStruct( ); - while( cmd->name ) - { - if( ! IRC_WriteStrClient( Client, "NOTICE %s :%s", Client_ID( Client ), cmd->name )) return DISCONNECTED; + IRC_SetPenalty(Client, 2); + + if ((Req->argc == 0 && array_bytes(&Conf_Helptext) > 0) + || (Req->argc >= 1 && strcasecmp(Req->argv[0], "Commands") != 0)) { + /* Help text available and requested */ + if (Req->argc >= 1) + return Help(Client, Req->argv[0]); + + if (!Help(Client, "Intro")) + return DISCONNECTED; + return CONNECTED; + } + + cmd = Parse_GetCommandStruct(); + while(cmd->name) { + if (!IRC_WriteStrClient(Client, "NOTICE %s :%s", + Client_ID(Client), cmd->name)) + return DISCONNECTED; cmd++; } - - IRC_SetPenalty( Client, 2 ); return CONNECTED; } /* IRC_HELP */ +/** + * Send help for a given topic to the client. + * + * @param Client The client requesting help. + * @param Topoc The help topic requested. + * @return CONNECTED or DISCONNECTED. + */ +static bool +Help(CLIENT *Client, const char *Topic) +{ + char *line; + size_t helptext_len, len_str, idx_start, lines = 0; + bool in_article = false; + + assert(Client != NULL); + assert(Topic != NULL); + + helptext_len = array_bytes(&Conf_Helptext); + line = array_start(&Conf_Helptext); + while (helptext_len > 0) { + len_str = strlen(line) + 1; + assert(helptext_len >= len_str); + helptext_len -= len_str; + + if (in_article) { + /* The first character in each article text line must + * be a TAB (ASCII 9) character which will be stripped + * in the output. If it is not a TAB, the end of the + * article has been reached. */ + if (line[0] != '\t') { + if (lines > 0) + return CONNECTED; + else + break; + } + + /* A single '.' character indicates an empty line */ + if (line[1] == '.' && line[2] == '\0') + idx_start = 2; + else + idx_start = 1; + + if (!IRC_WriteStrClient(Client, "NOTICE %s :%s", + Client_ID(Client), + &line[idx_start])) + return DISCONNECTED; + lines++; + + } else { + if (line[0] == '-' && line[1] == ' ' + && strcasecmp(&line[2], Topic) == 0) + in_article = true; + } + + line += len_str; + } + + /* Help topic not found (or empty)! */ + if (!IRC_WriteStrClient(Client, "NOTICE %s :No help for \"%s\" found!", + Client_ID(Client), Topic)) + return DISCONNECTED; + + return CONNECTED; +} + + 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 ... */ @@ -320,9 +455,11 @@ 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; + char *message = NULL; assert(Client != NULL); assert(Req != NULL); @@ -354,6 +491,13 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->prefix); +#ifdef ICONV + if (Client_Conn(Client) > NONE) + message = Conn_EncodingFrom(Client_Conn(Client), Req->argv[1]); + else +#endif + message = Req->argv[1]; + /* handle msgtarget = msgto *("," msgto) */ currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget); ngt_UpperStr(Req->command); @@ -410,9 +554,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_HostnameCloaked(cl)) == 0) + if (strcasecmp(nick, Client_ID(cl)) == 0 && + strcasecmp(user, Client_User(cl)) == 0 && + strcasecmp(host, Client_HostnameDisplayed(cl)) == 0) break; else continue; @@ -420,7 +564,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_HostnameCloaked(cl)) != 0) + Client_HostnameDisplayed(cl)) != 0) continue; if (server != NULL && strcasecmp(server, Client_ID(Client_Introducer(cl))) != 0) @@ -439,11 +583,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 @@ -455,6 +599,34 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) Req->command = "PRIVMSG"; } #endif + if (Client_HasMode(cl, 'b') && + !Client_HasMode(from, 'R') && + !Client_HasMode(from, 'o') && + !(Client_Type(from) == CLIENT_SERVER) && + !(Client_Type(from) == CLIENT_SERVICE)) { + if (SendErrors && !IRC_WriteStrClient(from, + ERR_NONONREG_MSG, + Client_ID(from), Client_ID(cl))) + return DISCONNECTED; + goto send_next_target; + } + + 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')) { @@ -470,12 +642,12 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) } if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s", Req->command, Client_ID(cl), - Req->argv[1])) + message)) return DISCONNECTED; } else if (ForceType != CLIENT_SERVICE && (chan = Channel_Search(currentTarget))) { if (!Channel_Write(chan, from, Client, Req->command, - SendErrors, Req->argv[1])) + SendErrors, message)) return DISCONNECTED; } else if (ForceType != CLIENT_SERVICE /* $#: server/target mask, RFC 2812, sec. 3.3.1 */ @@ -483,7 +655,7 @@ Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) && strchr(currentTarget, '.')) { /* targetmask */ if (!Send_Message_Mask(from, Req->command, currentTarget, - Req->argv[1], SendErrors)) + message, SendErrors)) return DISCONNECTED; } else { if (!SendErrors) @@ -493,7 +665,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;