void init() override { ConfigTagList tags = ServerInstance->Config->ConfTags("customprefix"); for (ConfigIter iter = tags.first; iter != tags.second; ++iter) { ConfigTag* tag = iter->second; const std::string name = tag->getString("name"); if (name.empty()) throw ModuleException("<customprefix:name> must be specified at " + tag->getTagLocation()); if (tag->getBool("change")) { ModeHandler* mh = ServerInstance->Modes.FindMode(name, MODETYPE_CHANNEL); if (!mh) throw ModuleException("<customprefix:change> specified for a non-existent mode at " + tag->getTagLocation()); PrefixMode* pm = mh->IsPrefixMode(); if (!pm) throw ModuleException("<customprefix:change> specified for a non-prefix mode at " + tag->getTagLocation()); unsigned long rank = tag->getUInt("rank", pm->GetPrefixRank(), 0, UINT_MAX); unsigned long setrank = tag->getUInt("ranktoset", pm->GetLevelRequired(true), rank, UINT_MAX); unsigned long unsetrank = tag->getUInt("ranktounset", pm->GetLevelRequired(false), setrank, UINT_MAX); bool depriv = tag->getBool("depriv", pm->CanSelfRemove()); pm->Update(rank, setrank, unsetrank, depriv); ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Changed the %s prefix: depriv=%u rank=%u ranktoset=%u ranktounset=%u", pm->name.c_str(), pm->CanSelfRemove(), pm->GetPrefixRank(), pm->GetLevelRequired(true), pm->GetLevelRequired(false)); continue; } const std::string letter = tag->getString("letter"); if (letter.length() != 1) throw ModuleException("<customprefix:letter> must be set to a mode character at " + tag->getTagLocation()); const std::string prefix = tag->getString("prefix"); if (prefix.length() != 1) throw ModuleException("<customprefix:prefix> must be set to a mode prefix at " + tag->getTagLocation()); try { CustomPrefixMode* mh = new CustomPrefixMode(this, name, letter[0], prefix[0], tag); modes.push_back(mh); ServerInstance->Modules.AddService(*mh); } catch (ModuleException& e) { throw ModuleException(e.GetReason() + " (while creating mode from " + tag->getTagLocation() + ")"); } } }
ModResult Call(User* user, Channel* chan, const std::string& restriction) { unsigned int mypfx = chan->GetPrefixValue(user); std::string minmode; ListModeBase::ModeList* list = ec.GetList(chan); if (list) { for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); ++i) { std::string::size_type pos = (*i).mask.find(':'); if (pos == std::string::npos) continue; if ((*i).mask.substr(0,pos) == restriction) minmode = (*i).mask.substr(pos + 1); } } PrefixMode* mh = FindMode(minmode); if (mh && mypfx >= mh->GetPrefixRank()) return MOD_RES_ALLOW; if (mh || minmode == "*") return MOD_RES_DENY; return ServerInstance->HandleOnCheckExemption.Call(user, chan, restriction); }
/* returns a list of DIRECT servernames for a specific channel */ void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list) { unsigned int minrank = 0; if (status) { PrefixMode* mh = ServerInstance->Modes->FindPrefix(status); if (mh) minrank = mh->GetPrefixRank(); } const UserMembList *ulist = c->GetUsers(); for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { if (IS_LOCAL(i->first)) continue; if (minrank && i->second->getRank() < minrank) continue; if (exempt_list.find(i->first) == exempt_list.end()) { TreeServer* best = TreeServer::Get(i->first); list.insert(best->GetSocket()); } } return; }
std::string ModeParser::BuildPrefixes(bool lettersAndModes) { std::string mletters; std::string mprefixes; std::map<int,std::pair<char,char> > prefixes; const PrefixModeList& list = GetPrefixModes(); for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i) { PrefixMode* pm = *i; if (pm->GetPrefix()) prefixes[pm->GetPrefixRank()] = std::make_pair(pm->GetPrefix(), pm->GetModeChar()); } for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++) { mletters = mletters + n->second.first; mprefixes = mprefixes + n->second.second; } return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters; }
ModResult OnCheckExemptionHandler::Call(User* user, Channel* chan, const std::string& restriction) { unsigned int mypfx = chan->GetPrefixValue(user); char minmode = 0; std::string current; irc::spacesepstream defaultstream(ServerInstance->Config->ConfValue("options")->getString("exemptchanops")); while (defaultstream.GetToken(current)) { std::string::size_type pos = current.find(':'); if (pos == std::string::npos) continue; if (!current.compare(0, pos, restriction)) minmode = current[pos+1]; } PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(minmode); if (mh && mypfx >= mh->GetPrefixRank()) return MOD_RES_ALLOW; if (mh || minmode == '*') return MOD_RES_DENY; return MOD_RES_PASSTHRU; }
CmdResult Handle(User* user, const Params& parameters) override { ModeHandler* mh; Channel* chan = ServerInstance->FindChan(parameters[0]); char modeletter = parameters[1][0]; if (chan == NULL) { user->WriteNotice("The channel " + parameters[0] + " does not exist."); return CMD_FAILURE; } mh = ServerInstance->Modes.FindMode(modeletter, MODETYPE_CHANNEL); if (mh == NULL || parameters[1].size() > 1) { user->WriteNotice(parameters[1] + " is not a valid channel mode."); return CMD_FAILURE; } if (chan->GetPrefixValue(user) < mh->GetLevelRequired(false)) { user->WriteNotice("You do not have access to unset " + ConvToStr(modeletter) + " on " + chan->name + "."); return CMD_FAILURE; } std::string pattern = parameters.size() > 2 ? parameters[2] : "*"; PrefixMode* pm; ListModeBase* lm; ListModeBase::ModeList* ml; Modes::ChangeList changelist; if ((pm = mh->IsPrefixMode())) { // As user prefix modes don't have a GetList() method, let's iterate through the channel's users. const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator it = users.begin(); it != users.end(); ++it) { if (!InspIRCd::Match(it->first->nick, pattern)) continue; if (it->second->HasMode(pm) && !((it->first == user) && (pm->GetPrefixRank() > VOICE_VALUE))) changelist.push_remove(mh, it->first->nick); } } else if ((lm = mh->IsListModeBase()) && ((ml = lm->GetList(chan)) != NULL)) { for (ListModeBase::ModeList::iterator it = ml->begin(); it != ml->end(); ++it) { if (!InspIRCd::Match(it->mask, pattern)) continue; changelist.push_remove(mh, it->mask); } } else { if (chan->IsModeSet(mh)) changelist.push_remove(mh); } ServerInstance->Modes.Process(user, chan, NULL, changelist); return CMD_SUCCESS; }
ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar, std::string ¶meter, bool SkipACL) { ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER; ModeHandler *mh = FindMode(modechar, type); int pcnt = mh->GetNumParams(adding); // crop mode parameter size to 250 characters if (parameter.length() > 250 && adding) parameter = parameter.substr(0, 250); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt)); if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY)) return MODEACTION_DENY; if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW)) { MOD_RESULT = mh->AccessCheck(user, chan, parameter, adding); if (MOD_RESULT == MOD_RES_DENY) return MODEACTION_DENY; if (MOD_RESULT == MOD_RES_PASSTHRU) { unsigned int neededrank = mh->GetLevelRequired(); /* Compare our rank on the channel against the rank of the required prefix, * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown * in NAMES(X) are not in rank order, we know the most powerful mode is listed * first, so we don't need to iterate, we just look up the first instead. */ unsigned int ourrank = chan->GetPrefixValue(user); if (ourrank < neededrank) { PrefixMode* neededmh = NULL; for(char c='A'; c <= 'z'; c++) { PrefixMode* privmh = FindPrefixMode(c); if (privmh && privmh->GetPrefixRank() >= neededrank) { // this mode is sufficient to allow this action if (!neededmh || privmh->GetPrefixRank() < neededmh->GetPrefixRank()) neededmh = privmh; } } if (neededmh) user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel %s access or above to %sset channel mode %c", user->nick.c_str(), chan->name.c_str(), neededmh->name.c_str(), adding ? "" : "un", modechar); else user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You cannot %sset channel mode %c", user->nick.c_str(), chan->name.c_str(), adding ? "" : "un", modechar); return MODEACTION_DENY; } } } // Ask mode watchers whether this mode change is OK std::pair<ModeWatchIter, ModeWatchIter> itpair = modewatchermap.equal_range(mh->name); for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) { ModeWatcher* mw = i->second; if (mw->GetModeType() == type) { if (!mw->BeforeMode(user, targetuser, chan, parameter, adding)) return MODEACTION_DENY; // A module whacked the parameter completely, and there was one. Abort. if (pcnt && parameter.empty()) return MODEACTION_DENY; } } if (IS_LOCAL(user) && !user->IsOper()) { char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes; if (disabled[modechar - 'A']) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator", user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar); return MODEACTION_DENY; } } if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type)) { /* It's an oper only mode, and they don't have access to it. */ if (user->IsOper()) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c", user->nick.c_str(), user->oper->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar); } else { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c", user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar); } return MODEACTION_DENY; } /* Call the handler for the mode */ ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding); if (pcnt && parameter.empty()) return MODEACTION_DENY; if (ma != MODEACTION_ALLOW) return ma; if ((!mh->IsListMode()) && (mh->GetNumParams(true)) && (chan)) chan->SetModeParam(mh, (adding ? parameter : "")); itpair = modewatchermap.equal_range(mh->name); for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) { ModeWatcher* mw = i->second; if (mw->GetModeType() == type) mw->AfterMode(user, targetuser, chan, parameter, adding); } return MODEACTION_ALLOW; }
CmdResult Handle(const std::vector<std::string> ¶meters, User *user) { ModeHandler* mh; Channel* chan = ServerInstance->FindChan(parameters[0]); char modeletter = parameters[1][0]; if (chan == NULL) { user->WriteNotice("The channel " + parameters[0] + " does not exist."); return CMD_FAILURE; } mh = ServerInstance->Modes->FindMode(modeletter, MODETYPE_CHANNEL); if (mh == NULL || parameters[1].size() > 1) { user->WriteNotice(parameters[1] + " is not a valid channel mode."); return CMD_FAILURE; } if (chan->GetPrefixValue(user) < mh->GetLevelRequired()) { user->WriteNotice("You do not have access to unset " + ConvToStr(modeletter) + " on " + chan->name + "."); return CMD_FAILURE; } std::string pattern = parameters.size() > 2 ? parameters[2] : "*"; PrefixMode* pm; ListModeBase* lm; ListModeBase::ModeList* ml; irc::modestacker modestack(false); if ((pm = mh->IsPrefixMode())) { // As user prefix modes don't have a GetList() method, let's iterate through the channel's users. const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator it = users.begin(); it != users.end(); ++it) { if (!InspIRCd::Match(it->first->nick, pattern)) continue; if (it->second->hasMode(modeletter) && !((it->first == user) && (pm->GetPrefixRank() > VOICE_VALUE))) modestack.Push(modeletter, it->first->nick); } } else if ((lm = mh->IsListModeBase()) && ((ml = lm->GetList(chan)) != NULL)) { for (ListModeBase::ModeList::iterator it = ml->begin(); it != ml->end(); ++it) { if (!InspIRCd::Match(it->mask, pattern)) continue; modestack.Push(modeletter, it->mask); } } else { if (chan->IsModeSet(mh)) modestack.Push(modeletter); } parameterlist stackresult; stackresult.push_back(chan->name); while (modestack.GetStackedLine(stackresult)) { ServerInstance->Modes->Process(stackresult, user); stackresult.erase(stackresult.begin() + 1, stackresult.end()); } return CMD_SUCCESS; }