diff --git a/Changes b/Changes
index ac1b5b997..4f810ab9d 100644
--- a/Changes
+++ b/Changes
@@ -2030,3 +2030,5 @@ seen. gmtime warning still there
Thanks to ora and others which helped me tracing this down.
- Added tld::options::ssl so you can have different motd/rules files if the user is using SSL.
- Fixed cloaking bug reported by Rocko (#0000869).
+- Added set::restrict-channelmodes, works exactly the same as restrict-usermodes, you can for
+ example disallow using of channelmode u and L. Suggested by poisoner and others (#0000838).
diff --git a/doc/unreal32docs.html b/doc/unreal32docs.html
index 816adb325..811d241ba 100644
--- a/doc/unreal32docs.html
+++ b/doc/unreal32docs.html
@@ -1648,6 +1648,10 @@ set {
Restrict users to set/unset the modes listed here (don't use + or -).
For example you can set +G in modes-on-connect and G in restrict-usermodes,
that way you can force all users to be +G and unable to do -G.
set::restrict-channelmodes <modes>
+ Restrict users to set/unset the channelmodes listed here (don't use + or -).
+ For example you can set +G in modes-on-join and G in restrict-channelmodes,
+ that way you can force all (new) channels to be +G and unable to do -G.
set::auto-join <channels>;
The channel(s) a user will be forced to join at connection. To specify more
than one channel use a comma seperated list.
diff --git a/include/dynconf.h b/include/dynconf.h
index 8527884bd..d2571ae72 100644
--- a/include/dynconf.h
+++ b/include/dynconf.h
@@ -96,6 +96,7 @@ struct zConfiguration {
#endif
enum UHAllowed userhost_allowed;
char *restrict_usermodes;
+ char *restrict_channelmodes;
long unknown_flood_bantime;
long unknown_flood_amount;
struct ChMode modes_on_join;
@@ -161,6 +162,7 @@ extern aConfiguration iConf;
#define STATIC_QUIT iConf.static_quit
#define UHOST_ALLOWED iConf.userhost_allowed
#define RESTRICT_USERMODES iConf.restrict_usermodes
+#define RESTRICT_CHANNELMODES iConf.restrict_channelmodes
#ifdef THROTTLING
#define THROTTLING_PERIOD iConf.throttle_period
#endif
diff --git a/src/channel.c b/src/channel.c
index 79a4312f0..694b4842a 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -2211,6 +2211,7 @@ void set_mode(aChannel *chptr, aClient *cptr, int parc, char *parv[], u_int *pco
int found = 0;
unsigned int htrig = 0;
long oldm, oldl;
+ int checkrestr = 0, warnrestr = 1;
paracount = 1;
*pcount = 0;
@@ -2218,8 +2219,22 @@ void set_mode(aChannel *chptr, aClient *cptr, int parc, char *parv[], u_int *pco
oldm = chptr->mode.mode;
oldl = chptr->mode.limit;
+ if (RESTRICT_CHANNELMODES && MyClient(cptr) && !IsAnOper(cptr) && !IsServer(cptr)) /* "cache" this */
+ checkrestr = 1;
+
for (curchr = parv[0]; *curchr; curchr++)
{
+ if (checkrestr && strchr(RESTRICT_CHANNELMODES, *curchr))
+ {
+ if (warnrestr)
+ {
+ sendto_one(cptr, ":%s NOTICE %s :Setting/removing of channelmode(s) '%s' has been disabled.",
+ me.name, cptr->name, RESTRICT_CHANNELMODES);
+ warnrestr = 0;
+ }
+ continue;
+ }
+
switch (*curchr)
{
case '+':
diff --git a/src/s_conf.c b/src/s_conf.c
index 8fcd28157..739b9864e 100644
--- a/src/s_conf.c
+++ b/src/s_conf.c
@@ -1124,6 +1124,7 @@ void free_iConf(aConfiguration *i)
ircfree(i->trusted_ca_file);
#endif
ircfree(i->restrict_usermodes);
+ ircfree(i->restrict_channelmodes);
ircfree(i->network.x_ircnetwork);
ircfree(i->network.x_ircnet005);
ircfree(i->network.x_defserv);
@@ -2202,6 +2203,9 @@ void report_dynconf(aClient *sptr)
if (RESTRICT_USERMODES)
sendto_one(sptr, ":%s %i %s :restrict-usermodes: %s", me.name, RPL_TEXT,
sptr->name, RESTRICT_USERMODES);
+ if (RESTRICT_CHANNELMODES)
+ sendto_one(sptr, ":%s %i %s :restrict-channelmodes: %s", me.name, RPL_TEXT,
+ sptr->name, RESTRICT_CHANNELMODES);
switch (UHOST_ALLOWED)
{
case UHALLOW_ALWAYS:
@@ -4980,6 +4984,18 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce)
*x = '\0';
tempiConf.restrict_usermodes = p;
}
+ else if (!strcmp(cep->ce_varname, "restrict-channelmodes")) {
+ int i;
+ char *p = MyMalloc(strlen(cep->ce_vardata) + 1), *x = p;
+ /* The data should be something like 'GL' or something,
+ * but just in case users use '+GL' then ignore the + (and -).
+ */
+ for (i=0; i < strlen(cep->ce_vardata); i++)
+ if ((cep->ce_vardata[i] != '+') && (cep->ce_vardata[i] != '-'))
+ *x++ = cep->ce_vardata[i];
+ *x = '\0';
+ tempiConf.restrict_channelmodes = p;
+ }
else if (!strcmp(cep->ce_varname, "anti-spam-quit-message-time")) {
tempiConf.anti_spam_quit_message_time = config_checkval(cep->ce_vardata,CFG_TIME);
}
@@ -5374,6 +5390,21 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
}
}
}
+ else if (!strcmp(cep->ce_varname, "restrict-channelmodes"))
+ {
+ CheckNull(cep);
+ if (cep->ce_varname) {
+ int warn = 0;
+ char *p;
+ for (p = cep->ce_vardata; *p; p++)
+ if ((*p == '+') || (*p == '-'))
+ warn = 1;
+ if (warn) {
+ config_status("%s:%i: warning: set::restrict-channelmodes: should only contain modechars, no + or -.\n",
+ cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
+ }
+ }
+ }
else if (!strcmp(cep->ce_varname, "dns")) {
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
CheckNull(cepp);
diff --git a/src/s_user.c b/src/s_user.c
index 5e45db6c4..4c179d0ca 100644
--- a/src/s_user.c
+++ b/src/s_user.c
@@ -2234,10 +2234,9 @@ CMD_FUNC(m_umode)
char **p, *m;
aClient *acptr;
int what, setflags, setsnomask = 0;
- short rpterror = 0, umode_restrict_err = 0, modex_err = 0, oper;
+ short rpterror = 0, umode_restrict_err = 0, chk_restrict = 0, modex_err = 0;
what = MODE_ADD;
- oper = IsAnOper(sptr) ? 1 : 0;
if (parc < 2)
{
@@ -2273,6 +2272,9 @@ CMD_FUNC(m_umode)
if ((sptr->umodes & Usermode_Table[i].mode))
setflags |= Usermode_Table[i].mode;
+ if (RESTRICT_USERMODES && MyClient(sptr) && !IsAnOper(sptr) && !IsServer(sptr))
+ chk_restrict = 1;
+
if (MyConnect(sptr))
setsnomask = sptr->user->snomask;
/*
@@ -2281,8 +2283,7 @@ CMD_FUNC(m_umode)
p = &parv[2];
for (m = *p; *m; m++)
{
- if (MyClient(sptr) && RESTRICT_USERMODES &&
- !oper && strchr(RESTRICT_USERMODES, *m))
+ if (chk_restrict && strchr(RESTRICT_USERMODES, *m))
{
if (!umode_restrict_err)
{