X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fchannel.c;h=e74cd6eb1dfcc4358668a1c5ec18ec040471d697;hp=59fe00229576d018900a600c548925fd4d9668cb;hb=10c7ba99e73b42ec8c4c191ccdae60bdd35bba7d;hpb=0d67be3f301e280225d8a04048ebb77a976d8169 diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c index 59fe0022..e74cd6eb 100644 --- a/src/ngircd/channel.c +++ b/src/ngircd/channel.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2014 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 @@ -18,41 +18,32 @@ * Channel management */ -#include "imp.h" #include #include #include #include #include #include +#include -#include "defines.h" #include "conn-func.h" -#include "exp.h" #include "channel.h" -#include "imp.h" #include "irc-write.h" #include "conf.h" #include "hash.h" -#include "lists.h" #include "log.h" #include "messages.h" #include "match.h" -#include "exp.h" - - #define REMOVE_PART 0 #define REMOVE_QUIT 1 #define REMOVE_KICK 2 - static CHANNEL *My_Channels; static CL2CHAN *My_Cl2Chan; - static CL2CHAN *Get_Cl2Chan PARAMS(( CHANNEL *Chan, CLIENT *Client )); static CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client )); static bool Remove_Client PARAMS(( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer )); @@ -131,11 +122,11 @@ Channel_InitPredefined( void ) new_chan = Channel_Create(conf_chan->name); if (!new_chan) { - Log(LOG_ERR, "Can't create pre-defined channel \"%s\"", + Log(LOG_ERR, "Can't create pre-defined channel \"%s\"!", conf_chan->name); continue; } - Log(LOG_INFO, "Created pre-defined channel \"%s\"", + Log(LOG_INFO, "Created pre-defined channel \"%s\".", conf_chan->name); Channel_ModeAdd(new_chan, 'P'); @@ -223,7 +214,7 @@ Channel_Join( CLIENT *Client, const char *Name ) /* Check that the channel name is valid */ if (! Channel_IsValidName(Name)) { - IRC_WriteStrClient(Client, ERR_NOSUCHCHANNEL_MSG, + IRC_WriteErrClient(Client, ERR_NOSUCHCHANNEL_MSG, Client_ID(Client), Name); return false; } @@ -268,14 +259,14 @@ Channel_Part(CLIENT * Client, CLIENT * Origin, const char *Name, const char *Rea /* Check that specified channel exists */ chan = Channel_Search(Name); if (!chan) { - IRC_WriteStrClient(Client, ERR_NOSUCHCHANNEL_MSG, + IRC_WriteErrClient(Client, ERR_NOSUCHCHANNEL_MSG, Client_ID(Client), Name); return false; } /* Check that the client is in the channel */ if (!Get_Cl2Chan(chan, Client)) { - IRC_WriteStrClient(Client, ERR_NOTONCHANNEL_MSG, + IRC_WriteErrClient(Client, ERR_NOTONCHANNEL_MSG, Client_ID(Client), Name); return false; } @@ -299,7 +290,6 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, const char *Reason ) { CHANNEL *chan; - char *ptr, *target_modes; bool can_kick = false; assert(Peer != NULL); @@ -310,9 +300,9 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, /* Check that channel exists */ chan = Channel_Search( Name ); - if( ! chan ) - { - IRC_WriteStrClient( Origin, ERR_NOSUCHCHANNEL_MSG, Client_ID( Origin ), Name ); + if (!chan) { + IRC_WriteErrClient(Origin, ERR_NOSUCHCHANNEL_MSG, + Client_ID(Origin), Name); return; } @@ -320,63 +310,68 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name, Client_Type(Origin) != CLIENT_SERVICE) { /* Check that user is on the specified channel */ if (!Channel_IsMemberOf(chan, Origin)) { - IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG, - Client_ID(Origin), Name); + IRC_WriteErrClient(Origin, ERR_NOTONCHANNEL_MSG, + Client_ID(Origin), Name); return; } } + /* Check that the client to be kicked is on the specified channel */ + if (!Channel_IsMemberOf(chan, Target)) { + IRC_WriteErrClient(Origin, ERR_USERNOTINCHANNEL_MSG, + Client_ID(Origin), Client_ID(Target), Name ); + return; + } + if(Client_Type(Peer) == CLIENT_USER) { - /* Check if client has the rights to kick target */ - ptr = Channel_UserModes(chan, Peer); - target_modes = Channel_UserModes(chan, Target); - while(*ptr) { - /* Owner can kick everyone */ - if ( *ptr == 'q') { - can_kick = true; - break; - } - /* Admin can't kick owner */ - if ( *ptr == 'a' ) { - if (!strchr(target_modes, 'q')) { - can_kick = true; - break; - } - } - /* Op can't kick owner | admin */ - if ( *ptr == 'o' ) { - if (!strchr(target_modes, 'q') && - !strchr(target_modes, 'a')) { - can_kick = true; - break; - } - } - /* Half Op can't kick owner | admin | op */ - if ( *ptr == 'h' ) { - if (!strchr(target_modes, 'q') && - !strchr(target_modes, 'a') && - !strchr(target_modes, 'o')) { - can_kick = true; - break; - } - } - ptr++; + /* Channel mode 'Q' and user mode 'q' on target: nobody but + * IRC Operators and servers can kick the target user */ + if ((Channel_HasMode(chan, 'Q') + || Client_HasMode(Target, 'q') + || Client_Type(Target) == CLIENT_SERVICE) + && !Client_HasMode(Origin, 'o')) { + IRC_WriteErrClient(Origin, ERR_KICKDENY_MSG, + Client_ID(Origin), Name, + Client_ID(Target)); + return; } + /* Check if client has the rights to kick target */ + + /* Owner can kick everyone */ + if (Channel_UserHasMode(chan, Peer, 'q')) + can_kick = true; + + /* Admin can't kick owner */ + else if (Channel_UserHasMode(chan, Peer, 'a') && + !Channel_UserHasMode(chan, Target, 'q')) + can_kick = true; + + /* Op can't kick owner | admin */ + else if (Channel_UserHasMode(chan, Peer, 'o') && + !Channel_UserHasMode(chan, Target, 'q') && + !Channel_UserHasMode(chan, Target, 'a')) + can_kick = true; + + /* Half Op can't kick owner | admin | op */ + else if (Channel_UserHasMode(chan, Peer, 'h') && + !Channel_UserHasMode(chan, Target, 'q') && + !Channel_UserHasMode(chan, Target, 'a') && + !Channel_UserHasMode(chan, Target, 'o')) + can_kick = true; + + /* IRC operators & IRCd with OperCanMode enabled + * can kick anyways regardless of privilege */ + else if(Client_HasMode(Origin, 'o') && Conf_OperCanMode) + can_kick = true; + if(!can_kick) { - IRC_WriteStrClient(Origin, ERR_CHANOPPRIVTOLOW_MSG, - Client_ID(Origin), Name); + IRC_WriteErrClient(Origin, ERR_CHANOPPRIVTOOLOW_MSG, + Client_ID(Origin), Name); return; } } - /* Check that the client to be kicked is on the specified channel */ - if (!Channel_IsMemberOf(chan, Target)) { - IRC_WriteStrClient(Origin, ERR_USERNOTINCHANNEL_MSG, - Client_ID(Origin), Client_ID(Target), Name ); - return; - } - /* Kick Client from channel */ Remove_Client( REMOVE_KICK, chan, Target, Origin, Reason, true); } /* Channel_Kick */ @@ -421,7 +416,7 @@ Channel_CountVisible (CLIENT *Client) c = My_Channels; while(c) { if (Client) { - if (!strchr(Channel_Modes(c), 's') + if (!Channel_HasMode(c, 's') || Channel_IsMemberOf(c, Client)) count++; } else @@ -487,6 +482,14 @@ Channel_Modes( CHANNEL *Chan ) } /* Channel_Modes */ +GLOBAL bool +Channel_HasMode( CHANNEL *Chan, char Mode ) +{ + assert( Chan != NULL ); + return strchr( Chan->modes, Mode ) != NULL; +} /* Channel_HasMode */ + + GLOBAL char * Channel_Key( CHANNEL *Chan ) { @@ -624,7 +627,7 @@ Channel_ModeAdd( CHANNEL *Chan, char Mode ) assert( Chan != NULL ); x[0] = Mode; x[1] = '\0'; - if( ! strchr( Chan->modes, x[0] )) + if( ! Channel_HasMode( Chan, x[0] )) { /* Channel does not have this mode yet, set it */ strlcat( Chan->modes, x, sizeof( Chan->modes )); @@ -733,6 +736,13 @@ Channel_UserModes( CHANNEL *Chan, CLIENT *Client ) } /* Channel_UserModes */ +GLOBAL bool +Channel_UserHasMode( CHANNEL *Chan, CLIENT *Client, char Mode ) +{ + return strchr(Channel_UserModes(Chan, Client), Mode) != NULL; +} /* Channel_UserHasMode */ + + GLOBAL bool Channel_IsMemberOf( CHANNEL *Chan, CLIENT *Client ) { @@ -861,15 +871,15 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From) if (Channel_IsMemberOf(Chan, From)) { is_member = true; - if (strchr(Channel_UserModes(Chan, From), 'v')) + if (Channel_UserHasMode(Chan, From, 'v')) has_voice = true; - if (strchr(Channel_UserModes(Chan, From), 'h')) + if (Channel_UserHasMode(Chan, From, 'h')) is_halfop = true; - if (strchr(Channel_UserModes(Chan, From), 'o')) + if (Channel_UserHasMode(Chan, From, 'o')) is_op = true; - if (strchr(Channel_UserModes(Chan, From), 'a')) + if (Channel_UserHasMode(Chan, From, 'a')) is_chanadmin = true; - if (strchr(Channel_UserModes(Chan, From), 'q')) + if (Channel_UserHasMode(Chan, From, 'q')) is_owner = true; } @@ -879,17 +889,17 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From) * If channel mode n set: non-members cannot send to channel. * If channel mode m set: need voice. */ - if (strchr(Channel_Modes(Chan), 'n') && !is_member) + if (Channel_HasMode(Chan, 'n') && !is_member) return false; - if (strchr(Channel_Modes(Chan), 'M') && !Client_HasMode(From, 'R') + if (Channel_HasMode(Chan, 'M') && !Client_HasMode(From, 'R') && !Client_HasMode(From, 'o')) return false; if (has_voice || is_halfop || is_op || is_chanadmin || is_owner) return true; - if (strchr(Channel_Modes(Chan), 'm')) + if (Channel_HasMode(Chan, 'm')) return false; if (Lists_Check(&Chan->list_excepts, From)) @@ -906,15 +916,20 @@ Channel_Write(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Command, if (!Can_Send_To_Channel(Chan, From)) { if (! SendErrors) return CONNECTED; /* no error, see RFC 2812 */ - return IRC_WriteStrClient(From, ERR_CANNOTSENDTOCHAN_MSG, + if (Channel_HasMode(Chan, 'M')) + return IRC_WriteErrClient(From, ERR_NEEDREGGEDNICK_MSG, + Client_ID(From), Channel_Name(Chan)); + else + return IRC_WriteErrClient(From, ERR_CANNOTSENDTOCHAN_MSG, Client_ID(From), Channel_Name(Chan)); } if (Client_Conn(From) > NONE) Conn_UpdateIdle(Client_Conn(From)); - return IRC_WriteStrChannelPrefix(Client, Chan, From, true, - "%s %s :%s", Command, Channel_Name(Chan), Text); + IRC_WriteStrChannelPrefix(Client, Chan, From, true, "%s %s :%s", + Command, Channel_Name(Chan), Text); + return CONNECTED; } @@ -1073,7 +1088,7 @@ Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const ch } /* When channel is empty and is not pre-defined, delete */ - if( ! strchr( Channel_Modes( Chan ), 'P' )) + if( ! Channel_HasMode( Chan, 'P' )) { if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan ); } @@ -1201,7 +1216,7 @@ Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key) assert(Client != NULL); assert(Key != NULL); - if (!strchr(Chan->modes, 'k')) + if (!Channel_HasMode(Chan, 'k')) return true; if (*Key == '\0') return false;