Implemented xop support
3 new channel user modes have been added. Half Op: +h(Prefix: %) can set the channel modes +imntvIbek and kick all +v and normal users. Admin: +a(Prefix: &) can set channel modes +imntvIbekoRsz and kick all +o, +h, +v and normal users. Owner: +q(Prefix: ~) can set channel modes +imntvIbekoRsz and kick all +a, +o, +h, +v and normal users
This commit is contained in:
parent
d0bb185cf5
commit
7b01bb833f
|
@ -1 +1,2 @@
|
||||||
sample-ngircd.conf
|
sample-ngircd.conf
|
||||||
|
Add_Modes.txt
|
||||||
|
|
|
@ -294,6 +294,8 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name,
|
||||||
const char *Reason )
|
const char *Reason )
|
||||||
{
|
{
|
||||||
CHANNEL *chan;
|
CHANNEL *chan;
|
||||||
|
char *ptr, *target_modes;
|
||||||
|
bool can_kick = false;
|
||||||
|
|
||||||
assert(Peer != NULL);
|
assert(Peer != NULL);
|
||||||
assert(Target != NULL);
|
assert(Target != NULL);
|
||||||
|
@ -317,10 +319,47 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name,
|
||||||
Client_ID(Origin), Name);
|
Client_ID(Origin), Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if user has operator status */
|
if(Client_Type(Peer) == CLIENT_USER) {
|
||||||
if (!strchr(Channel_UserModes(chan, Origin), 'o')) {
|
/* Check if client has the rights to kick target */
|
||||||
IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG,
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!can_kick) {
|
||||||
|
IRC_WriteStrClient(Origin, ERR_CHANOPPRIVTOLOW_MSG,
|
||||||
Client_ID(Origin), Name);
|
Client_ID(Origin), Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -807,9 +846,9 @@ Channel_SetMaxUsers(CHANNEL *Chan, unsigned long Count)
|
||||||
static bool
|
static bool
|
||||||
Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
|
Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
|
||||||
{
|
{
|
||||||
bool is_member, has_voice, is_op;
|
bool is_member, has_voice, is_halfop, is_op, is_chanadmin, is_owner;
|
||||||
|
|
||||||
is_member = has_voice = is_op = false;
|
is_member = has_voice = is_halfop = is_op = is_chanadmin = is_owner = false;
|
||||||
|
|
||||||
/* The server itself always can send messages :-) */
|
/* The server itself always can send messages :-) */
|
||||||
if (Client_ThisServer() == From)
|
if (Client_ThisServer() == From)
|
||||||
|
@ -819,8 +858,14 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
|
||||||
is_member = true;
|
is_member = true;
|
||||||
if (strchr(Channel_UserModes(Chan, From), 'v'))
|
if (strchr(Channel_UserModes(Chan, From), 'v'))
|
||||||
has_voice = true;
|
has_voice = true;
|
||||||
|
if (strchr(Channel_UserModes(Chan, From), 'h'))
|
||||||
|
is_halfop = true;
|
||||||
if (strchr(Channel_UserModes(Chan, From), 'o'))
|
if (strchr(Channel_UserModes(Chan, From), 'o'))
|
||||||
is_op = true;
|
is_op = true;
|
||||||
|
if (strchr(Channel_UserModes(Chan, From), 'a'))
|
||||||
|
is_chanadmin = true;
|
||||||
|
if (strchr(Channel_UserModes(Chan, From), 'q'))
|
||||||
|
is_owner = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -832,7 +877,7 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
|
||||||
if (strchr(Channel_Modes(Chan), 'n') && !is_member)
|
if (strchr(Channel_Modes(Chan), 'n') && !is_member)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (is_op || has_voice)
|
if (has_voice || is_halfop || is_op || is_chanadmin || is_owner)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (strchr(Channel_Modes(Chan), 'm'))
|
if (strchr(Channel_Modes(Chan), 'm'))
|
||||||
|
@ -1187,64 +1232,6 @@ Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key)
|
||||||
} /* Channel_CheckKey */
|
} /* 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 *
|
static CL2CHAN *
|
||||||
Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
|
Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
|
||||||
{
|
{
|
||||||
|
|
|
@ -164,7 +164,7 @@
|
||||||
#define USERMODES "acCiorRswx"
|
#define USERMODES "acCiorRswx"
|
||||||
|
|
||||||
/** Supported channel modes. */
|
/** Supported channel modes. */
|
||||||
#define CHANMODES "beiIklmnoOPrRstvz"
|
#define CHANMODES "abehiIklmnoOPqrRstvz"
|
||||||
|
|
||||||
/** Away message for users connected to linked servers. */
|
/** Away message for users connected to linked servers. */
|
||||||
#define DEFAULT_AWAY_MSG "Away"
|
#define DEFAULT_AWAY_MSG "Away"
|
||||||
|
|
|
@ -510,7 +510,7 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
|
||||||
CHANNEL *chan;
|
CHANNEL *chan;
|
||||||
CLIENT *from;
|
CLIENT *from;
|
||||||
char *topic;
|
char *topic;
|
||||||
bool onchannel, topicok, use_servermode, r;
|
bool r, is_oper;
|
||||||
|
|
||||||
assert( Client != NULL );
|
assert( Client != NULL );
|
||||||
assert( Req != NULL );
|
assert( Req != NULL );
|
||||||
|
@ -533,10 +533,9 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
|
||||||
return IRC_WriteStrClient(from, ERR_NOSUCHCHANNEL_MSG,
|
return IRC_WriteStrClient(from, ERR_NOSUCHCHANNEL_MSG,
|
||||||
Client_ID(from), Req->argv[0]);
|
Client_ID(from), Req->argv[0]);
|
||||||
|
|
||||||
Channel_CheckAdminRights(chan, Client, from,
|
/* Only IRC opers and channel members allowed */
|
||||||
&onchannel, &topicok, &use_servermode);
|
is_oper = Client_OperByMe(from);
|
||||||
|
if (!Channel_IsMemberOf(chan, from) && !is_oper)
|
||||||
if (!onchannel && !topicok)
|
|
||||||
return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG,
|
return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG,
|
||||||
Client_ID(from), Req->argv[0]);
|
Client_ID(from), Req->argv[0]);
|
||||||
|
|
||||||
|
@ -565,8 +564,12 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strchr(Channel_Modes(chan), 't')) {
|
if (strchr(Channel_Modes(chan), 't')) {
|
||||||
/* Topic Lock. Is the user a channel or IRC operator? */
|
/* Topic Lock. Is the user a channel op or IRC operator? */
|
||||||
if (!topicok)
|
if(!strchr(Channel_UserModes(chan, from), 'h') &&
|
||||||
|
!strchr(Channel_UserModes(chan, from), 'o') &&
|
||||||
|
!strchr(Channel_UserModes(chan, from), 'a') &&
|
||||||
|
!strchr(Channel_UserModes(chan, from), 'q') &&
|
||||||
|
!is_oper)
|
||||||
return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
|
return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
|
||||||
Client_ID(from),
|
Client_ID(from),
|
||||||
Channel_Name(chan));
|
Channel_Name(chan));
|
||||||
|
@ -578,7 +581,7 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
|
||||||
Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
|
Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
|
||||||
Req->argv[1][0] ? Req->argv[1] : "<none>");
|
Req->argv[1][0] ? Req->argv[1] : "<none>");
|
||||||
|
|
||||||
if (use_servermode)
|
if (Conf_OperServerMode)
|
||||||
from = Client_ThisServer();
|
from = Client_ThisServer();
|
||||||
|
|
||||||
/* Update channel and forward new topic to other servers */
|
/* Update channel and forward new topic to other servers */
|
||||||
|
|
|
@ -807,22 +807,38 @@ who_flags_status(const char *client_modes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *
|
static char *
|
||||||
who_flags_qualifier(CLIENT *Client, const char *chan_user_modes)
|
who_flags_qualifier(CLIENT *Client, const char *chan_user_modes, char *str, size_t len)
|
||||||
{
|
{
|
||||||
assert(Client != NULL);
|
assert(Client != NULL);
|
||||||
|
|
||||||
if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
|
if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
|
||||||
if (strchr(chan_user_modes, 'o') &&
|
if (strchr(chan_user_modes, 'q'))
|
||||||
strchr(chan_user_modes, 'v'))
|
strlcat(str, "~", len);
|
||||||
return "@+";
|
if (strchr(chan_user_modes, 'a'))
|
||||||
|
strlcat(str, "&", len);
|
||||||
|
if (strchr(chan_user_modes, 'o'))
|
||||||
|
strlcat(str, "@", len);
|
||||||
|
if (strchr(chan_user_modes, 'h'))
|
||||||
|
strlcat(str, "&", len);
|
||||||
|
if (strchr(chan_user_modes, 'v'))
|
||||||
|
strlcat(str, "+", len);
|
||||||
|
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strchr(chan_user_modes, 'o'))
|
if (strchr(chan_user_modes, 'q'))
|
||||||
return "@";
|
strlcat(str, "~", len);
|
||||||
|
else if (strchr(chan_user_modes, 'a'))
|
||||||
|
strlcat(str, "&", len);
|
||||||
|
else if (strchr(chan_user_modes, 'o'))
|
||||||
|
strlcat(str, "@", len);
|
||||||
|
else if (strchr(chan_user_modes, 'h'))
|
||||||
|
strlcat(str, "%", len);
|
||||||
else if (strchr(chan_user_modes, 'v'))
|
else if (strchr(chan_user_modes, 'v'))
|
||||||
return "+";
|
strlcat(str, "+", len);
|
||||||
return "";
|
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -841,7 +857,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
|
||||||
CL2CHAN *cl2chan;
|
CL2CHAN *cl2chan;
|
||||||
const char *client_modes;
|
const char *client_modes;
|
||||||
const char *chan_user_modes;
|
const char *chan_user_modes;
|
||||||
char flags[8];
|
char flags[10];
|
||||||
CLIENT *c;
|
CLIENT *c;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
@ -874,8 +890,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
|
||||||
strlcat(flags, "*", sizeof(flags));
|
strlcat(flags, "*", sizeof(flags));
|
||||||
|
|
||||||
chan_user_modes = Channel_UserModes(Chan, c);
|
chan_user_modes = Channel_UserModes(Chan, c);
|
||||||
strlcat(flags, who_flags_qualifier(c, chan_user_modes),
|
who_flags_qualifier(c, chan_user_modes, flags, sizeof(flags));
|
||||||
sizeof(flags));
|
|
||||||
|
|
||||||
if (!write_whoreply(Client, c, Channel_Name(Chan),
|
if (!write_whoreply(Client, c, Channel_Name(Chan),
|
||||||
flags))
|
flags))
|
||||||
|
@ -1087,8 +1102,7 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
|
||||||
if (str[strlen(str) - 1] != ':')
|
if (str[strlen(str) - 1] != ':')
|
||||||
strlcat(str, " ", sizeof(str));
|
strlcat(str, " ", sizeof(str));
|
||||||
|
|
||||||
strlcat(str, who_flags_qualifier(c, Channel_UserModes(chan, c)),
|
who_flags_qualifier(c, Channel_UserModes(chan, c), str, sizeof(str));
|
||||||
sizeof(str));
|
|
||||||
strlcat(str, Channel_Name(chan), sizeof(str));
|
strlcat(str, Channel_Name(chan), sizeof(str));
|
||||||
|
|
||||||
if (strlen(str) > (LINE_LEN - CHANNEL_NAME_LEN - 4)) {
|
if (strlen(str) > (LINE_LEN - CHANNEL_NAME_LEN - 4)) {
|
||||||
|
@ -1578,16 +1592,8 @@ IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
|
||||||
if (is_member || is_visible) {
|
if (is_member || is_visible) {
|
||||||
if (str[strlen(str) - 1] != ':')
|
if (str[strlen(str) - 1] != ':')
|
||||||
strlcat(str, " ", sizeof(str));
|
strlcat(str, " ", sizeof(str));
|
||||||
if (Client_Cap(cl) & CLIENT_CAP_MULTI_PREFIX) {
|
|
||||||
if (strchr(Channel_UserModes(Chan, cl), 'o') &&
|
who_flags_qualifier(cl, Channel_UserModes(Chan, cl), str, sizeof(str));
|
||||||
strchr(Channel_UserModes(Chan, cl), 'v'))
|
|
||||||
strlcat(str, "@+", sizeof(str));
|
|
||||||
} else {
|
|
||||||
if (strchr(Channel_UserModes(Chan, cl), 'o'))
|
|
||||||
strlcat(str, "@", sizeof(str));
|
|
||||||
else if (strchr(Channel_UserModes(Chan, cl), 'v'))
|
|
||||||
strlcat(str, "+", sizeof(str));
|
|
||||||
}
|
|
||||||
strlcat(str, Client_ID(cl), sizeof(str));
|
strlcat(str, Client_ID(cl), sizeof(str));
|
||||||
|
|
||||||
if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) {
|
if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) {
|
||||||
|
|
|
@ -396,13 +396,16 @@ static bool
|
||||||
Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
{
|
{
|
||||||
char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
|
char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
|
||||||
argadd[CLIENT_PASS_LEN], *mode_ptr;
|
argadd[CLIENT_PASS_LEN], *mode_ptr, *o_mode_ptr;
|
||||||
bool connected, set, skiponce, retval, onchannel, modeok, use_servermode;
|
bool connected, set, skiponce, retval, use_servermode,
|
||||||
|
is_halfop, is_op, is_admin, is_owner, is_machine, is_oper;
|
||||||
int mode_arg, arg_arg, mode_arg_count = 0;
|
int mode_arg, arg_arg, mode_arg_count = 0;
|
||||||
CLIENT *client;
|
CLIENT *client;
|
||||||
long l;
|
long l;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false;
|
||||||
|
|
||||||
if (Channel_IsModeless(Channel))
|
if (Channel_IsModeless(Channel))
|
||||||
return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG,
|
return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG,
|
||||||
Client_ID(Client), Channel_Name(Channel));
|
Client_ID(Client), Channel_Name(Channel));
|
||||||
|
@ -411,10 +414,20 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
if (Req->argc <= 1)
|
if (Req->argc <= 1)
|
||||||
return Channel_Mode_Answer_Request(Origin, Channel);
|
return Channel_Mode_Answer_Request(Origin, Channel);
|
||||||
|
|
||||||
Channel_CheckAdminRights(Channel, Client, Origin,
|
/* Check if origin is oper and opers can use mode */
|
||||||
&onchannel, &modeok, &use_servermode);
|
use_servermode = Conf_OperServerMode;
|
||||||
|
if(Client_OperByMe(Client) && Conf_OperCanMode) {
|
||||||
|
is_oper = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!onchannel && !modeok)
|
/* Check if client is a server/service */
|
||||||
|
if(Client_Type(Client) == CLIENT_SERVER ||
|
||||||
|
Client_Type(Client) == CLIENT_SERVICE) {
|
||||||
|
is_machine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if client is member of channel or an oper or an server/service */
|
||||||
|
if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine)
|
||||||
return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
|
return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
|
||||||
Client_ID(Origin),
|
Client_ID(Origin),
|
||||||
Channel_Name(Channel));
|
Channel_Name(Channel));
|
||||||
|
@ -493,20 +506,43 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
if (arg_arg >= Req->argc)
|
if (arg_arg >= Req->argc)
|
||||||
arg_arg = -1;
|
arg_arg = -1;
|
||||||
|
|
||||||
|
if(!is_machine) {
|
||||||
|
o_mode_ptr = Channel_UserModes(Channel, Client);
|
||||||
|
while( *o_mode_ptr ) {
|
||||||
|
if ( *o_mode_ptr == 'q')
|
||||||
|
is_owner = true;
|
||||||
|
if ( *o_mode_ptr == 'a')
|
||||||
|
is_admin = true;
|
||||||
|
if ( *o_mode_ptr == 'o')
|
||||||
|
is_op = true;
|
||||||
|
if ( *o_mode_ptr == 'h')
|
||||||
|
is_halfop = true;
|
||||||
|
o_mode_ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Validate modes */
|
/* Validate modes */
|
||||||
x[0] = '\0';
|
x[0] = '\0';
|
||||||
argadd[0] = '\0';
|
argadd[0] = '\0';
|
||||||
client = NULL;
|
client = NULL;
|
||||||
switch (*mode_ptr) {
|
switch (*mode_ptr) {
|
||||||
/* --- Channel modes --- */
|
/* --- Channel modes --- */
|
||||||
|
case 'R': /* Registered users only */
|
||||||
|
case 's': /* Secret channel */
|
||||||
|
case 'z': /* Secure connections only */
|
||||||
|
if(!is_oper && !is_machine && !is_owner &&
|
||||||
|
!is_admin && !is_op) {
|
||||||
|
connected = IRC_WriteStrClient(Origin,
|
||||||
|
ERR_CHANOPRIVSNEEDED_MSG,
|
||||||
|
Client_ID(Origin), Channel_Name(Channel));
|
||||||
|
goto chan_exit;
|
||||||
|
}
|
||||||
case 'i': /* Invite only */
|
case 'i': /* Invite only */
|
||||||
case 'm': /* Moderated */
|
case 'm': /* Moderated */
|
||||||
case 'n': /* Only members can write */
|
case 'n': /* Only members can write */
|
||||||
case 'R': /* Registered users only */
|
|
||||||
case 's': /* Secret channel */
|
|
||||||
case 't': /* Topic locked */
|
case 't': /* Topic locked */
|
||||||
case 'z': /* Secure connections only */
|
if(is_oper || is_machine || is_owner ||
|
||||||
if (modeok)
|
is_admin || is_op || is_halfop)
|
||||||
x[0] = *mode_ptr;
|
x[0] = *mode_ptr;
|
||||||
else
|
else
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
|
@ -517,7 +553,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
if (Mode_Limit_Reached(Client, mode_arg_count++))
|
if (Mode_Limit_Reached(Client, mode_arg_count++))
|
||||||
goto chan_exit;
|
goto chan_exit;
|
||||||
if (!set) {
|
if (!set) {
|
||||||
if (modeok)
|
if (is_oper || is_machine || is_owner ||
|
||||||
|
is_admin || is_op || is_halfop)
|
||||||
x[0] = *mode_ptr;
|
x[0] = *mode_ptr;
|
||||||
else
|
else
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
|
@ -527,7 +564,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (arg_arg > mode_arg) {
|
if (arg_arg > mode_arg) {
|
||||||
if (modeok) {
|
if (is_oper || is_machine || is_owner ||
|
||||||
|
is_admin || is_op || is_halfop) {
|
||||||
Channel_ModeDel(Channel, 'k');
|
Channel_ModeDel(Channel, 'k');
|
||||||
Channel_SetKey(Channel,
|
Channel_SetKey(Channel,
|
||||||
Req->argv[arg_arg]);
|
Req->argv[arg_arg]);
|
||||||
|
@ -553,7 +591,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
if (Mode_Limit_Reached(Client, mode_arg_count++))
|
if (Mode_Limit_Reached(Client, mode_arg_count++))
|
||||||
goto chan_exit;
|
goto chan_exit;
|
||||||
if (!set) {
|
if (!set) {
|
||||||
if (modeok)
|
if (is_oper || is_machine || is_owner ||
|
||||||
|
is_admin || is_op || is_halfop)
|
||||||
x[0] = *mode_ptr;
|
x[0] = *mode_ptr;
|
||||||
else
|
else
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
|
@ -563,7 +602,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (arg_arg > mode_arg) {
|
if (arg_arg > mode_arg) {
|
||||||
if (modeok) {
|
if (is_oper || is_machine || is_owner ||
|
||||||
|
is_admin || is_op || is_halfop) {
|
||||||
l = atol(Req->argv[arg_arg]);
|
l = atol(Req->argv[arg_arg]);
|
||||||
if (l > 0 && l < 0xFFFF) {
|
if (l > 0 && l < 0xFFFF) {
|
||||||
Channel_ModeDel(Channel, 'l');
|
Channel_ModeDel(Channel, 'l');
|
||||||
|
@ -588,44 +628,47 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'O': /* IRC operators only */
|
case 'O': /* IRC operators only */
|
||||||
if (modeok) {
|
if (set) {
|
||||||
/* Only IRC operators are allowed to
|
/* Only IRC operators are allowed to
|
||||||
* set the 'O' channel mode! */
|
* set the 'O' channel mode! */
|
||||||
if (set && !(Client_OperByMe(Client)
|
if(is_oper || is_machine)
|
||||||
|| Client_Type(Client) == CLIENT_SERVER))
|
x[0] = 'O';
|
||||||
|
else
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
ERR_NOPRIVILEGES_MSG,
|
ERR_NOPRIVILEGES_MSG,
|
||||||
Client_ID(Origin));
|
Client_ID(Origin));
|
||||||
else
|
} else if(is_oper || is_machine || is_owner ||
|
||||||
|
is_admin || is_op)
|
||||||
x[0] = 'O';
|
x[0] = 'O';
|
||||||
} else
|
else
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
ERR_CHANOPRIVSNEEDED_MSG,
|
ERR_CHANOPRIVSNEEDED_MSG,
|
||||||
Client_ID(Origin),
|
Client_ID(Origin),
|
||||||
Channel_Name(Channel));
|
Channel_Name(Channel));
|
||||||
break;
|
break;
|
||||||
case 'P': /* Persistent channel */
|
case 'P': /* Persistent channel */
|
||||||
if (modeok) {
|
if (set) {
|
||||||
/* Only IRC operators are allowed to
|
/* Only IRC operators are allowed to
|
||||||
* set the 'P' channel mode! */
|
* set the 'P' channel mode! */
|
||||||
if (set && !(Client_OperByMe(Client)
|
if(is_oper || is_machine)
|
||||||
|| Client_Type(Client) == CLIENT_SERVER))
|
x[0] = 'P';
|
||||||
|
else
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
ERR_NOPRIVILEGES_MSG,
|
ERR_NOPRIVILEGES_MSG,
|
||||||
Client_ID(Origin));
|
Client_ID(Origin));
|
||||||
else
|
} else if(is_oper || is_machine || is_owner ||
|
||||||
|
is_admin || is_op)
|
||||||
x[0] = 'P';
|
x[0] = 'P';
|
||||||
} else
|
else
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
ERR_CHANOPRIVSNEEDED_MSG,
|
ERR_CHANOPRIVSNEEDED_MSG,
|
||||||
Client_ID(Origin),
|
Client_ID(Origin),
|
||||||
Channel_Name(Channel));
|
Channel_Name(Channel));
|
||||||
break;
|
break;
|
||||||
/* --- Channel user modes --- */
|
/* --- Channel user modes --- */
|
||||||
case 'a':
|
case 'q': /* Owner */
|
||||||
case 'h':
|
case 'a': /* Channel admin */
|
||||||
case 'q':
|
if(!is_oper && !is_machine && !is_owner) {
|
||||||
if (Client_Type(Client) != CLIENT_SERVER) {
|
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
ERR_CHANOPRIVSNEEDED_MSG,
|
ERR_CHANOPRIVSNEEDED_MSG,
|
||||||
Client_ID(Origin),
|
Client_ID(Origin),
|
||||||
|
@ -633,16 +676,34 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
goto chan_exit;
|
goto chan_exit;
|
||||||
}
|
}
|
||||||
case 'o': /* Channel operator */
|
case 'o': /* Channel operator */
|
||||||
|
if(!is_oper && !is_machine && !is_owner &&
|
||||||
|
!is_admin && !is_op) {
|
||||||
|
connected = IRC_WriteStrClient(Origin,
|
||||||
|
ERR_CHANOPRIVSNEEDED_MSG,
|
||||||
|
Client_ID(Origin),
|
||||||
|
Channel_Name(Channel));
|
||||||
|
goto chan_exit;
|
||||||
|
}
|
||||||
|
case 'h': /* Half Op */
|
||||||
|
if(!is_oper && !is_machine && !is_owner &&
|
||||||
|
!is_admin && !is_op) {
|
||||||
|
connected = IRC_WriteStrClient(Origin,
|
||||||
|
ERR_CHANOPRIVSNEEDED_MSG,
|
||||||
|
Client_ID(Origin),
|
||||||
|
Channel_Name(Channel));
|
||||||
|
goto chan_exit;
|
||||||
|
}
|
||||||
case 'v': /* Voice */
|
case 'v': /* Voice */
|
||||||
if (arg_arg > mode_arg) {
|
if (arg_arg > mode_arg) {
|
||||||
if (modeok) {
|
if (is_oper || is_machine || is_owner ||
|
||||||
|
is_admin || is_op || is_halfop) {
|
||||||
client = Client_Search(Req->argv[arg_arg]);
|
client = Client_Search(Req->argv[arg_arg]);
|
||||||
if (client)
|
if (client)
|
||||||
x[0] = *mode_ptr;
|
x[0] = *mode_ptr;
|
||||||
else
|
else
|
||||||
connected = IRC_WriteStrClient(Client,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
ERR_NOSUCHNICK_MSG,
|
ERR_NOSUCHNICK_MSG,
|
||||||
Client_ID(Client),
|
Client_ID(Origin),
|
||||||
Req->argv[arg_arg]);
|
Req->argv[arg_arg]);
|
||||||
} else {
|
} else {
|
||||||
connected = IRC_WriteStrClient(Origin,
|
connected = IRC_WriteStrClient(Origin,
|
||||||
|
@ -667,7 +728,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
|
||||||
goto chan_exit;
|
goto chan_exit;
|
||||||
if (arg_arg > mode_arg) {
|
if (arg_arg > mode_arg) {
|
||||||
/* modify list */
|
/* modify list */
|
||||||
if (modeok) {
|
if (is_oper || is_machine || is_owner ||
|
||||||
|
is_admin || is_op || is_halfop) {
|
||||||
connected = set
|
connected = set
|
||||||
? Add_To_List(*mode_ptr, Origin,
|
? Add_To_List(*mode_ptr, Origin,
|
||||||
Client, Channel,
|
Client, Channel,
|
||||||
|
|
|
@ -166,8 +166,11 @@ IRC_INVITE(CLIENT *Client, REQUEST *Req)
|
||||||
|
|
||||||
/* Is the channel "invite-only"? */
|
/* Is the channel "invite-only"? */
|
||||||
if (strchr(Channel_Modes(chan), 'i')) {
|
if (strchr(Channel_Modes(chan), 'i')) {
|
||||||
/* Yes. The user must be channel operator! */
|
/* Yes. The user must be channel owner/admin/operator/halfop! */
|
||||||
if (!strchr(Channel_UserModes(chan, from), 'o'))
|
if (!strchr(Channel_UserModes(chan, from), 'q') &&
|
||||||
|
!strchr(Channel_UserModes(chan, from), 'a') &&
|
||||||
|
!strchr(Channel_UserModes(chan, from), 'o') &&
|
||||||
|
!strchr(Channel_UserModes(chan, from), 'h'))
|
||||||
return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
|
return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
|
||||||
Client_ID(from), Channel_Name(chan));
|
Client_ID(from), Channel_Name(chan));
|
||||||
remember = true;
|
remember = true;
|
||||||
|
|
|
@ -202,7 +202,7 @@ GLOBAL bool
|
||||||
IRC_NJOIN( CLIENT *Client, REQUEST *Req )
|
IRC_NJOIN( CLIENT *Client, REQUEST *Req )
|
||||||
{
|
{
|
||||||
char nick_in[COMMAND_LEN], nick_out[COMMAND_LEN], *channame, *ptr, modes[8];
|
char nick_in[COMMAND_LEN], nick_out[COMMAND_LEN], *channame, *ptr, modes[8];
|
||||||
bool is_op, is_voiced;
|
bool is_owner, is_chanadmin, is_op, is_halfop, is_voiced;
|
||||||
CHANNEL *chan;
|
CHANNEL *chan;
|
||||||
CLIENT *c;
|
CLIENT *c;
|
||||||
|
|
||||||
|
@ -221,9 +221,13 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
|
||||||
is_op = is_voiced = false;
|
is_op = is_voiced = false;
|
||||||
|
|
||||||
/* cut off prefixes */
|
/* cut off prefixes */
|
||||||
while(( *ptr == '@' ) || ( *ptr == '+' ))
|
while(( *ptr == '~') || ( *ptr == '&' ) || ( *ptr == '@' ) ||
|
||||||
|
( *ptr == '%') || ( *ptr == '+' ))
|
||||||
{
|
{
|
||||||
|
if( *ptr == '~' ) is_owner = true;
|
||||||
|
if( *ptr == '&' ) is_chanadmin = true;
|
||||||
if( *ptr == '@' ) is_op = true;
|
if( *ptr == '@' ) is_op = true;
|
||||||
|
if( *ptr == 'h' ) is_halfop = true;
|
||||||
if( *ptr == '+' ) is_voiced = true;
|
if( *ptr == '+' ) is_voiced = true;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
@ -235,7 +239,10 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
|
||||||
chan = Channel_Search( channame );
|
chan = Channel_Search( channame );
|
||||||
assert( chan != NULL );
|
assert( chan != NULL );
|
||||||
|
|
||||||
|
if( is_owner ) Channel_UserModeAdd( chan, c, 'q' );
|
||||||
|
if( is_chanadmin ) Channel_UserModeAdd( chan, c, 'a' );
|
||||||
if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
|
if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
|
||||||
|
if( is_halfop ) Channel_UserModeAdd( chan, c, 'h' );
|
||||||
if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );
|
if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );
|
||||||
|
|
||||||
/* announce to channel... */
|
/* announce to channel... */
|
||||||
|
@ -250,7 +257,10 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out ));
|
if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out ));
|
||||||
|
if( is_owner ) strlcat( nick_out, "~", sizeof( nick_out ));
|
||||||
|
if( is_chanadmin ) strlcat( nick_out, "&", sizeof( nick_out ));
|
||||||
if( is_op ) strlcat( nick_out, "@", sizeof( nick_out ));
|
if( is_op ) strlcat( nick_out, "@", sizeof( nick_out ));
|
||||||
|
if( is_halfop ) strlcat( nick_out, "%", sizeof( nick_out ));
|
||||||
if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out ));
|
if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out ));
|
||||||
strlcat( nick_out, ptr, sizeof( nick_out ));
|
strlcat( nick_out, ptr, sizeof( nick_out ));
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define RPL_YOURHOST_MSG "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)"
|
#define RPL_YOURHOST_MSG "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)"
|
||||||
#define RPL_CREATED_MSG "003 %s :This server has been started %s"
|
#define RPL_CREATED_MSG "003 %s :This server has been started %s"
|
||||||
#define RPL_MYINFO_MSG "004 %s %s ngircd-%s %s %s"
|
#define RPL_MYINFO_MSG "004 %s %s ngircd-%s %s %s"
|
||||||
#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=beI,k,l,imnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
|
#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(qaohv)~&@%%+ CHANTYPES=#&+ CHANMODES=beI,k,l,imnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
|
||||||
#define RPL_ISUPPORT2_MSG "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=beI:%d EXCEPTS=e INVEX=I PENALTY :are supported on this server"
|
#define RPL_ISUPPORT2_MSG "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=beI:%d EXCEPTS=e INVEX=I PENALTY :are supported on this server"
|
||||||
|
|
||||||
#define RPL_TRACELINK_MSG "200 %s Link %s-%s %s %s V%s %ld %d %d"
|
#define RPL_TRACELINK_MSG "200 %s Link %s-%s %s %s V%s %ld %d %d"
|
||||||
|
@ -135,6 +135,7 @@
|
||||||
#define ERR_LISTFULL_MSG "478 %s %s %s: Channel list is full (%d)"
|
#define ERR_LISTFULL_MSG "478 %s %s %s: Channel list is full (%d)"
|
||||||
#define ERR_NOPRIVILEGES_MSG "481 %s :Permission denied"
|
#define ERR_NOPRIVILEGES_MSG "481 %s :Permission denied"
|
||||||
#define ERR_CHANOPRIVSNEEDED_MSG "482 %s %s :You are not channel operator"
|
#define ERR_CHANOPRIVSNEEDED_MSG "482 %s %s :You are not channel operator"
|
||||||
|
#define ERR_CHANOPPRIVTOLOW_MSG "482 %s %s :Your privileges are to low"
|
||||||
#define ERR_CANTKILLSERVER_MSG "483 %s :You can't kill a server!"
|
#define ERR_CANTKILLSERVER_MSG "483 %s :You can't kill a server!"
|
||||||
#define ERR_RESTRICTED_MSG "484 %s :Your connection is restricted"
|
#define ERR_RESTRICTED_MSG "484 %s :Your connection is restricted"
|
||||||
#define ERR_NOOPERHOST_MSG "491 %s :Not configured for your host"
|
#define ERR_NOOPERHOST_MSG "491 %s :Not configured for your host"
|
||||||
|
|
|
@ -67,10 +67,17 @@ Announce_Channel(CLIENT *Client, CHANNEL *Chan)
|
||||||
* (if user is channel operator or has voice) */
|
* (if user is channel operator or has voice) */
|
||||||
if (str[strlen(str) - 1] != ':')
|
if (str[strlen(str) - 1] != ':')
|
||||||
strlcat(str, ",", sizeof(str));
|
strlcat(str, ",", sizeof(str));
|
||||||
if (strchr(Channel_UserModes(Chan, cl), 'v'))
|
if (strchr(Channel_UserModes(Chan, cl), 'q'))
|
||||||
strlcat(str, "+", sizeof(str));
|
strlcat(str, "~", sizeof(str));
|
||||||
|
if (strchr(Channel_UserModes(Chan, cl), 'a'))
|
||||||
|
strlcat(str, "&", sizeof(str));
|
||||||
if (strchr(Channel_UserModes(Chan, cl), 'o'))
|
if (strchr(Channel_UserModes(Chan, cl), 'o'))
|
||||||
strlcat(str, "@", sizeof(str));
|
strlcat(str, "@", sizeof(str));
|
||||||
|
if (strchr(Channel_UserModes(Chan, cl), 'h'))
|
||||||
|
strlcat(str, "%", sizeof(str));
|
||||||
|
if (strchr(Channel_UserModes(Chan, cl), 'v'))
|
||||||
|
strlcat(str, "+", sizeof(str));
|
||||||
|
|
||||||
strlcat(str, Client_ID(cl), sizeof(str));
|
strlcat(str, Client_ID(cl), sizeof(str));
|
||||||
|
|
||||||
/* Send the data if the buffer is "full" */
|
/* Send the data if the buffer is "full" */
|
||||||
|
|
Loading…
Reference in New Issue