Add full support for +a (owner) and +h (halfop) chmodes.

This commit is contained in:
B.Greenham 2010-02-28 02:35:48 -05:00
parent fc5ba33325
commit 82f8e812f5
6 changed files with 517 additions and 20 deletions

View File

@ -147,10 +147,14 @@ typedef int (*ExtbanFunc)(const char *data, struct Client *client_p,
#define CHFL_BANNED 0x0008 /* cached as banned */
#define CHFL_QUIETED 0x0010 /* cached as being +q victim */
#define ONLY_SERVERS 0x0020
#define CHFL_HALFOP 0x0040
#define CHFL_OWNER 0x0080
#define ALL_MEMBERS CHFL_PEON
#define ONLY_CHANOPS CHFL_CHANOP
#define ONLY_CHANOPSVOICED (CHFL_CHANOP|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_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))

View File

@ -66,9 +66,15 @@ extern void chm_limit(struct Client *source_p, struct Channel *chptr,
extern void chm_regonly(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_op(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_halfop(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_voice(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

@ -490,11 +490,21 @@ ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char
for (i = 0; i < 2; i++)
{
if(*s == '@')
if(*s == '!')
{
fl |= CHFL_OWNER;
s++;
}
else if(*s == '@')
{
fl |= CHFL_CHANOP;
s++;
}
else if(*s == '%')
{
fl |= CHFL_HALFOP;
s++;
}
else if(*s == '+')
{
fl |= CHFL_VOICE;
@ -520,12 +530,24 @@ ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char
if(keep_new_modes)
{
if(fl & CHFL_OWNER)
{
*ptr_uid++ = '!';
len_nick++;
len_uid++;
}
if(fl & CHFL_CHANOP)
{
*ptr_uid++ = '@';
len_nick++;
len_uid++;
}
if(fl & CHFL_HALFOP)
{
*ptr_uid++ = '%';
len_nick++;
len_uid++;
}
if(fl & CHFL_VOICE)
{
*ptr_uid++ = '+';
@ -551,12 +573,108 @@ ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char
joins++;
}
/* 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_OWNER)
{
*mbuf++ = 'a';
para[pargs++] = target_p->name;
if(fl & CHFL_CHANOP)
{
/* its possible the +a 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 +a 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 +a 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;
}
}
if(fl & CHFL_CHANOP)
{
*mbuf++ = 'o';
para[pargs++] = target_p->name;
/* a +ov user.. bleh */
if(fl & CHFL_HALFOP)
{
/* its possible the +o 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 +o has filled up MAXMODEPARAMS, if so, start
@ -580,6 +698,34 @@ ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char
para[pargs++] = target_p->name;
}
}
if(fl & CHFL_HALFOP)
{
*mbuf++ = 'h';
para[pargs++] = target_p->name;
if(fl & CHFL_VOICE)
{
/* its possible the +h 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_VOICE)
{
*mbuf++ = 'v';
@ -798,13 +944,152 @@ remove_our_modes(struct Channel *chptr, struct Client *source_p)
{
msptr = ptr->data;
if(is_chanop(msptr))
/* 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_owner(msptr))
{
msptr->flags &= ~CHFL_OWNER;
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_chanop(msptr))
{
msptr->flags &= ~CHFL_CHANOP;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'o';
/* +ov, might not fit so check. */
/* Make sure it fits if +h or +v are involved */
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_halfop(msptr))
{
msptr->flags &= ~CHFL_HALFOP;
lpara[count++] = msptr->client_p->name;
*mbuf++ = 'h';
/* +hv, might not fit so check. */
if(is_voiced(msptr))
{
if(count >= MAXMODEPARAMS)

View File

@ -219,9 +219,10 @@ find_channel_status(struct membership *msptr, int combine)
int
is_halfop(struct membership *msptr)
{
/* will do something other than return 0 when owner is implemented */
if(!ConfigChannel.use_halfop)
return 0;
if(is_chmode_h(msptr))
return 1;
else
return 0;
}
@ -237,9 +238,10 @@ is_halfop(struct membership *msptr)
int
is_owner(struct membership *msptr)
{
/* will do something other than return 0 when owner is implemented */
if(!ConfigChannel.use_owner)
return 0;
if(is_chmode_a(msptr))
return 1;
else
return 0;
}

View File

@ -89,7 +89,9 @@ construct_noparam_modes(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_op) &&
!(chmode_table[i].set_func == chm_halfop) &&
!(chmode_table[i].set_func == chm_voice))
{
chmode_flags[i] = chmode_table[i].mode_type;
@ -175,8 +177,12 @@ find_cflag_slot(void)
static int
get_channel_access(struct Client *source_p, struct membership *msptr)
{
if(!MyClient(source_p) || is_chanop(msptr))
if(!MyClient(source_p) || is_owner(msptr))
return CHFL_OWNER;
else if(is_chanop(msptr))
return CHFL_CHANOP;
else if(is_halfop(msptr))
return CHFL_HALFOP;
return CHFL_PEON;
}
@ -492,7 +498,7 @@ chm_simple(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)
{
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -706,7 +712,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
*errors |= errorval;
/* non-ops cant see +eI lists.. */
if(alevel != CHFL_CHANOP && mode_type != CHFL_BAN &&
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP && mode_type != CHFL_BAN &&
mode_type != CHFL_QUIET)
{
if(!(*errors & SM_ERR_NOOPS))
@ -730,7 +736,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr,
return;
}
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -809,6 +815,103 @@ 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;
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(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
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)
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++].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++].client = targ_p;
mstptr->flags &= ~CHFL_OWNER;
}
}
void
chm_op(struct Client *source_p, struct Channel *chptr,
int alevel, int parc, int *parn,
@ -818,7 +921,7 @@ chm_op(struct Client *source_p, struct Channel *chptr,
const char *opnick;
struct Client *targ_p;
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -897,6 +1000,103 @@ chm_op(struct Client *source_p, struct Channel *chptr,
}
}
void
chm_halfop(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 *halfopnick;
struct Client *targ_p;
if(!ConfigChannel.use_halfop)
{
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_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
me.name, source_p->name, chptr->chname);
*errors |= SM_ERR_NOOPS;
return;
}
if((dir == MODE_QUERY) || (parc <= *parn))
return;
halfopnick = parv[(*parn)];
(*parn)++;
/* empty nick */
if(EmptyString(halfopnick))
{
sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
return;
}
if((targ_p = find_chasing(source_p, halfopnick, 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), halfopnick, chptr->chname);
*errors |= SM_ERR_NOTONCHANNEL;
return;
}
if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
return;
if(dir == MODE_ADD)
{
if(targ_p == source_p)
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++].client = targ_p;
mstptr->flags |= CHFL_HALFOP;
}
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++].client = targ_p;
mstptr->flags &= ~CHFL_HALFOP;
}
}
void
chm_voice(struct Client *source_p, struct Channel *chptr,
int alevel, int parc, int *parn,
@ -906,7 +1106,7 @@ chm_voice(struct Client *source_p, struct Channel *chptr,
const char *opnick;
struct Client *targ_p;
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -984,7 +1184,7 @@ chm_limit(struct Client *source_p, struct Channel *chptr,
static char limitstr[30];
int limit;
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -1043,7 +1243,7 @@ chm_throttle(struct Client *source_p, struct Channel *chptr,
{
int joins = 0, timeslice = 0;
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -1126,7 +1326,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr,
}
#ifndef FORWARD_OPERONLY
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -1218,7 +1418,7 @@ chm_key(struct Client *source_p, struct Channel *chptr,
{
char *key;
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -1295,7 +1495,7 @@ chm_regonly(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)
{
if(alevel != CHFL_CHANOP)
if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
{
if(!(*errors & SM_ERR_NOOPS))
sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
@ -1429,14 +1629,14 @@ struct ChannelMode chmode_table[256] =
{chm_nosuch, 0 },
{chm_nosuch, 0 },
{chm_nosuch, 0 },
{chm_nosuch, 0 }, /* a */
{chm_owner, 0 }, /* a */
{chm_ban, CHFL_BAN }, /* b */
{chm_simple, MODE_NOCOLOR }, /* c */
{chm_nosuch, 0 }, /* d */
{chm_ban, CHFL_EXCEPTION }, /* e */
{chm_forward, 0 }, /* f */
{chm_simple, MODE_FREEINVITE }, /* g */
{chm_nosuch, 0 }, /* h */
{chm_halfop, 0 }, /* h */
{chm_simple, MODE_INVITEONLY }, /* i */
{chm_throttle, 0 }, /* j */
{chm_key, 0 }, /* k */

View File

@ -584,7 +584,7 @@ sendto_channel_opmod(struct Client *one, struct Client *source_p,
if(IsIOError(target_p->from) || target_p->from == one)
continue;
if((msptr->flags & CHFL_CHANOP) == 0)
if(!is_any_op(msptr))
continue;
if(IsDeaf(target_p))