X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Firc-info.c;h=93c43b75f14072b71aa17ef3843f3fdcee6b8c8a;hb=6a308fcb42eae1de168699ed432b49b610073ede;hp=ebb7be4afb5c7aed28a361d1fae6a34a79083176;hpb=f47904bf954696803c0df8e756a57a3dabaa8845;p=ngircd-alex.git diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index ebb7be4a..93c43b75 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors. + * 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 @@ -37,6 +37,7 @@ #include "match.h" #include "tool.h" #include "parse.h" +#include "irc.h" #include "irc-write.h" #include "exp.h" @@ -154,6 +155,15 @@ IRC_INFO(CLIENT * Client, REQUEST * Req) } /* IRC_INFO */ +/** + * Handler for the IRC "ISON" command. + * + * See RFC 2812, 4.9 "Ison message". + * + * @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_ISON( CLIENT *Client, REQUEST *Req ) { @@ -162,80 +172,103 @@ IRC_ISON( CLIENT *Client, REQUEST *Req ) char *ptr; int i; - assert( Client != NULL ); - assert( Req != NULL ); + 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 ); + /* Bad number of arguments? */ + if (Req->argc < 1) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); - strlcpy( rpl, RPL_ISON_MSG, sizeof rpl ); - for( i = 0; i < Req->argc; i++ ) - { - ptr = strtok( Req->argv[i], " " ); - while( ptr ) - { - ngt_TrimStr( ptr ); - c = Client_Search( ptr ); - if( c && ( Client_Type( c ) == CLIENT_USER )) - { - /* Dieser Nick ist "online" */ - strlcat( rpl, ptr, sizeof( rpl )); - strlcat( rpl, " ", sizeof( rpl )); + strlcpy(rpl, RPL_ISON_MSG, sizeof rpl); + for (i = 0; i < Req->argc; i++) { + /* "All" ircd even parse ": ..." arguments and split + * them up; so we do the same ... */ + ptr = strtok(Req->argv[i], " "); + while (ptr) { + ngt_TrimStr(ptr); + c = Client_Search(ptr); + if (c && Client_Type(c) == CLIENT_USER) { + strlcat(rpl, Client_ID(c), sizeof(rpl)); + strlcat(rpl, " ", sizeof(rpl)); } - ptr = strtok( NULL, " " ); + ptr = strtok(NULL, " "); } } ngt_TrimLastChr(rpl, ' '); - return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) ); + return IRC_WriteStrClient(Client, rpl, Client_ID(Client)); } /* IRC_ISON */ +/** + * Handler for the IRC "LINKS" command. + * + * See RFC 2812, 3.4.5 "Links message". + * + * @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_LINKS( CLIENT *Client, REQUEST *Req ) +IRC_LINKS(CLIENT *Client, REQUEST *Req) { CLIENT *target, *from, *c; char *mask; - assert( Client != NULL ); - assert( Req != NULL ); + assert(Client != NULL); + assert(Req != NULL); - if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + IRC_SetPenalty(Client, 1); - /* Server-Mask ermitteln */ - if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1]; - else mask = "*"; + if (Req->argc > 2) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); - /* Absender ermitteln */ - if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix ); - else from = Client; - if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix ); + /* Get pointer to server mask or "*", if none given */ + if (Req->argc > 0) + mask = Req->argv[Req->argc - 1]; + else + mask = "*"; - /* An anderen Server forwarden? */ - if( Req->argc == 2 ) - { - target = Client_Search( Req->argv[0] ); - if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] ); - else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] ); - } + if (Client_Type(Client) == CLIENT_SERVER) + from = Client_Search(Req->prefix); + else + from = Client; + if (!from) + return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), Req->prefix); - /* Wer ist der Absender? */ - if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix ); - else target = Client; - if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix ); + /* Forward? */ + if (Req->argc == 2) { + target = Client_Search(Req->argv[0]); + if (! target || Client_Type(target) != CLIENT_SERVER) + return IRC_WriteStrClient(from, ERR_NOSUCHSERVER_MSG, + Client_ID(from), + Req->argv[0] ); + else + if (target != Client_ThisServer()) + return IRC_WriteStrClientPrefix(target, from, + "LINKS %s %s", Req->argv[0], + Req->argv[1]); + } - c = Client_First( ); - while( c ) - { - if( Client_Type( c ) == CLIENT_SERVER ) - { - 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; + c = Client_First(); + while (c) { + if (Client_Type(c) == CLIENT_SERVER + && MatchCaseInsensitive(mask, Client_ID(c))) { + if (!IRC_WriteStrClient(from, RPL_LINKS_MSG, + Client_ID(from), Client_ID(c), + Client_ID(Client_TopServer(c) + ? Client_TopServer(c) + : Client_ThisServer()), + Client_Hops(c), Client_Info(c))) + return DISCONNECTED; } - c = Client_Next( c ); + c = Client_Next(c); } - - IRC_SetPenalty( target, 1 ); - return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask ); + return IRC_WriteStrClient(from, RPL_ENDOFLINKS_MSG, + Client_ID(from), mask); } /* IRC_LINKS */ @@ -615,10 +648,10 @@ IRC_STATS( CLIENT *Client, REQUEST *Req ) * therefore answers with ERR_SUMMONDISABLED. */ GLOBAL bool -IRC_SUMMON(CLIENT * Client, REQUEST * Req) +IRC_SUMMON(CLIENT * Client, UNUSED REQUEST * Req) { return IRC_WriteStrClient(Client, ERR_SUMMONDISABLED_MSG, - Client_ID(Client), Req->command); + Client_ID(Client)); } /* IRC_SUMMON */ @@ -708,10 +741,10 @@ IRC_USERHOST(CLIENT *Client, REQUEST *Req) * See RFC 2812 section 4.6. As suggested there the command is disabled. */ GLOBAL bool -IRC_USERS(CLIENT * Client, REQUEST * Req) +IRC_USERS(CLIENT * Client, UNUSED REQUEST * Req) { return IRC_WriteStrClient(Client, ERR_USERSDISABLED_MSG, - Client_ID(Client), Req->command); + Client_ID(Client)); } /* IRC_USERS */ @@ -801,6 +834,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps) const char *chan_user_modes; char flags[8]; CLIENT *c; + int count = 0; assert( Client != NULL ); assert( Chan != NULL ); @@ -823,6 +857,9 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps) is_visible = strchr(client_modes, 'i') == NULL; if (is_member || is_visible) { + if (IRC_CheckListTooBig(Client, count, MAX_RPL_WHO, "WHO")) + break; + strcpy(flags, who_flags_status(client_modes)); if (is_ircop) strlcat(flags, "*", sizeof(flags)); @@ -834,6 +871,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps) if (!write_whoreply(Client, c, Channel_Name(Chan), flags)) return DISCONNECTED; + count++; } } return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), @@ -857,6 +895,7 @@ IRC_WHO_Mask(CLIENT *Client, char *Mask, bool OnlyOps) CHANNEL *chan; bool client_match, is_visible; char flags[4]; + int count = 0; assert (Client != NULL); @@ -907,13 +946,16 @@ IRC_WHO_Mask(CLIENT *Client, char *Mask, bool OnlyOps) if (!is_visible) /* target user is not visible */ continue; + if (IRC_CheckListTooBig(Client, count, MAX_RPL_WHO, "WHO")) + break; + strcpy(flags, who_flags_status(Client_Modes(c))); if (strchr(Client_Modes(c), 'o')) strlcat(flags, "*", sizeof(flags)); if (!write_whoreply(Client, c, "*", flags)) return DISCONNECTED; - + count++; } return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), @@ -983,10 +1025,10 @@ IRC_WHO(CLIENT *Client, REQUEST *Req) /** * Generate WHOIS reply of one actual client. * - * @param Client The client from which this command has been received. - * @param from The client requesting the information ("originator"). - * @param c The client of which information should be returned. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param from The client requesting the information ("originator"). + * @param c The client of which information should be returned. + * @return CONNECTED or DISCONNECTED. */ static bool IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c) @@ -995,6 +1037,10 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c) CL2CHAN *cl2chan; CHANNEL *chan; + assert(Client != NULL); + assert(from != NULL); + assert(c != NULL); + /* Nick, user, hostname and client info */ if (!IRC_WriteStrClient(from, RPL_WHOISUSER_MSG, Client_ID(from), Client_ID(c), Client_User(c), @@ -1052,33 +1098,37 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c) /* IRC-Operator? */ if (Client_HasMode(c, 'o') && - !IRC_WriteStrClient(from, RPL_WHOISOPERATOR_MSG, - Client_ID(from), Client_ID(c))) - return DISCONNECTED; + !IRC_WriteStrClient(from, RPL_WHOISOPERATOR_MSG, + Client_ID(from), Client_ID(c))) + return DISCONNECTED; /* Connected using SSL? */ if (Conn_UsesSSL(Client_Conn(c)) && - !IRC_WriteStrClient(from, RPL_WHOISSSL_MSG, - Client_ID(from), Client_ID(c))) - return DISCONNECTED; + !IRC_WriteStrClient(from, RPL_WHOISSSL_MSG, Client_ID(from), + Client_ID(c))) + return DISCONNECTED; + + /* Registered nick name? */ + if (Client_HasMode(c, 'R') && + !IRC_WriteStrClient(from, RPL_WHOISREGNICK_MSG, + Client_ID(from), Client_ID(c))) + return DISCONNECTED; /* Idle and signon time (local clients only!) */ if (!Conf_MorePrivacy && Client_Conn(c) > NONE && - !IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG, - Client_ID(from), Client_ID(c), - (unsigned long)Conn_GetIdle(Client_Conn(c)), - (unsigned long)Conn_GetSignon(Client_Conn(c)))) - return DISCONNECTED; + !IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG, + Client_ID(from), Client_ID(c), + (unsigned long)Conn_GetIdle(Client_Conn(c)), + (unsigned long)Conn_GetSignon(Client_Conn(c)))) + return DISCONNECTED; /* Away? */ if (Client_HasMode(c, 'a') && - !IRC_WriteStrClient(from, RPL_AWAY_MSG, - Client_ID(from), Client_ID(c), - Client_Away(c))) - return DISCONNECTED; + !IRC_WriteStrClient(from, RPL_AWAY_MSG, + Client_ID(from), Client_ID(c), Client_Away(c))) + return DISCONNECTED; - return IRC_WriteStrClient(from, RPL_ENDOFWHOIS_MSG, - Client_ID(from), Client_ID(c)); + return CONNECTED; } /* IRC_WHOIS_SendReply */ @@ -1098,7 +1148,7 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req ) unsigned int match_count = 0, found = 0; bool has_wildcards, is_remote; bool got_wildcard = false; - const char *query; + char mask[COMMAND_LEN], *query; assert( Client != NULL ); assert( Req != NULL ); @@ -1139,7 +1189,8 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req ) Req->argv[0], Req->argv[1]); is_remote = Client_Conn(from) < 0; - for (query = strtok(Req->argv[Req->argc - 1], ","); + strlcpy(mask, Req->argv[Req->argc - 1], sizeof(mask)); + for (query = strtok(ngt_LowerStr(mask), ","); query && found < 3; query = strtok(NULL, ","), found++) { @@ -1150,11 +1201,11 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req ) * - no wildcards for remote clients * - only one wildcard target per local client * - * also, at most ten matches are returned. + * Also, at most MAX_RPL_WHOIS matches are returned. */ if (!has_wildcards || is_remote) { c = Client_Search(query); - if (c) { + if (c && Client_Type(c) == CLIENT_USER) { if (!IRC_WHOIS_SendReply(Client, from, c)) return DISCONNECTED; } else { @@ -1176,21 +1227,28 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req ) got_wildcard = true; IRC_SetPenalty(Client, 3); - for (c = Client_First(); c && match_count < 10; c = Client_Next(c)) { + for (c = Client_First(); c; c = Client_Next(c)) { + if (IRC_CheckListTooBig(Client, match_count, + MAX_RPL_WHOIS, "WHOIS")) + break; + if (Client_Type(c) != CLIENT_USER) continue; if (!MatchCaseInsensitive(query, Client_ID(c))) continue; if (!IRC_WHOIS_SendReply(Client, from, c)) return DISCONNECTED; + match_count++; } if (match_count == 0) - return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, - Client_ID(Client), Req->argv[Req->argc - 1]); + IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), + Req->argv[Req->argc - 1]); } - return CONNECTED; + return IRC_WriteStrClient(from, RPL_ENDOFWHOIS_MSG, + Client_ID(from), Req->argv[Req->argc - 1]); } /* IRC_WHOIS */ @@ -1272,11 +1330,11 @@ IRC_WHOWAS( CLIENT *Client, REQUEST *Req ) if (last < 0) last = 0; - max = DEFAULT_WHOWAS; + max = DEF_RPL_WHOWAS; if (Req->argc > 1) { max = atoi(Req->argv[1]); if (max < 1) - max = MAX_WHOWAS; + max = MAX_RPL_WHOWAS; } /* @@ -1534,7 +1592,8 @@ IRC_Send_ISUPPORT(CLIENT * Client) return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client), CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1, COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1, - COMMAND_LEN - 113); + COMMAND_LEN - 113, MAX_HNDL_MODES_ARG, + MAX_HNDL_CHANNEL_LISTS); } /* IRC_Send_ISUPPORT */