From eccd1c58d258a4201ea54cc4811c8b0387f7de05 Mon Sep 17 00:00:00 2001 From: JD Horelick Date: Tue, 2 Mar 2010 19:54:59 -0500 Subject: [PATCH] Initial support for 'noisy' oper-override of channel modes, using omode-type code. Supports simple modes at present. --- include/channel.h | 1 + src/chmode.c | 177 ++++++++++++++++++++++++++-------------------- 2 files changed, 103 insertions(+), 75 deletions(-) diff --git a/include/channel.h b/include/channel.h index 0627dd5..1744acd 100644 --- a/include/channel.h +++ b/include/channel.h @@ -114,6 +114,7 @@ struct ChModeChange int caps; int nocaps; int mems; + int override; struct Client *client; }; diff --git a/src/chmode.c b/src/chmode.c index 52912b6..2784ddc 100644 --- a/src/chmode.c +++ b/src/chmode.c @@ -498,13 +498,21 @@ 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) { + + 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(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE)) @@ -526,6 +534,7 @@ chm_simple(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 = override; mode_changes[mode_count++].arg = NULL; } else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type)) @@ -538,6 +547,7 @@ chm_simple(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; } } @@ -1813,12 +1823,13 @@ void set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr, struct membership *msptr, int parc, const char *parv[]) { + static char cmdbuf[BUFSIZE]; static char modebuf[BUFSIZE]; static char parabuf[BUFSIZE]; char *mbuf; char *pbuf; int cur_len, mlen, paralen, paracount, arglen, len; - int i, j, flags; + int i, j, flags, override; int dir = MODE_ADD; int parn = 1; int errors = 0; @@ -1867,87 +1878,103 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, return; if(IsServer(source_p)) - mlen = rb_sprintf(modebuf, ":%s MODE %s ", fakesource_p->name, chptr->chname); + rb_sprintf(cmdbuf, ":%s MODE %s ", fakesource_p->name, chptr->chname); else - mlen = rb_sprintf(modebuf, ":%s!%s@%s MODE %s ", + rb_sprintf(cmdbuf, ":%s!%s@%s MODE %s ", source_p->name, source_p->username, source_p->host, chptr->chname); - for(j = 0, flags = ALL_MEMBERS; j < 2; j++, flags = ONLY_CHANOPS) + for (override = 0; override < (IsOverride(source_p) ? 2 : 1); ++override) { - cur_len = mlen; - mbuf = modebuf + mlen; - pbuf = parabuf; - parabuf[0] = '\0'; - paracount = paralen = 0; - dir = MODE_QUERY; - - for(i = 0; i < mode_count; i++) + int was_on_chan = 0; + if(override) { - if(mode_changes[i].letter == 0 || mode_changes[i].mems != flags) - continue; - - if(mode_changes[i].arg != NULL) - { - arglen = strlen(mode_changes[i].arg); - - if(arglen > MODEBUFLEN - 5) - continue; - } + if(msptr) + was_on_chan = 1; else - arglen = 0; - - /* if we're creeping over MAXMODEPARAMSSERV, or over - * bufsize (4 == +/-,modechar,two spaces) send now. - */ - if(mode_changes[i].arg != NULL && - ((paracount == MAXMODEPARAMSSERV) || - ((cur_len + paralen + arglen + 4) > (BUFSIZE - 3)))) - { - *mbuf = '\0'; - - if(cur_len > mlen) - sendto_channel_local(flags, chptr, "%s %s", modebuf, - parabuf); - else - continue; - - paracount = paralen = 0; - cur_len = mlen; - mbuf = modebuf + mlen; - pbuf = parabuf; - parabuf[0] = '\0'; - dir = MODE_QUERY; - } - - if(dir != mode_changes[i].dir) - { - *mbuf++ = (mode_changes[i].dir == MODE_ADD) ? '+' : '-'; - cur_len++; - dir = mode_changes[i].dir; - } - - *mbuf++ = mode_changes[i].letter; - cur_len++; - - if(mode_changes[i].arg != NULL) - { - paracount++; - len = rb_sprintf(pbuf, "%s ", mode_changes[i].arg); - pbuf += len; - paralen += len; - } + add_user_to_channel(chptr, source_p, 0); } - if(paralen && parabuf[paralen - 1] == ' ') - parabuf[paralen - 1] = '\0'; + for(j = 0, flags = ALL_MEMBERS; j < 2; j++, flags = ONLY_CHANOPS) + { + cur_len = mlen; + mbuf = modebuf + mlen; + pbuf = parabuf; + parabuf[0] = '\0'; + paracount = paralen = 0; + dir = MODE_QUERY; - *mbuf = '\0'; - if(cur_len > mlen) - sendto_channel_local(flags, chptr, "%s %s", modebuf, parabuf); + for(i = 0; i < mode_count; i++) + { + if(mode_changes[i].letter == 0 || mode_changes[i].mems != flags) + + if(mode_changes[i].override != override) + continue; + + if(mode_changes[i].arg != NULL) + { + arglen = strlen(mode_changes[i].arg); + + if(arglen > MODEBUFLEN - 5) + continue; + } + else + arglen = 0; + + /* if we're creeping over MAXMODEPARAMSSERV, or over + * bufsize (4 == +/-,modechar,two spaces) send now. + */ + if(mode_changes[i].arg != NULL && + ((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); + 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); + } + else + continue; + + paracount = paralen = 0; + cur_len = mlen; + mbuf = modebuf + mlen; + pbuf = parabuf; + parabuf[0] = '\0'; + dir = MODE_QUERY; + } + + if(dir != mode_changes[i].dir) + { + *mbuf++ = (mode_changes[i].dir == MODE_ADD) ? '+' : '-'; + cur_len++; + dir = mode_changes[i].dir; + } + + *mbuf++ = mode_changes[i].letter; + cur_len++; + + if(mode_changes[i].arg != NULL) + { + paracount++; + len = rb_sprintf(pbuf, "%s ", mode_changes[i].arg); + pbuf += len; + paralen += len; + } + } + + if(override && !was_on_chan) + remove_user_from_channel(find_channel_membership(chptr, source_p)); } - /* 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); + } }