/* +------------------------------------+ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * * InspIRCd: (C) 2002-2009 InspIRCd Development Team * See: http://wiki.inspircd.org/Credits * * This program is free but copyrighted software; see * the file COPYING for details. * * --------------------------------------------------- */ #include "inspircd.h" #include "protocol.h" #include "opflags.h" class OpFlagProviderImpl : public OpFlagProvider { public: LocalStringExt ext; OpFlagProviderImpl(Module* parent) : OpFlagProvider(parent, "opflags"), ext(EXTENSIBLE_MEMBERSHIP, "flaglist", parent) { } std::string GetFlags(Membership* memb) { std::string* v = ext.get(memb); if (v) return *v; return ""; } void SetFlags(Membership* memb, const std::string& flags, bool sendGlobal) { if (flags.empty()) ext.unset(memb); else ext.set(memb, flags); if (sendGlobal) { parameterlist encap; encap.push_back("*"); encap.push_back("OPFLAGS"); encap.push_back(memb->chan->name); encap.push_back(memb->user->uuid); encap.push_back(":=" + flags); ServerInstance->PI->SendEncapsulatedData(encap); } } std::string SetFlags(Membership* memb, const std::set& flags, bool sendGlobal) { std::string v; for(std::set::iterator i = flags.begin(); i != flags.end(); i++) { if (i != flags.begin()) v.push_back(','); v.append(*i); } SetFlags(memb, v, sendGlobal); return v; } bool PermissionCheck(Membership* memb, const std::string& needed) { if (!memb || needed.empty()) return false; std::string* mine = ext.get(memb); if (!mine) return false; irc::commasepstream flags(needed); std::string flag; while (flags.GetToken(flag)) { irc::commasepstream myflags(*mine); std::string myflag; while (myflags.GetToken(myflag)) { if (flag == myflag) return true; } } return false; } }; class FlagCmd : public Command { public: OpFlagProviderImpl prov; unsigned int conflevel; unsigned int usermax; FlagCmd(Module* parent) : Command(parent, "OPFLAGS", 1), prov(parent) { syntax = " [nick] {+-=}[]"; TRANSLATE4(TR_TEXT, TR_NICK, TR_TEXT, TR_END); } CmdResult Handle(const std::vector ¶meters, User *src) { Channel* chan = ServerInstance->FindChan(parameters[0]); if (!chan) { src->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", src->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } if (parameters.size() == 1) { std::map > opflags; std::string tmp; for(UserMembCIter i = chan->GetUsers()->begin(); i != chan->GetUsers()->end(); ++i) { irc::commasepstream flags(prov.GetFlags(i->second)); while(flags.GetToken(tmp)) opflags[tmp].push_back(i->first->nick); } for(std::map >::iterator i = opflags.begin(); i != opflags.end(); ++i) { for(std::vector::iterator j = i->second.begin(); j != i->second.end(); ++j) { if(j == i->second.begin()) tmp.clear(); else tmp.push_back(','); tmp.append(*j); } src->WriteNumeric(926, "%s %s %s %s :Opflag is held by these users", src->nick.c_str(), chan->name.c_str(), i->first.c_str(), tmp.c_str()); } src->WriteNumeric(925, "%s %s :End of channel opflags", src->nick.c_str(), chan->name.c_str()); return CMD_SUCCESS; } User* user = ServerInstance->FindNick(parameters[1]); if (!user) { src->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", src->nick.c_str(), parameters[1].c_str()); return CMD_FAILURE; } Membership* memb = chan->GetUser(user); if (!memb) { src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s %s :They are not on that channel", src->nick.c_str(), user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } std::string* ptr = prov.ext.get(memb); if (parameters.size() == 2) { if(ptr) src->WriteNumeric(923, "%s %s %s %s :Opflags held", src->nick.c_str(), chan->name.c_str(), user->nick.c_str(), ptr->c_str()); else src->WriteNumeric(924, "%s %s %s :No opflags held", src->nick.c_str(), chan->name.c_str(), user->nick.c_str()); return CMD_SUCCESS; } std::string delta = parameters[2]; if (IS_LOCAL(src)) { OpFlagPermissionData perm(src, chan, user, delta); FOR_EACH_MOD(OnPermissionCheck, (perm)); if (!perm.result.check(chan->GetAccessRank(src) >= conflevel)) { src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You cannot change opflags on this channel.", src->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } } std::string flag; std::set flags; if (ptr) { irc::commasepstream myflags(*ptr); while (myflags.GetToken(flag)) flags.insert(flag); } bool adding = true; irc::commasepstream deltaflags(delta); while (deltaflags.GetToken(flag)) { if (flag[0] == '=') { flags.clear(); flag = flag.substr(1); } else if (flag[0] == '+' || flag[0] == '-') { adding = (flag[0] == '+'); flag = flag.substr(1); } if (flag.empty()) continue; if (adding) flags.insert(flag); else flags.erase(flag); } if (IS_LOCAL(src) && flags.size() > usermax) { src->WriteNumeric(920, "%s %s %s :User would have too many opflags set", src->nick.c_str(), chan->name.c_str(), user->nick.c_str()); return CMD_FAILURE; } if (flags.empty()) { prov.ext.unset(memb); if (!IS_SERVER(src)) for (UserMembIter i = chan->userlist.begin(); i != chan->userlist.end(); ++i) if (IS_LOCAL(i->first)) i->first->WriteNumeric(922, "%s %s %s %s :Removed all opflags from", i->first->nick.c_str(), chan->name.c_str(), src->nick.c_str(), user->nick.c_str()); } else { std::string v = prov.SetFlags(memb, flags, false); if (!IS_SERVER(src)) for (UserMembIter i = chan->userlist.begin(); i != chan->userlist.end(); ++i) if (IS_LOCAL(i->first)) i->first->WriteNumeric(921, "%s %s %s %s %s :Set opflags to", i->first->nick.c_str(), chan->name.c_str(), src->nick.c_str(), user->nick.c_str(), v.c_str()); } return CMD_SUCCESS; } RouteDescriptor GetRouting(User* user, const std::vector& parameters) { if (parameters.size() == 2) return ROUTE_LOCALONLY; return ROUTE_OPT_BCAST; } }; class ModuleOpFlags : public Module { FlagCmd cmd; public: ModuleOpFlags() : cmd(this) { } void init() { ServerInstance->Modules->AddService(cmd); ServerInstance->Modules->AddService(cmd.prov); ServerInstance->Modules->AddService(cmd.prov.ext); Implementation eventlist[] = { I_OnSyncChannel, I_OnPermissionCheck }; ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } void ReadConfig(ConfigReadStatus&) { ConfigTag* tag = ServerInstance->Config->GetTag("opflags"); cmd.conflevel = tag->getInt("level", OP_VALUE); cmd.usermax = tag->getInt("maxflags", 15); } void OnSyncChannel(Channel* channel, SyncTarget* target) { const UserMembList* users = channel->GetUsers(); for(UserMembCIter u = users->begin(); u != users->end(); u++) { std::string* ptr = cmd.prov.ext.get(u->second); if (ptr) { parameterlist flags; flags.push_back(channel->name); flags.push_back(u->first->uuid); flags.push_back(*ptr); target->SendEncap("OPFLAGS", flags); } } } void OnPermissionCheck(PermissionData& perm) { if (perm.chan && perm.source && perm.result == MOD_RES_PASSTHRU) { Membership* memb = perm.chan->GetUser(perm.source); if (cmd.prov.PermissionCheck(memb, perm.name)) perm.result = MOD_RES_ALLOW; } } Version GetVersion() { return Version("Provides per-channel access flags", VF_OPTCOMMON | VF_VENDOR); } }; MODULE_INIT(ModuleOpFlags)