diff --git a/extensions/m_remove.c b/extensions/m_remove.c index 03ea99ad..f3acbd81 100644 --- a/extensions/m_remove.c +++ b/extensions/m_remove.c @@ -108,7 +108,7 @@ m_remove(struct Client *client_p, struct Client *source_p, int parc, const char return 0; } - if(get_channel_access(source_p, msptr) < CHFL_CHANOP) + if(get_channel_access(source_p, msptr, MODE_ADD) < CHFL_CHANOP) { if(MyConnect(source_p)) { @@ -178,6 +178,7 @@ m_remove(struct Client *client_p, struct Client *source_p, int parc, const char hookdata.msptr = msptr; hookdata.target = who; hookdata.approved = 1; + hookdata.dir = MODE_ADD; /* ensure modules like override speak up */ call_hook(h_can_kick, &hookdata); diff --git a/extensions/override.c b/extensions/override.c index 90524c62..3bdf4bd3 100644 --- a/extensions/override.c +++ b/extensions/override.c @@ -153,6 +153,9 @@ hack_channel_access(void *vdata) { hook_data_channel_approval *data = (hook_data_channel_approval *) vdata; + if (data->dir == MODE_QUERY) + return; + if (data->approved == CHFL_CHANOP) return; @@ -189,6 +192,9 @@ hack_can_send(void *vdata) { hook_data_channel_approval *data = (hook_data_channel_approval *) vdata; + if (data->dir == MODE_QUERY) + return; + if (data->approved == CAN_SEND_NONOP || data->approved == CAN_SEND_OPV) return; diff --git a/include/channel.h b/include/channel.h index 0f8bd314..2304aa4b 100644 --- a/include/channel.h +++ b/include/channel.h @@ -270,7 +270,7 @@ extern int match_extban(const char *banstr, struct Client *client_p, struct Chan extern int valid_extban(const char *banstr, struct Client *client_p, struct Channel *chptr, long mode_type); const char * get_extban_string(void); -extern int get_channel_access(struct Client *source_p, struct membership *msptr); +extern int get_channel_access(struct Client *source_p, struct membership *msptr, int dir); extern void send_channel_join(struct Channel *chptr, struct Client *client_p); diff --git a/include/hook.h b/include/hook.h index 88f6cc73..c2bf69e8 100644 --- a/include/hook.h +++ b/include/hook.h @@ -82,6 +82,7 @@ typedef struct struct membership *msptr; struct Client *target; int approved; + int dir; } hook_data_channel_approval; typedef struct diff --git a/modules/core/m_kick.c b/modules/core/m_kick.c index cf45f636..38753461 100644 --- a/modules/core/m_kick.c +++ b/modules/core/m_kick.c @@ -97,7 +97,7 @@ m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *p return 0; } - if(get_channel_access(source_p, msptr) < CHFL_CHANOP) + if(get_channel_access(source_p, msptr, MODE_ADD) < CHFL_CHANOP) { if(MyConnect(source_p)) { @@ -167,6 +167,7 @@ m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *p hookdata.msptr = msptr; hookdata.target = who; hookdata.approved = 1; + hookdata.dir = MODE_ADD; /* ensure modules like override speak up */ call_hook(h_can_kick, &hookdata); diff --git a/modules/m_topic.c b/modules/m_topic.c index 318eea02..b59378a3 100644 --- a/modules/m_topic.c +++ b/modules/m_topic.c @@ -119,7 +119,7 @@ m_topic(struct Client *client_p, struct Client *source_p, int parc, const char * } if(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || - get_channel_access(source_p, msptr) >= CHFL_CHANOP) && + get_channel_access(source_p, msptr, MODE_ADD) >= CHFL_CHANOP) && (!MyClient(source_p) || can_send(chptr, source_p, msptr))) { diff --git a/src/channel.c b/src/channel.c index bbb09a3d..5f3f56cc 100644 --- a/src/channel.c +++ b/src/channel.c @@ -821,6 +821,7 @@ can_send(struct Channel *chptr, struct Client *source_p, struct membership *mspt hook_data_channel_approval moduledata; moduledata.approved = CAN_SEND_NONOP; + moduledata.dir = MODE_QUERY; if(IsServer(source_p) || IsService(source_p)) return CAN_SEND_OPV; @@ -871,6 +872,7 @@ can_send(struct Channel *chptr, struct Client *source_p, struct membership *mspt moduledata.chptr = msptr->chptr; moduledata.msptr = msptr; moduledata.target = NULL; + moduledata.dir = (moduledata.approved == CAN_SEND_NO) ? MODE_ADD : MODE_QUERY; call_hook(h_can_send, &moduledata); diff --git a/src/chmode.c b/src/chmode.c index 37906113..20ad88c7 100644 --- a/src/chmode.c +++ b/src/chmode.c @@ -179,7 +179,7 @@ cflag_orphan(char c_) } int -get_channel_access(struct Client *source_p, struct membership *msptr) +get_channel_access(struct Client *source_p, struct membership *msptr, int dir) { hook_data_channel_approval moduledata; @@ -194,6 +194,7 @@ get_channel_access(struct Client *source_p, struct membership *msptr) moduledata.msptr = msptr; moduledata.target = NULL; moduledata.approved = is_chanop(msptr) ? CHFL_CHANOP : CHFL_PEON; + moduledata.dir = dir; call_hook(h_get_channel_access, &moduledata); @@ -518,7 +519,7 @@ check_forward(struct Client *source_p, struct Channel *chptr, if(MyClient(source_p) && !(targptr->mode.mode & MODE_FREETARGET)) { if((msptr = find_channel_membership(targptr, source_p)) == NULL || - get_channel_access(source_p, msptr) != CHFL_CHANOP) + get_channel_access(source_p, msptr, MODE_QUERY) != CHFL_CHANOP) { sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name, source_p->name, targptr->chname); @@ -1632,13 +1633,14 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, char *pbuf; int cur_len, mlen, paralen, paracount, arglen, len; int i, j, flags; - int dir = MODE_ADD; + int dir = MODE_QUERY; int parn = 1; int errors = 0; int alevel; const char *ml = parv[0]; char c; struct Client *fakesource_p; + int reauthorized = 0; /* if we change from MODE_QUERY to MODE_ADD/MODE_DEL, then reauth once, ugly but it works */ mask_pos = 0; removed_mask_pos = 0; @@ -1646,23 +1648,33 @@ set_channel_mode(struct Client *client_p, struct Client *source_p, mode_limit = 0; mode_limit_simple = 0; - alevel = get_channel_access(source_p, msptr); - /* Hide connecting server on netburst -- jilles */ if (ConfigServerHide.flatten_links && IsServer(source_p) && !has_id(source_p) && !HasSentEob(source_p)) fakesource_p = &me; else fakesource_p = source_p; + alevel = get_channel_access(source_p, msptr, dir); + for(; (c = *ml) != 0; ml++) { switch (c) { case '+': dir = MODE_ADD; + if (!reauthorized) + { + alevel = get_channel_access(source_p, msptr, dir); + reauthorized = 1; + } break; case '-': dir = MODE_DEL; + if (!reauthorized) + { + alevel = get_channel_access(source_p, msptr, dir); + reauthorized = 1; + } break; case '=': dir = MODE_QUERY;