+ }
+ return MODEACTION_DENY;
+ }
+};
+
+/** Abstraction of FounderProtectBase for channel mode +q
+ */
+class ChanFounder : public ModeHandler, public FounderProtectBase
+{
+ char* dummyptr;
+ public:
+ ChanFounder(InspIRCd* Instance, bool using_prefixes, bool depriv_self)
+ : ModeHandler(Instance, 'q', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '~' : 0),
+ FounderProtectBase(Instance, "cm_founder_", "founder", 386, 387, depriv_self) { }
+
+ unsigned int GetPrefixRank()
+ {
+ return FOUNDER_VALUE;
+ }
+
+ ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
+ {
+ return FounderProtectBase::ModeSet(source, dest, channel, parameter);
+ }
+
+ void RemoveMode(chanrec* channel)
+ {
+ FounderProtectBase::RemoveMode(channel, this->GetModeChar());
+ }
+
+ void RemoveMode(userrec* user)
+ {
+ }
+
+ ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
+ {
+ userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel);
+
+ if (!theuser)
+ {
+ return MODEACTION_DENY;
+ }
+
+ // source is a server, or ulined, we'll let them +-q the user.
+ if ((unload_kludge) || ((source == theuser) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (!IS_LOCAL(source)))
+ {
+ return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
+ }
+ else
+ {
+ // whoops, someones being naughty!
+ source->WriteServ("468 %s %s :Only servers may set channel mode +q",source->nick, channel->name);
+ parameter = "";
+ return MODEACTION_DENY;
+ }
+ }
+
+ void DisplayList(userrec* user, chanrec* channel)
+ {
+ FounderProtectBase::DisplayList(user,channel);
+ }
+};
+
+/** Abstraction of FounderProtectBase for channel mode +a
+ */
+class ChanProtect : public ModeHandler, public FounderProtectBase
+{
+ char* dummyptr;
+ public:
+ ChanProtect(InspIRCd* Instance, bool using_prefixes, bool depriv_self)
+ : ModeHandler(Instance, 'a', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '&' : 0),
+ FounderProtectBase(Instance,"cm_protect_","protected user", 388, 389, depriv_self) { }
+
+ unsigned int GetPrefixRank()
+ {
+ return PROTECT_VALUE;
+ }
+
+ ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter)
+ {
+ return FounderProtectBase::ModeSet(source, dest, channel, parameter);
+ }
+
+ void RemoveMode(chanrec* channel)
+ {
+ FounderProtectBase::RemoveMode(channel, this->GetModeChar());
+ }
+
+ void RemoveMode(userrec* user)
+ {
+ }
+
+ ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding)
+ {
+ userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel);
+
+ if (!theuser)
+ return MODEACTION_DENY;
+
+ std::string founder = "cm_founder_"+std::string(channel->name);
+
+ // source has +q, is a server, or ulined, we'll let them +-a the user.
+ if ((unload_kludge) || ((source == theuser) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (source->GetExt(founder,dummyptr)) || (!IS_LOCAL(source)))
+ {
+ return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
+ }
+ else
+ {
+ // bzzzt, wrong answer!
+ source->WriteServ("482 %s %s :You are not a channel founder",source->nick, channel->name);
+ return MODEACTION_DENY;
+ }
+ }
+
+ virtual void DisplayList(userrec* user, chanrec* channel)
+ {
+ FounderProtectBase::DisplayList(user, channel);
+ }
+
+};
+
+class ModuleChanProtect : public Module
+{
+
+ bool FirstInGetsFounder;
+ bool QAPrefixes;
+ bool DeprivSelf;
+ bool booting;
+ ChanProtect* cp;
+ ChanFounder* cf;
+ char* dummyptr;
+
+ public:
+
+ ModuleChanProtect(InspIRCd* Me)
+ : Module::Module(Me), FirstInGetsFounder(false), QAPrefixes(false), DeprivSelf(false), booting(true)
+ {
+ /* Load config stuff */
+ OnRehash("");
+ booting = false;
+
+ /* Initialise module variables */
+
+ cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf);
+ cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf);
+
+ ServerInstance->AddMode(cp, 'a');
+ ServerInstance->AddMode(cf, 'q');
+ }
+
+ void Implements(char* List)
+ {
+ List[I_OnUserKick] = List[I_OnUserPart] = List[I_OnRehash] = List[I_OnUserJoin] = List[I_OnAccessCheck] = List[I_OnSyncChannel] = 1;
+ }
+
+ virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason)
+ {
+ // FIX: when someone gets kicked from a channel we must remove their Extensibles!
+ user->Shrink("cm_founder_"+std::string(chan->name));
+ user->Shrink("cm_protect_"+std::string(chan->name));
+ }
+
+ virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason)
+ {
+ // FIX: when someone parts a channel we must remove their Extensibles!
+ user->Shrink("cm_founder_"+std::string(channel->name));
+ user->Shrink("cm_protect_"+std::string(channel->name));
+ }
+
+ virtual void OnRehash(const std::string ¶meter)
+ {
+ /* Create a configreader class and read our flag,
+ * in old versions this was heap-allocated and the
+ * object was kept between rehashes...now we just
+ * stack-allocate it locally.
+ */
+ ConfigReader Conf(ServerInstance);
+
+ bool old_qa = QAPrefixes;
+
+ FirstInGetsFounder = Conf.ReadFlag("options","noservices",0);
+ QAPrefixes = Conf.ReadFlag("options","qaprefixes",0);
+ DeprivSelf = Conf.ReadFlag("options","deprotectself",0);
+
+ /* Did the user change the QA prefixes on the fly?
+ * If so, remove all instances of the mode, and reinit
+ * the module with prefixes enabled.
+ */
+ if ((old_qa != QAPrefixes) && (!booting))
+ {
+ ServerInstance->Modes->DelMode(cp);
+ ServerInstance->Modes->DelMode(cf);
+ DELETE(cp);
+ DELETE(cf);
+ cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf);
+ cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf);
+ ServerInstance->AddMode(cp, 'a');
+ ServerInstance->AddMode(cf, 'q');
+ ServerInstance->WriteOpers("*** WARNING: +qa prefixes were enabled or disabled via a REHASH. Clients will probably need to reconnect to pick up this change.");
+ }
+ }
+
+ virtual void OnUserJoin(userrec* user, chanrec* channel)
+ {
+ // if the user is the first user into the channel, mark them as the founder, but only if
+ // the config option for it is set
+ if (FirstInGetsFounder)
+ {
+ if (channel->GetUserCounter() == 1)