diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index e49e5a9a..c8c15d96 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2011 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 @@ -1119,6 +1119,64 @@ Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key) } /* Channel_CheckKey */ +/** + * Check wether a client is allowed to administer a channel or not. + * + * @param Chan The channel to test. + * @param Client The client from which the command has been received. + * @param Origin The originator of the command (or NULL). + * @param OnChannel Set to true if the originator is member of the channel. + * @param AdminOk Set to true if the client is allowed to do + * administrative tasks on this channel. + * @param UseServerMode Set to true if ngIRCd should emulate "server mode", + * that is send commands as if originating from a server + * and not the originator of the command. + */ +GLOBAL void +Channel_CheckAdminRights(CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, + bool *OnChannel, bool *AdminOk, bool *UseServerMode) +{ + assert (Chan != NULL); + assert (Client != NULL); + assert (OnChannel != NULL); + assert (AdminOk != NULL); + assert (UseServerMode != NULL); + + /* Use the client as origin, if no origin has been given (no prefix?) */ + if (!Origin) + Origin = Client; + + *OnChannel = false; + *AdminOk = false; + *UseServerMode = false; + + if (Client_Type(Client) != CLIENT_USER + && Client_Type(Client) != CLIENT_SERVER + && Client_Type(Client) != CLIENT_SERVICE) + return; + + /* Allow channel administration if the client is a server or service */ + if (Client_Type(Client) != CLIENT_USER) { + *AdminOk = true; + return; + } + + *OnChannel = Channel_IsMemberOf(Chan, Origin); + + if (*OnChannel && strchr(Channel_UserModes(Chan, Origin), 'o')) { + /* User is a channel operator */ + *AdminOk = true; + } else if (Conf_OperCanMode) { + /* IRC operators are allowed to administer channels as well */ + if (Client_OperByMe(Origin)) { + *AdminOk = true; + if (Conf_OperServerMode) + *UseServerMode = true; + } + } +} /* Channel_CheckAdminRights */ + + static CL2CHAN * Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan ) { diff --git a/src/ngircd/channel.h b/src/ngircd/channel.h index 030f9109..b912aab4 100644 --- a/src/ngircd/channel.h +++ b/src/ngircd/channel.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 by Alexander Barton (alex@barton.de) + * Copyright (c)2001-2011 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 @@ -133,6 +133,10 @@ GLOBAL void Channel_LogServer PARAMS((const char *msg)); GLOBAL bool Channel_CheckKey PARAMS((CHANNEL *Chan, CLIENT *Client, const char *Key)); +GLOBAL void Channel_CheckAdminRights PARAMS((CHANNEL *Chan, CLIENT *Client, + CLIENT *Origin, bool *OnChannel, + bool *AdminOk, bool *UseServerMode)); + #define Channel_IsLocal(c) (Channel_Name(c)[0] == '&') #define Channel_IsModeless(c) (Channel_Name(c)[0] == '+') diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c index a4c1d89b..1e6772a6 100644 --- a/src/ngircd/irc-mode.c +++ b/src/ngircd/irc-mode.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2011 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 @@ -316,8 +316,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) { char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], argadd[CLIENT_PASS_LEN], *mode_ptr; - bool connected, set, skiponce, retval, onchannel; - bool modeok = true, use_servermode = false; + bool connected, set, skiponce, retval, onchannel, modeok, use_servermode; int mode_arg, arg_arg; CLIENT *client; long l; @@ -331,28 +330,13 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel) if (Req->argc <= 1) return Channel_Mode_Answer_Request(Origin, Channel); - /* Is the user allowed to change modes? */ - if (Client_Type(Client) == CLIENT_USER) { - /* Is the originating user on that channel? */ - onchannel = Channel_IsMemberOf(Channel, Origin); - modeok = false; - /* channel operator? */ - if (onchannel && - strchr(Channel_UserModes(Channel, Origin), 'o')) { - modeok = true; - } else if (Conf_OperCanMode) { - /* IRC-Operators can use MODE as well */ - if (Client_OperByMe(Origin)) { - modeok = true; - if (Conf_OperServerMode) - use_servermode = true; /* Change Origin to Server */ - } - } + Channel_CheckAdminRights(Channel, Client, Origin, + &onchannel, &modeok, &use_servermode); - if (!onchannel && !modeok) - return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG, - Client_ID(Origin), Channel_Name(Channel)); - } + if (!onchannel && !modeok) + return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG, + Client_ID(Origin), + Channel_Name(Channel)); mode_arg = 1; mode_ptr = Req->argv[mode_arg];