From aa294a3a54f80df7e8c9d4d8eaae8a3d681a74c4 Mon Sep 17 00:00:00 2001 From: Sam Dodrill Date: Tue, 10 Sep 2013 07:08:49 -0700 Subject: [PATCH 1/3] 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 --- doc/example.conf | 1 + doc/reference.charybdis.conf | 10 ++ doc/reference.conf | 10 ++ extensions/m_ojoin.c | 16 +- extensions/m_omode.c | 39 ++++- include/channel.h | 7 +- include/chmode.h | 3 + include/s_conf.h | 1 + libratbox/src/version.c.last | 64 -------- modules/core/m_join.c | 296 ++++++++++++++++++++++++++++++++++- modules/m_info.c | 6 + src/channel.c | 53 ++++++- src/chmode.c | 154 +++++++++++++++--- src/newconf.c | 1 + src/s_conf.c | 1 + src/supported.c | 6 +- 16 files changed, 565 insertions(+), 103 deletions(-) delete mode 100644 libratbox/src/version.c.last diff --git a/doc/example.conf b/doc/example.conf index e7fd1ca..3216148 100755 --- a/doc/example.conf +++ b/doc/example.conf @@ -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; diff --git a/doc/reference.charybdis.conf b/doc/reference.charybdis.conf index 03c088d..a5625ed 100755 --- a/doc/reference.charybdis.conf +++ b/doc/reference.charybdis.conf @@ -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. diff --git a/doc/reference.conf b/doc/reference.conf index 5d0d7d6..1641b52 100755 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -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. diff --git a/extensions/m_ojoin.c b/extensions/m_ojoin.c index a58c083..96ad351 100644 --- a/extensions/m_ojoin.c +++ b/extensions/m_ojoin.c @@ -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, diff --git a/extensions/m_omode.c b/extensions/m_omode.c index c588c53..084208e 100644 --- a/extensions/m_omode.c +++ b/extensions/m_omode.c @@ -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 */ diff --git a/include/channel.h b/include/channel.h index 37751d7..553a928 100644 --- a/include/channel.h +++ b/include/channel.h @@ -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); diff --git a/include/chmode.h b/include/chmode.h index 915741f..e5d0b8e 100644 --- a/include/chmode.h +++ b/include/chmode.h @@ -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); diff --git a/include/s_conf.h b/include/s_conf.h index ab4a71d..0a52c7a 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -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; diff --git a/libratbox/src/version.c.last b/libratbox/src/version.c.last deleted file mode 100644 index 0818ab5..0000000 --- a/libratbox/src/version.c.last +++ /dev/null @@ -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 ", - "anfl, Lee Hardy ", - "Special thanks for support, code and ideas to:", - "Hwy, W. Campbell ", - "jilles, Jilles Tjoelker ", - "larne, Edward Brocklesby ", - " ", - "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, -}; diff --git a/modules/core/m_join.c b/modules/core/m_join.c index 61fdf18..ece4d6e 100644 --- a/modules/core/m_join.c +++ b/modules/core/m_join.c @@ -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; diff --git a/modules/m_info.c b/modules/m_info.c index dd14294..4ec27f3 100644 --- a/modules/m_info.c +++ b/modules/m_info.c @@ -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, diff --git a/src/channel.c b/src/channel.c index 57e9f50..aa365e6 100644 --- a/src/channel.c +++ b/src/channel.c @@ -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; } diff --git a/src/chmode.c b/src/chmode.c index 1cd08f6..cf6220d 100644 --- a/src/chmode.c +++ b/src/chmode.c @@ -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 */ diff --git a/src/newconf.c b/src/newconf.c index ed68cc6..f5c15a0 100644 --- a/src/newconf.c +++ b/src/newconf.c @@ -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 }, diff --git a/src/s_conf.c b/src/s_conf.c index e04941f..07e6242 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -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; diff --git a/src/supported.c b/src/supported.c index 84ec34a..2e08d99 100644 --- a/src/supported.c +++ b/src/supported.c @@ -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; From df8e2d39e73b6cf8591ad43684fb24dc2674e085 Mon Sep 17 00:00:00 2001 From: Sam Dodrill Date: Fri, 13 Sep 2013 17:07:49 -0700 Subject: [PATCH 2/3] Fix desync when using OJOIN as channel founder --- extensions/m_ojoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/m_ojoin.c b/extensions/m_ojoin.c index 96ad351..ce2b9da 100644 --- a/extensions/m_ojoin.c +++ b/extensions/m_ojoin.c @@ -101,7 +101,7 @@ mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char { add_user_to_channel(chptr, source_p, CHFL_OWNER); sendto_server(client_p, chptr, CAP_TS6, NOCAPS, - ":%s SJOIN %ld %s + :!%s", + ":%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, From 172deacb065d1db5f8dead0924fc06b8fa4088f2 Mon Sep 17 00:00:00 2001 From: Sam Dodrill Date: Fri, 13 Sep 2013 19:52:30 -0700 Subject: [PATCH 3/3] Finalize behavor of channel admins Channel admins are able to kick channel admins --- src/channel.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/channel.c b/src/channel.c index aa365e6..9075594 100644 --- a/src/channel.c +++ b/src/channel.c @@ -319,23 +319,25 @@ can_kick_deop(struct membership *source, struct membership *target) * Reworked the logic to match this: * - owners can do what they want * - admins cannot kick or deop owners + * - admins can kick or deop admins * - 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)) + if(is_owner(source)) return 1; + if(is_admin(source) && is_owner(target)) + return 0; + if(is_chanop(source) && is_owner(target)) + return 0; + if(is_chanop(source) && is_admin(target)) + return 0; + if(is_halfop(source) && is_any_op(target)) + return 0; + + return 1; - return 0; } /* add_user_to_channel()