Support for channel owner mode added

This is a lot like the previous channel owner mode patch, except the
documentation that previously said "admin" now says "owner" in comments.

src/channel: Kicking logic for owner mode fixed

src/channel: Document the kick/deop logic

decruft: remove temporary files
This commit is contained in:
Sam Dodrill 2013-09-10 07:08:49 -07:00
parent 8c2b9a6e59
commit aa294a3a54
16 changed files with 565 additions and 103 deletions

View File

@ -390,6 +390,7 @@ channel {
exemptchanops = "NT";
use_halfop = yes;
use_admin = yes;
use_owner = yes;
use_knock = yes;
use_local_channels = yes;
knock_delay = 5 minutes;

View File

@ -808,6 +808,16 @@ channel {
*/
use_admin = no;
/* owner: Enable/disable channel mode +y, which adds owner,
* a channel status above admin that has op powers (kick, ban, mode, etc.)
* owners can only be kicked/deadmined by other owners, and may kick
* or deop anyone. Disabling this via rehash will cause things which
* are rather confusing to occur, it is highly recommended to restart
* if you wish to disable this option, though it may be enabled
* by rehash with no problems.
*/
use_owner = no;
/* knock: Allows users to request an invite to a channel that
* is locked somehow (+ikl). If the channel is +p or you are banned
* the knock will not be sent.

View File

@ -804,6 +804,16 @@ channel {
*/
use_admin = yes;
/* owner: Enable/disable channel mode +y, which adds owner,
* a channel status above admin that has op powers (kick, ban, mode, etc.)
* owners can only be kicked/deadmined by other owners, and may kick
* or deop anyone. Disabling this via rehash will cause things which
* are rather confusing to occur, it is highly recommended to restart
* if you wish to disable this option, though it may be enabled
* by rehash with no problems.
*/
use_owner = yes;
/* knock: Allows users to request an invite to a channel that
* is locked somehow (+ikl). If the channel is +p or you are banned
* the knock will not be sent.

View File

@ -64,7 +64,7 @@ mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char
return 0;
}
if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+' || *parv[1] == '!')
if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+' || *parv[1] == '!' || *parv[1] == '~')
{
parv[1]++;
move_me = 1;
@ -97,7 +97,19 @@ mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char
me.name, parv[1],
source_p->name, source_p->username, source_p->host);
if(*parv[1] == '!' && ConfigChannel.use_admin)
if(*parv[1] == '~' && ConfigChannel.use_owner)
{
add_user_to_channel(chptr, source_p, CHFL_OWNER);
sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
":%s SJOIN %ld %s + :!%s",
me.id, (long) chptr->channelts, chptr->chname, source_p->id);
sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
source_p->name,
source_p->username, source_p->host, chptr->chname);
sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +y %s",
me.name, chptr->chname, source_p->name);
}
else if(*parv[1] == '!' && ConfigChannel.use_admin)
{
add_user_to_channel(chptr, source_p, CHFL_ADMIN);
sendto_server(client_p, chptr, CAP_TS6, NOCAPS,

View File

@ -123,7 +123,24 @@ mo_omode(struct Client *client_p, struct Client *source_p, int parc, const char
set_channel_mode(client_p, source_p->servptr, chptr, msptr,
parc - 2, parv + 2);
#else
if (parc == 4 && !strcmp(parv[2], "+a") && !irccmp(parv[3], source_p->name))
if (parc == 4 && !strcmp(parv[2], "+y") && !irccmp(parv[3], source_p->name))
{
/* Ownering themselves */
if (!wasonchannel)
{
sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname);
return 0;
}
sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +y %s",
me.name, parv[1], source_p->name);
sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
":%s TMODE %ld %s +y %s",
me.id, (long) chptr->channelts, parv[1],
source_p->id);
msptr->flags |= CHFL_OWNER;
}
else if (parc == 4 && !strcmp(parv[2], "+a") && !irccmp(parv[3], source_p->name))
{
/* Admining themselves */
if (!wasonchannel)
@ -174,6 +191,26 @@ mo_omode(struct Client *client_p, struct Client *source_p, int parc, const char
source_p->id);
msptr->flags |= CHFL_HALFOP;
}
else if (ConfigChannel.use_owner)
{
/* I hope this is correct.
* -- Kabaka */
/* Hack it so set_channel_mode() will accept */
if (wasonchannel)
msptr->flags |= CHFL_OWNER;
else
{
add_user_to_channel(chptr, source_p, CHFL_CHANOP);
msptr = find_channel_membership(chptr, source_p);
}
set_channel_mode(client_p, source_p, chptr, msptr,
parc - 2, parv + 2);
if (wasonchannel)
msptr->flags &= ~CHFL_OWNER;
else
remove_user_from_channel(msptr);
}
else if (ConfigChannel.use_admin)
{
/* Hack it so set_channel_mode() will accept */

View File

@ -154,13 +154,15 @@ typedef int (*ExtbanFunc)(const char *data, struct Client *client_p,
#define ONLY_SERVERS 0x0020
#define CHFL_HALFOP 0x0040
#define CHFL_ADMIN 0x0080
#define CHFL_OWNER 0x0200
#define ONLY_OPERS 0x0100
#define ALL_MEMBERS CHFL_PEON
#define ONLY_CHANOPS (CHFL_ADMIN|CHFL_CHANOP|CHFL_HALFOP)
#define ONLY_CHANOPSVOICED (CHFL_ADMIN|CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE)
#define ONLY_CHANOPS (CHFL_OWNER|CHFL_ADMIN|CHFL_CHANOP|CHFL_HALFOP)
#define ONLY_CHANOPSVOICED (CHFL_OWNER|CHFL_ADMIN|CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE)
#define is_chmode_h(x) ((x) && (x)->flags & CHFL_HALFOP) /* does not check if halfop is enabled, should typically not be used */
#define is_chmode_a(x) ((x) && (x)->flags & CHFL_ADMIN) /* does not check if admin is enabled, should typically not be used */
#define is_chmode_y(x) ((x) && (x)->flags & CHFL_OWNER) /* does not check if owner is enabled, should typically not be used */
#define is_chanop(x) ((x) && (x)->flags & CHFL_CHANOP)
#define is_voiced(x) ((x) && (x)->flags & CHFL_VOICE)
#define can_send_banned(x) ((x) && (x)->flags & (CHFL_BANNED|CHFL_QUIETED))
@ -243,6 +245,7 @@ extern struct membership *find_channel_membership(struct Channel *, struct Clien
extern const char *find_channel_status(struct membership *msptr, int combine);
extern int is_halfop(struct membership *msptr);
extern int is_admin(struct membership *msptr);
extern int is_owner(struct membership *msptr);
extern int is_any_op(struct membership *msptr);
extern int is_chanop_voiced(struct membership *msptr);
extern int can_kick_deop(struct membership *source, struct membership *target);

View File

@ -66,6 +66,9 @@ extern void chm_key(struct Client *source_p, struct Channel *chptr,
extern void chm_limit(struct Client *source_p, struct Channel *chptr,
int alevel, int parc, int *parn,
const char **parv, int *errors, int dir, char c, long mode_type);
extern void chm_owner(struct Client *source_p, struct Channel *chptr,
int alevel, int parc, int *parn,
const char **parv, int *errors, int dir, char c, long mode_type);
extern void chm_admin(struct Client *source_p, struct Channel *chptr,
int alevel, int parc, int *parn,
const char **parv, int *errors, int dir, char c, long mode_type);

View File

@ -243,6 +243,7 @@ struct config_channel_entry
int admin_on_channel_create;
int use_halfop;
int use_admin;
int use_owner;
int use_except;
int use_invex;
int use_knock;

View File

@ -1,64 +0,0 @@
/*
* libratbox: a library used by ircd-ratbox and other things
* src/version.c
*
* Copyright (C) 1990 Chelsea Ashley Dyerman
* Copyright (C) 2008 ircd-ratbox development team
*
* 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
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file is generated by version.c.SH. Any changes made will go away.
*/
#include "../include/serno.h"
const char *libratbox_generation = "1";
const char *libratbox_platform = "Linux genesect 3.10.10-1-grsec #2-Alpine SMP Mon Sep 2 10:06:15 UTC 2013 x86_64 GNU/Linux";
const char *libratbox_serno = SERIALNUM;
const char *libratbox_creation = "Mon Sep 9 2013 at 15:58:38 PDT";
const char *libratbox_infotext[] =
{
"libratbox --",
"Based on the original code written by Jarkko Oikarinen",
"Copyright 1988, 1989, 1990, 1991 University of Oulu, Computing Center",
"Copyright (c) 1996-2001 Hybrid Development Team",
"Copyright (c) 2002-2008 ircd-ratbox Development Team",
"",
"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 the Free Software Foundation; either version 2, or",
"(at your option) any later version.",
"",
" ",
"ircd-ratbox is an evolution where ircd-hybrid left off around version 7-rc1. ",
"Currently the ircd-ratbox team consists of the following developers:",
" ",
"AndroSyn, Aaron Sethman <androsyn -at- ratbox.org>",
"anfl, Lee Hardy <lee -at- leeh.co.uk>",
"Special thanks for support, code and ideas to:",
"Hwy, W. Campbell <wcampbel -at- botbay.net>",
"jilles, Jilles Tjoelker <jilles -at- stack.nl>",
"larne, Edward Brocklesby <ejb -at- sdf.lonestar.org>",
" ",
"Of course our work is based on the work of many, many others over the past",
"10 or so years since irc has existed, including the work done by the Hybrid",
"team, our thanks goes to them.",
" ",
"",
0,
};

View File

@ -544,7 +544,12 @@ ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char
for (i = 0; i < 4; i++)
{
if(*s == '!')
if(*s == '~')
{
fl |= CHFL_OWNER;
s++;
}
else if(*s == '!')
{
fl |= CHFL_ADMIN;
s++;
@ -584,7 +589,13 @@ ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char
if(keep_new_modes)
{
if(fl & CHFL_ADMIN)
if(fl & CHFL_OWNER)
{
*ptr_uid++ = '~';
len_nick++;
len_uid++;
}
else if(fl & CHFL_ADMIN)
{
*ptr_uid++ = '!';
len_nick++;
@ -630,7 +641,101 @@ ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char
/* If anyone can think of a way to do this that doesn't make babies cry
* I would love to hear it - Taros */
if(fl & CHFL_ADMIN)
if(fl & CHFL_OWNER)
{
*mbuf++ = 'y';
para[pargs++] = target_p->name;
if(fl & CHFL_ADMIN)
{
/* its possible the +y has filled up MAXMODEPARAMS, if so, start
* a new buffer
*/
if(pargs >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
fakesource_p->name, chptr->chname,
modebuf,
para[0], para[1], para[2], para[3]);
mbuf = modebuf;
*mbuf++ = '+';
para[0] = para[1] = para[2] = para[3] = NULL;
pargs = 0;
}
*mbuf++ = 'a';
para[pargs++] = target_p->name;
}
if(fl & CHFL_CHANOP)
{
/* its possible the +y has filled up MAXMODEPARAMS, if so, start
* a new buffer
*/
if(pargs >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
fakesource_p->name, chptr->chname,
modebuf,
para[0], para[1], para[2], para[3]);
mbuf = modebuf;
*mbuf++ = '+';
para[0] = para[1] = para[2] = para[3] = NULL;
pargs = 0;
}
*mbuf++ = 'o';
para[pargs++] = target_p->name;
}
if(fl & CHFL_HALFOP)
{
/* its possible the +y has filled up MAXMODEPARAMS, if so, start
* a new buffer
*/
if(pargs >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
fakesource_p->name, chptr->chname,
modebuf,
para[0], para[1], para[2], para[3]);
mbuf = modebuf;
*mbuf++ = '+';
para[0] = para[1] = para[2] = para[3] = NULL;
pargs = 0;
}
*mbuf++ = 'h';
para[pargs++] = target_p->name;
}
if(fl & CHFL_VOICE)
{
/* its possible the +y has filled up MAXMODEPARAMS, if so, start
* a new buffer
*/
if(pargs >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
fakesource_p->name, chptr->chname,
modebuf,
para[0], para[1], para[2], para[3]);
mbuf = modebuf;
*mbuf++ = '+';
para[0] = para[1] = para[2] = para[3] = NULL;
pargs = 0;
}
*mbuf++ = 'v';
para[pargs++] = target_p->name;
}
}
else if(fl & CHFL_ADMIN)
{
*mbuf++ = 'a';
para[pargs++] = target_p->name;
@ -1026,7 +1131,190 @@ remove_our_modes(struct Channel *chptr, struct Client *source_p)
/* If anyone can think of a way to do this that doesn't make babies cry
* I would love to hear it - Taros */
if(is_admin(msptr))
if(is_owner(msptr))
{
msptr->flags &= ~CHFL_ADMIN;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'y';
/* Make sure it fits if +h, +o, or +v are involved */
if(is_admin(msptr))
{
if(count >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
source_p->name, chptr->chname,
lmodebuf, lpara[0], lpara[1],
lpara[2], lpara[3]);
/* preserve the initial '-' */
mbuf = lmodebuf;
*mbuf++ = '-';
count = 0;
for(i = 0; i < MAXMODEPARAMS; i++)
lpara[i] = NULL;
}
msptr->flags &= ~CHFL_ADMIN;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'a';
}
if(is_chanop(msptr))
{
if(count >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
source_p->name, chptr->chname,
lmodebuf, lpara[0], lpara[1],
lpara[2], lpara[3]);
/* preserve the initial '-' */
mbuf = lmodebuf;
*mbuf++ = '-';
count = 0;
for(i = 0; i < MAXMODEPARAMS; i++)
lpara[i] = NULL;
}
msptr->flags &= ~CHFL_CHANOP;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'o';
}
if(is_halfop(msptr))
{
if(count >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
source_p->name, chptr->chname,
lmodebuf, lpara[0], lpara[1],
lpara[2], lpara[3]);
/* preserve the initial '-' */
mbuf = lmodebuf;
*mbuf++ = '-';
count = 0;
for(i = 0; i < MAXMODEPARAMS; i++)
lpara[i] = NULL;
}
msptr->flags &= ~CHFL_HALFOP;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'h';
}
if(is_voiced(msptr))
{
if(count >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
source_p->name, chptr->chname,
lmodebuf, lpara[0], lpara[1],
lpara[2], lpara[3]);
/* preserve the initial '-' */
mbuf = lmodebuf;
*mbuf++ = '-';
count = 0;
for(i = 0; i < MAXMODEPARAMS; i++)
lpara[i] = NULL;
}
msptr->flags &= ~CHFL_VOICE;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'v';
}
else if(is_admin(msptr))
{
msptr->flags &= ~CHFL_ADMIN;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'a';
/* Make sure it fits if +h, +o, or +v are involved */
if(is_chanop(msptr))
{
if(count >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
source_p->name, chptr->chname,
lmodebuf, lpara[0], lpara[1],
lpara[2], lpara[3]);
/* preserve the initial '-' */
mbuf = lmodebuf;
*mbuf++ = '-';
count = 0;
for(i = 0; i < MAXMODEPARAMS; i++)
lpara[i] = NULL;
}
msptr->flags &= ~CHFL_CHANOP;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'o';
}
if(is_halfop(msptr))
{
if(count >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
source_p->name, chptr->chname,
lmodebuf, lpara[0], lpara[1],
lpara[2], lpara[3]);
/* preserve the initial '-' */
mbuf = lmodebuf;
*mbuf++ = '-';
count = 0;
for(i = 0; i < MAXMODEPARAMS; i++)
lpara[i] = NULL;
}
msptr->flags &= ~CHFL_HALFOP;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'h';
}
if(is_voiced(msptr))
{
if(count >= MAXMODEPARAMS)
{
*mbuf = '\0';
sendto_channel_local(ALL_MEMBERS, chptr,
":%s MODE %s %s %s %s %s %s",
source_p->name, chptr->chname,
lmodebuf, lpara[0], lpara[1],
lpara[2], lpara[3]);
/* preserve the initial '-' */
mbuf = lmodebuf;
*mbuf++ = '-';
count = 0;
for(i = 0; i < MAXMODEPARAMS; i++)
lpara[i] = NULL;
}
msptr->flags &= ~CHFL_VOICE;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'v';
}
}
}
else if(is_admin(msptr))
{
msptr->flags &= ~CHFL_ADMIN;
lpara[count++] = msptr->client_p->name;

View File

@ -643,6 +643,12 @@ static struct InfoStruct info_table[] = {
&ConfigChannel.use_admin,
"Enable chanmode +a (admin)",
},
{
"use_owner",
OUTPUT_BOOLEAN_YN,
&ConfigChannel.use_owner,
"Enable chanmode +y (owner)",
},
{
"use_except",
OUTPUT_BOOLEAN_YN,

View File

@ -186,6 +186,12 @@ find_channel_status(struct membership *msptr, int combine)
p = buffer;
if(is_owner(msptr))
{
if(!combine)
return "~";
*p++ = '~';
}
if(is_admin(msptr))
{
if(!combine)
@ -252,6 +258,24 @@ is_admin(struct membership *msptr)
return 0;
}
/* is_owner()
* input - membership to check for owner
* output - 1 if the user is an admin, 0 if the user is not or owner
* is disabled
* side effects -
*
*/
int
is_owner(struct membership *msptr)
{
if(!ConfigChannel.use_owner)
return 0;
if(is_chmode_y(msptr))
return 1;
else
return 0;
}
/* is_any_op()
*
* input - membership to check for ops
@ -261,7 +285,7 @@ is_admin(struct membership *msptr)
int
is_any_op(struct membership *msptr)
{
if(is_chanop(msptr) || is_halfop(msptr) || is_admin(msptr))
if(is_chanop(msptr) || is_halfop(msptr) || is_admin(msptr) || is_owner(msptr))
return 1;
else
return 0;
@ -276,7 +300,7 @@ is_any_op(struct membership *msptr)
int
is_chanop_voiced(struct membership *msptr)
{
if(is_chanop(msptr) || is_voiced(msptr) || is_halfop(msptr) || is_admin(msptr))
if(is_chanop(msptr) || is_voiced(msptr) || is_halfop(msptr) || is_admin(msptr) || is_owner(msptr))
return 1;
else
return 0;
@ -291,12 +315,25 @@ is_chanop_voiced(struct membership *msptr)
int
can_kick_deop(struct membership *source, struct membership *target)
{
if(is_chanop(source) && !is_admin(target))
return 1;
else if(is_halfop(source) && !is_any_op(target))
return 1;
else if(is_admin(source))
return 1;
/*
* Reworked the logic to match this:
* - owners can do what they want
* - admins cannot kick or deop owners
* - ops cannot kick or deop admins
* - halfops cannot kick or deop anyone that has halfop or up
* -- Niichan
*/
if(is_halfop(source) && !is_any_op(target))
return 1;
else if(is_chanop(source) && !is_admin(target))
return 1;
else if(is_chanop(source) && !is_owner(target))
return 1;
else if(is_admin(source) && !is_owner(target))
return 1;
else if(is_owner(source))
return 1;
return 0;
}

View File

@ -92,6 +92,7 @@ construct_cflags_strings(void)
!(chmode_table[i].set_func == chm_throttle) &&
!(chmode_table[i].set_func == chm_key) &&
!(chmode_table[i].set_func == chm_limit) &&
!(chmode_table[i].set_func == chm_owner) &&
!(chmode_table[i].set_func == chm_admin) &&
!(chmode_table[i].set_func == chm_op) &&
!(chmode_table[i].set_func == chm_halfop) &&
@ -129,9 +130,10 @@ construct_cflags_strings(void)
}
/* Should we leave orphaned check here? -- dwr */
if( !(chmode_table[i].set_func == chm_nosuch) &&
!(chmode_table[i].set_func == chm_orphaned) &&
!(chmode_table[i].set_func == chm_admin && !ConfigChannel.use_admin) &&
if( !(chmode_table[i].set_func == chm_nosuch) &&
!(chmode_table[i].set_func == chm_orphaned) &&
!(chmode_table[i].set_func == chm_owner && !ConfigChannel.use_owner) &&
!(chmode_table[i].set_func == chm_admin && !ConfigChannel.use_admin) &&
!(chmode_table[i].set_func == chm_halfop && !ConfigChannel.use_halfop))
{
*ptr2++ = (char) i;
@ -147,7 +149,8 @@ construct_cflag_param_string(void)
{
*cflagsparaminfo = '\0';
rb_snprintf(cflagsparaminfo, sizeof cflagsparaminfo, "%sb%s%s%s%sklov%s%s",
rb_snprintf(cflagsparaminfo, sizeof cflagsparaminfo, "%s%sb%s%s%s%sklov%s%s",
ConfigChannel.use_owner ? "y" : "",
ConfigChannel.use_admin ? "a" : "",
ConfigChannel.use_except ? "e" : "",
ConfigChannel.use_forward ? "f" : "",
@ -210,8 +213,10 @@ cflag_orphan(char c_)
static int
get_channel_access(struct Client *source_p, struct membership *msptr)
{
if(!MyClient(source_p) || is_admin(msptr))
return CHFL_ADMIN;
if(!MyClient(source_p) || is_owner(msptr))
return CHFL_OWNER;
else if(is_admin(msptr))
return CHFL_ADMIN;
else if(is_chanop(msptr))
return CHFL_CHANOP;
else if(is_halfop(msptr))
@ -536,7 +541,7 @@ chm_simple(struct Client *source_p, struct Channel *chptr,
struct Metadata *md;
struct DictionaryIter iter;
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER)
{
if (IsOverride(source_p))
override = 1;
@ -747,7 +752,7 @@ chm_staff(struct Client *source_p, struct Channel *chptr,
return;
}
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER)
{
if (IsOverride(source_p))
override = 1;
@ -879,8 +884,8 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
*errors |= errorval;
/* non-ops cant see +eI lists.. */
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && mode_type != CHFL_BAN &&
mode_type != CHFL_QUIET)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER &&
mode_type != CHFL_BAN && mode_type != CHFL_QUIET)
{
if(IsOverride(source_p))
{
@ -913,7 +918,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
return;
}
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1000,6 +1005,115 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
}
}
void
chm_owner(struct Client *source_p, struct Channel *chptr,
int alevel, int parc, int *parn,
const char **parv, int *errors, int dir, char c, long mode_type)
{
struct membership *mstptr;
const char *ownernick;
struct Client *targ_p;
int override = 0;
if(!ConfigChannel.use_owner)
{
if(*errors & SM_ERR_UNKNOWN)
return;
*errors |= SM_ERR_UNKNOWN;
sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
return;
}
if(alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
else
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, ":%s 482 %s %s :You're not a channel owner", me.name, source_p->name, chptr->chname);
*errors |= SM_ERR_NOOPS;
return;
}
}
if((dir == MODE_QUERY) || (parc <= *parn))
return;
ownernick = parv[(*parn)];
(*parn)++;
/* empty nick */
if(EmptyString(ownernick))
{
sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
return;
}
if((targ_p = find_chasing(source_p, ownernick, NULL)) == NULL)
return;
mstptr = find_channel_membership(chptr, targ_p);
if(mstptr == NULL)
{
if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
form_str(ERR_USERNOTINCHANNEL), ownernick, chptr->chname);
*errors |= SM_ERR_NOTONCHANNEL;
return;
}
if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
return;
if(dir == MODE_ADD)
{
if(targ_p == source_p)
{
no_override_deop = 1;
/* Don't reject modes from remote. It desyncs, and this is perfectly
* legitimate from a remote override oper.
if(!override)
return;
*/
}
mode_changes[mode_count].letter = c;
mode_changes[mode_count].dir = MODE_ADD;
mode_changes[mode_count].caps = 0;
mode_changes[mode_count].nocaps = 0;
mode_changes[mode_count].mems = ALL_MEMBERS;
mode_changes[mode_count].id = targ_p->id;
mode_changes[mode_count].arg = targ_p->name;
mode_changes[mode_count].override = override;
mode_changes[mode_count++].client = targ_p;
mstptr->flags |= CHFL_OWNER;
}
else
{
if(MyClient(source_p) && IsService(targ_p))
{
sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
me.name, source_p->name, targ_p->name, chptr->chname);
return;
}
mode_changes[mode_count].letter = c;
mode_changes[mode_count].dir = MODE_DEL;
mode_changes[mode_count].caps = 0;
mode_changes[mode_count].nocaps = 0;
mode_changes[mode_count].mems = ALL_MEMBERS;
mode_changes[mode_count].id = targ_p->id;
mode_changes[mode_count].arg = targ_p->name;
mode_changes[mode_count].override = override;
mode_changes[mode_count++].client = targ_p;
mstptr->flags &= ~CHFL_OWNER;
}
}
void
chm_admin(struct Client *source_p, struct Channel *chptr,
int alevel, int parc, int *parn,
@ -1019,7 +1133,7 @@ chm_admin(struct Client *source_p, struct Channel *chptr,
return;
}
if(alevel != CHFL_ADMIN)
if(alevel != CHFL_ADMIN && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1122,7 +1236,7 @@ chm_op(struct Client *source_p, struct Channel *chptr,
struct Client *targ_p;
int override = 0;
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1235,7 +1349,7 @@ chm_halfop(struct Client *source_p, struct Channel *chptr,
return;
}
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1339,7 +1453,7 @@ chm_voice(struct Client *source_p, struct Channel *chptr,
struct Client *targ_p;
int override = 0;
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1426,7 +1540,7 @@ chm_limit(struct Client *source_p, struct Channel *chptr,
int limit;
int override = 0;
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1493,7 +1607,7 @@ chm_throttle(struct Client *source_p, struct Channel *chptr,
int joins = 0, timeslice = 0;
int override = 0;
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1585,7 +1699,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr,
}
#ifndef FORWARD_OPERONLY
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1690,7 +1804,7 @@ chm_key(struct Client *source_p, struct Channel *chptr,
char *key;
int override = 0;
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && alevel != CHFL_OWNER)
{
if(IsOverride(source_p))
override = 1;
@ -1894,7 +2008,7 @@ struct ChannelMode chmode_table[256] =
{chm_voice, 0 }, /* v */
{chm_nosuch, 0 }, /* w */
{chm_nosuch, 0 }, /* x */
{chm_nosuch, 0 }, /* y */
{chm_owner, 0 }, /* y */
{chm_simple, MODE_OPMODERATE }, /* z */
{chm_nosuch, 0 }, /* 0x7b */

View File

@ -2301,6 +2301,7 @@ static struct ConfEntry conf_channel_table[] =
{ "admin_on_channel_create", CF_YESNO, NULL, 0, &ConfigChannel.admin_on_channel_create },
{ "use_halfop", CF_YESNO, NULL, 0, &ConfigChannel.use_halfop },
{ "use_admin", CF_YESNO, NULL, 0, &ConfigChannel.use_admin },
{ "use_owner", CF_YESNO, NULL, 0, &ConfigChannel.use_owner },
{ "use_except", CF_YESNO, NULL, 0, &ConfigChannel.use_except },
{ "use_invex", CF_YESNO, NULL, 0, &ConfigChannel.use_invex },
{ "use_knock", CF_YESNO, NULL, 0, &ConfigChannel.use_knock },

View File

@ -771,6 +771,7 @@ set_default_conf(void)
ConfigChannel.admin_on_channel_create = NO;
ConfigChannel.use_halfop = YES;
ConfigChannel.use_admin = YES;
ConfigChannel.use_owner = YES;
ConfigChannel.use_except = YES;
ConfigChannel.use_invex = YES;
ConfigChannel.use_knock = YES;

View File

@ -257,11 +257,13 @@ isupport_chanlimit(const void *ptr)
static const char*
isupport_prefix(const void *ptr)
{
static char result[11];
static char result[13];
rb_snprintf(result, sizeof result, "(%so%sv)%s@%s+",
rb_snprintf(result, sizeof result, "(%s%so%sv)%s%s@%s+",
ConfigChannel.use_owner ? "y" : "",
ConfigChannel.use_admin ? "a" : "",
ConfigChannel.use_halfop ? "h" : "",
ConfigChannel.use_owner ? "~" : "",
ConfigChannel.use_admin ? "!" : "",
ConfigChannel.use_halfop ? "%" : "");
return result;