X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/eccd1c58d258a4201ea54cc4811c8b0387f7de05..11e91210d712ae0a0418e80f929f2597c454f80b:/src/chmode.c?ds=sidebyside diff --git a/src/chmode.c b/src/chmode.c index 2784ddc..792016a 100644 --- a/src/chmode.c +++ b/src/chmode.c @@ -42,6 +42,7 @@ #include "s_newconf.h" #include "logger.h" #include "chmode.h" +#include "irc_dictionary.h" /* bitmasks for error returns, so we send once per call */ #define SM_ERR_NOTS 0x00000001 /* No TS on channel */ @@ -64,6 +65,7 @@ static int mode_count; static int mode_limit; static int mode_limit_simple; static int mask_pos; +static int no_override_deop; char cflagsbuf[256]; char cflagsmyinfo[256]; @@ -500,6 +502,8 @@ chm_simple(struct Client *source_p, struct Channel *chptr, { int override = 0; + struct Metadata *md; + struct DictionaryIter iter; if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP) { @@ -539,6 +543,18 @@ chm_simple(struct Client *source_p, struct Channel *chptr, } else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type)) { + /* cleanup metadata when the related mode is removed */ + if(c == 'J') + { + DICTIONARY_FOREACH(md, &iter, chptr->metadata) + { + if(!strcmp(md->value, "KICKNOREJOIN")) + channel_metadata_delete(chptr, md->name, 0); + } + } + if(c == 'K') + channel_metadata_delete(chptr, "NOREPEAT", 0); + chptr->mode.mode &= ~mode_type; mode_changes[mode_count].letter = c; @@ -586,6 +602,59 @@ chm_orphaned(struct Client *source_p, struct Channel *chptr, } } +void +chm_hidden(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(!IsOper(source_p) && !IsServer(source_p)) + { + if(!(*errors & SM_ERR_NOPRIVS)) + sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES)); + *errors |= SM_ERR_NOPRIVS; + return; + } + if(MyClient(source_p) && !IsOperAdmin(source_p)) + { + if(!(*errors & SM_ERR_NOPRIVS)) + sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, + source_p->name, "cmodes"); + *errors |= SM_ERR_NOPRIVS; + return; + } + + if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) + return; + + /* setting + */ + if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type)) + { + chptr->mode.mode |= mode_type; + + 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].id = NULL; + mode_changes[mode_count].mems = ONLY_OPERS; + mode_changes[mode_count].override = 0; + mode_changes[mode_count++].arg = NULL; + } + else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type)) + { + chptr->mode.mode &= ~mode_type; + + 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 = ONLY_OPERS; + mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = 0; + mode_changes[mode_count++].arg = NULL; + } +} + void chm_staff(struct Client *source_p, struct Channel *chptr, int alevel, int parc, int *parn, @@ -621,6 +690,7 @@ chm_staff(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].id = NULL; mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].override = 0; mode_changes[mode_count++].arg = NULL; } else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type)) @@ -632,6 +702,7 @@ chm_staff(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].caps = 0; mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; + mode_changes[mode_count].override = 0; mode_changes[mode_count].id = NULL; mode_changes[mode_count++].arg = NULL; } @@ -652,6 +723,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr, int rpl_endlist; int caps; int mems; + int override = 0; switch (mode_type) { @@ -725,11 +797,22 @@ chm_ban(struct Client *source_p, struct Channel *chptr, if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP && mode_type != CHFL_BAN && mode_type != CHFL_QUIET) { - 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(IsOverride(source_p)) + { + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + "%s is overriding modes on %s: (%s list)", + get_oper_name(source_p), chptr->chname, + mode_type == CHFL_INVEX ? "invex" : "exempt"); + } + else + { + + 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; + } } RB_DLINK_FOREACH(ptr, list->head) @@ -748,11 +831,17 @@ chm_ban(struct Client *source_p, struct Channel *chptr, 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(IsOverride(source_p)) + override = 1; + else + { + + 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(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS)) @@ -804,6 +893,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = mems; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = mask; } else if(dir == MODE_DEL) @@ -821,6 +911,7 @@ chm_ban(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = mems; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = mask; } } @@ -833,6 +924,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr, struct membership *mstptr; const char *ownernick; struct Client *targ_p; + int override = 0; if(!ConfigChannel.use_owner) { @@ -845,11 +937,17 @@ chm_owner(struct Client *source_p, struct Channel *chptr, 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(IsOverride(source_p)) + override = 1; + else + { + + 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)) @@ -887,7 +985,14 @@ chm_owner(struct Client *source_p, struct Channel *chptr, if(dir == MODE_ADD) { if(targ_p == source_p) - return; + { + 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; @@ -896,6 +1001,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr, 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; @@ -916,6 +1022,7 @@ chm_owner(struct Client *source_p, struct Channel *chptr, 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; @@ -930,14 +1037,21 @@ chm_op(struct Client *source_p, struct Channel *chptr, struct membership *mstptr; const char *opnick; struct Client *targ_p; + int override = 0; if(alevel != CHFL_CHANOP && 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(IsOverride(source_p)) + override = 1; + else + { + + 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)) @@ -975,7 +1089,14 @@ chm_op(struct Client *source_p, struct Channel *chptr, if(dir == MODE_ADD) { if(targ_p == source_p) - return; + { + 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; @@ -984,6 +1105,7 @@ chm_op(struct Client *source_p, struct Channel *chptr, 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_CHANOP; @@ -1004,6 +1126,7 @@ chm_op(struct Client *source_p, struct Channel *chptr, 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_CHANOP; @@ -1018,6 +1141,7 @@ chm_halfop(struct Client *source_p, struct Channel *chptr, struct membership *mstptr; const char *halfopnick; struct Client *targ_p; + int override = 0; if(!ConfigChannel.use_halfop) { @@ -1030,11 +1154,17 @@ chm_halfop(struct Client *source_p, struct Channel *chptr, if(alevel != CHFL_CHANOP && 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(IsOverride(source_p)) + override = 1; + else + { + + 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)) @@ -1072,7 +1202,14 @@ chm_halfop(struct Client *source_p, struct Channel *chptr, if(dir == MODE_ADD) { if(targ_p == source_p) - return; + { + 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; @@ -1081,6 +1218,7 @@ chm_halfop(struct Client *source_p, struct Channel *chptr, 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_HALFOP; @@ -1101,6 +1239,7 @@ chm_halfop(struct Client *source_p, struct Channel *chptr, 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_HALFOP; @@ -1115,14 +1254,21 @@ chm_voice(struct Client *source_p, struct Channel *chptr, struct membership *mstptr; const char *opnick; struct Client *targ_p; + int override = 0; 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(IsOverride(source_p)) + override = 1; + else + { + + 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) @@ -1166,6 +1312,7 @@ chm_voice(struct Client *source_p, struct Channel *chptr, 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_VOICE; @@ -1179,6 +1326,7 @@ chm_voice(struct Client *source_p, struct Channel *chptr, 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_VOICE; @@ -1193,14 +1341,20 @@ chm_limit(struct Client *source_p, struct Channel *chptr, const char *lstr; static char limitstr[30]; int limit; + int override = 0; 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(IsOverride(source_p)) + override = 1; + else + { + 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) @@ -1225,6 +1379,7 @@ chm_limit(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = limitstr; chptr->mode.limit = limit; @@ -1242,6 +1397,7 @@ chm_limit(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = NULL; } } @@ -1252,14 +1408,21 @@ chm_throttle(struct Client *source_p, struct Channel *chptr, const char **parv, int *errors, int dir, char c, long mode_type) { int joins = 0, timeslice = 0; + int override = 0; 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(IsOverride(source_p)) + override = 1; + else + { + + 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) @@ -1281,6 +1444,7 @@ chm_throttle(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = parv[(*parn)]; (*parn)++; @@ -1304,6 +1468,7 @@ chm_throttle(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = NULL; } } @@ -1316,6 +1481,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr, struct Channel *targptr = NULL; struct membership *msptr; const char *forward; + int override = 0; /* if +f is disabled, ignore local attempts to set it */ if(!ConfigChannel.use_forward && MyClient(source_p) && @@ -1338,11 +1504,16 @@ chm_forward(struct Client *source_p, struct Channel *chptr, #ifndef FORWARD_OPERONLY 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(IsOverride(source_p)) + override = 1; + else + { + 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; + } } #else if(!IsOper(source_p) && !IsServer(source_p)) @@ -1388,9 +1559,14 @@ chm_forward(struct Client *source_p, struct Channel *chptr, if((msptr = find_channel_membership(targptr, source_p)) == NULL || is_any_op(msptr)) { - sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), - me.name, source_p->name, targptr->chname); - return; + if(IsOverride(source_p)) + override = 1; + else + { + sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, targptr->chname); + return; + } } } @@ -1402,6 +1578,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ConfigChannel.use_forward ? ALL_MEMBERS : ONLY_SERVERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = forward; } else if(dir == MODE_DEL) @@ -1417,6 +1594,7 @@ chm_forward(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = NULL; } } @@ -1427,14 +1605,20 @@ chm_key(struct Client *source_p, struct Channel *chptr, const char **parv, int *errors, int dir, char c, long mode_type) { char *key; + int override = 0; 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(IsOverride(source_p)) + override = 1; + else + { + 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) @@ -1465,6 +1649,7 @@ chm_key(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = chptr->mode.key; } else if(dir == MODE_DEL) @@ -1496,6 +1681,7 @@ chm_key(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = "*"; } } @@ -1505,13 +1691,20 @@ 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) { + int override = 0; + 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(IsOverride(source_p)) + override = 1; + else + { + 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) @@ -1535,6 +1728,7 @@ chm_regonly(struct Client *source_p, struct Channel *chptr, mode_changes[mode_count].nocaps = 0; mode_changes[mode_count].mems = ALL_MEMBERS; mode_changes[mode_count].id = NULL; + mode_changes[mode_count].override = override; mode_changes[mode_count++].arg = NULL; } @@ -1619,7 +1813,7 @@ struct ChannelMode chmode_table[256] = {chm_simple, MODE_NOREJOIN }, /* J */ {chm_simple, MODE_NOREPEAT }, /* K */ {chm_staff, MODE_EXLIMIT }, /* L */ - {chm_nosuch, 0 }, /* M */ + {chm_hidden, MODE_NOOPERKICK }, /* M */ {chm_simple, MODE_NONICK }, /* N */ {chm_nosuch, 0 }, /* O */ {chm_staff, MODE_PERMANENT }, /* P */ @@ -1837,6 +2031,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, const char *ml = parv[0]; char c; struct Client *fakesource_p; + int flags_list[3] = { ALL_MEMBERS, ONLY_CHANOPS, ONLY_OPERS }; mask_pos = 0; mode_count = 0; @@ -1845,6 +2040,8 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, alevel = get_channel_access(source_p, msptr); + no_override_deop = 0; + /* Hide connecting server on netburst -- jilles */ if (ConfigServerHide.flatten_links && IsServer(source_p) && !has_id(source_p) && !HasSentEob(source_p)) fakesource_p = &me; @@ -1884,18 +2081,24 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, source_p->name, source_p->username, source_p->host, chptr->chname); - for (override = 0; override < (IsOverride(source_p) ? 2 : 1); ++override) + mlen = 0; + + for (override = 0; override < (IsOverride(source_p) && alevel != CHFL_CHANOP ? 2 : 1); ++override) { int was_on_chan = 0; + if(override) { if(msptr) + { was_on_chan = 1; + msptr->flags |= CHFL_CHANOP; + } else - add_user_to_channel(chptr, source_p, 0); + add_user_to_channel(chptr, source_p, CHFL_CHANOP); } - for(j = 0, flags = ALL_MEMBERS; j < 2; j++, flags = ONLY_CHANOPS) + for(j = 0, flags = flags_list[0]; j < 3; j++, flags = flags_list[j]) { cur_len = mlen; mbuf = modebuf + mlen; @@ -1907,6 +2110,7 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, for(i = 0; i < mode_count; i++) { if(mode_changes[i].letter == 0 || mode_changes[i].mems != flags) + continue; if(mode_changes[i].override != override) continue; @@ -1925,15 +2129,15 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, * bufsize (4 == +/-,modechar,two spaces) send now. */ if(mode_changes[i].arg != NULL && - ((paracount == MAXMODEPARAMSSERV) || - ((cur_len + paralen + arglen + 4) > (BUFSIZE - 3)))) + ((paracount == MAXMODEPARAMSSERV) || + ((cur_len + paralen + arglen + 4) > (BUFSIZE - 3)))) { *mbuf = '\0'; if(cur_len > mlen) { sendto_channel_local(flags, chptr, "%s%s %s", - cmdbuf, modebuf, parabuf); + cmdbuf, modebuf, parabuf); if(override) sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s is overriding modes on %s: %s %s", @@ -1970,11 +2174,30 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, } } - if(override && !was_on_chan) + if(paralen && parabuf[paralen - 1] == ' ') + parabuf[paralen - 1] = '\0'; + + *mbuf = '\0'; + if(cur_len > mlen) + { + sendto_channel_local(flags, chptr, "%s%s %s", cmdbuf, modebuf, parabuf); + if(override) + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + "%s is overriding modes on %s: %s %s", + get_oper_name(source_p), chptr->chname, + modebuf, parabuf); + } + } + if(override) + { + if(!was_on_chan) remove_user_from_channel(find_channel_membership(chptr, source_p)); + else if (!no_override_deop) + msptr->flags &= ~CHFL_CHANOP; + } } + /* only propagate modes originating locally, or if we're hubbing */ if(MyClient(source_p) || rb_dlink_list_length(&serv_list) > 1) send_cap_mode_changes(client_p, source_p, chptr, mode_changes, mode_count); - } }