ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) { if ((mask.length() > 2) && (mask[0] == 'j') && (mask[1] == ':')) { std::string rm = mask.substr(2); char status = 0; ModeHandler* mh = ServerInstance->Modes->FindPrefix(rm[0]); if (mh) { rm = mask.substr(3); status = mh->GetModeChar(); } for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) { if (InspIRCd::Match((**i).name, rm)) { if (status) { Membership* memb = (**i).GetUser(user); if (memb && memb->hasMode(status)) return MOD_RES_DENY; } else return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; }
void OnPostJoin(Membership *memb) { if (!IS_LOCAL(memb->user)) return; modelist* list = mh.extItem.get(memb->chan); if (list) { std::string modeline("+"); std::vector<std::string> modechange; modechange.push_back(memb->chan->name); for (modelist::iterator it = list->begin(); it != list->end(); it++) { std::string::size_type colon = it->mask.find(':'); if (colon == std::string::npos) continue; if (memb->chan->CheckBan(memb->user, it->mask.substr(colon+1))) { ModeHandler* given = mh.FindMode(it->mask.substr(0, colon)); if (given && given->GetPrefixRank()) modeline.push_back(given->GetModeChar()); } } modechange.push_back(modeline); for(std::string::size_type i = modeline.length(); i > 1; --i) // we use "i > 1" instead of "i" so we skip the + modechange.push_back(memb->user->nick); if(modechange.size() >= 3) ServerInstance->SendGlobalMode(modechange, ServerInstance->FakeClient); } }
void DataKeeper::SaveMemberData(Channel* chan, std::vector<OwnedModesExts>& memberdatalist) { ModesExts currdata; const Channel::MemberMap& users = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { Membership* const memb = i->second; for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++) { ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh; if ((mh->IsPrefixMode()) && (memb->hasMode(mh->GetModeChar()))) currdata.modelist.push_back(InstanceData(j, memb->user->uuid)); // Need to pass the user's uuid to the mode parser to set the mode later } SaveExtensions(memb, currdata.extlist); // Same logic as in DoSaveUsers() if (!currdata.empty()) { memberdatalist.push_back(OwnedModesExts(memb->user->uuid)); memberdatalist.back().swap(currdata); } } }
std::string ModeParser::GiveModeList(ModeType mt) { std::string type1; /* Listmodes EXCEPT those with a prefix */ std::string type2; /* Modes that take a param when adding or removing */ std::string type3; /* Modes that only take a param when adding */ std::string type4; /* Modes that dont take a param */ for (unsigned char mode = 'A'; mode <= 'z'; mode++) { ModeHandler* mh = modehandlers[mt][mode-65]; /* One parameter when adding */ if (mh) { if (mh->GetNumParams(true)) { PrefixMode* pm = mh->IsPrefixMode(); if ((mh->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0))) { type1 += mh->GetModeChar(); } else { /* ... and one parameter when removing */ if (mh->GetNumParams(false)) { /* But not a list mode */ if (!pm) { type2 += mh->GetModeChar(); } } else { /* No parameters when removing */ type3 += mh->GetModeChar(); } } } else { type4 += mh->GetModeChar(); } } } return type1 + "," + type2 + "," + type3 + "," + type4; }
static std::string BuildModeList(ModeType type) { std::vector<std::string> modes; for(char c='A'; c <= 'z'; c++) { ModeHandler* mh = ServerInstance->Modes->FindMode(c, type); if (mh) { std::string mdesc = mh->name; mdesc.push_back('='); if (mh->GetPrefix()) mdesc.push_back(mh->GetPrefix()); if (mh->GetModeChar()) mdesc.push_back(mh->GetModeChar()); modes.push_back(mdesc); } } sort(modes.begin(), modes.end()); irc::stringjoiner line(" ", modes, 0, modes.size() - 1); return line.GetJoined(); }
unsigned int ModeParser::ProcessSingle(User* user, Channel* targetchannel, User* targetuser, Modes::ChangeList& changelist, ModeProcessFlag flags, unsigned int beginindex) { LastParse.clear(); LastChangeList.clear(); unsigned int modes_processed = 0; std::string output_mode; std::string output_parameters; char output_pm = '\0'; // current output state, '+' or '-' Modes::ChangeList::List& list = changelist.getlist(); for (Modes::ChangeList::List::iterator i = list.begin()+beginindex; i != list.end(); ++i) { modes_processed++; Modes::Change& item = *i; ModeHandler* mh = item.mh; // If the mode is supposed to have a parameter then we first take a look at item.param // and, if we were asked to, also handle mode merges now if (mh->GetNumParams(item.adding)) { // Skip the mode if the parameter does not pass basic validation if (!IsModeParamValid(user, targetchannel, targetuser, item)) continue; // If this is a merge and we won we don't apply this mode if ((flags & MODE_MERGE) && (!ShouldApplyMergedMode(targetchannel, item))) continue; } ModeAction ma = TryMode(user, targetuser, targetchannel, item, (!(flags & MODE_CHECKACCESS))); if (ma != MODEACTION_ALLOW) continue; char needed_pm = item.adding ? '+' : '-'; if (needed_pm != output_pm) { output_pm = needed_pm; output_mode.append(1, output_pm); } output_mode.push_back(mh->GetModeChar()); if (!item.param.empty()) { output_parameters.push_back(' '); output_parameters.append(item.param); } LastChangeList.push(mh, item.adding, item.param); if ((output_mode.length() + output_parameters.length() > 450) || (output_mode.length() > 100) || (LastChangeList.size() >= ServerInstance->Config->Limits.MaxModes)) { /* mode sequence is getting too long */ break; } } if (!output_mode.empty()) { LastParse = targetchannel ? targetchannel->name : targetuser->nick; LastParse.append(" "); LastParse.append(output_mode); LastParse.append(output_parameters); if (targetchannel) targetchannel->WriteChannel(user, "MODE " + LastParse); else targetuser->WriteFrom(user, "MODE " + LastParse); FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastChangeList, flags, output_mode)); } return modes_processed; }
ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Modes::Change& mcitem, bool SkipACL) { ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER; ModeHandler* mh = mcitem.mh; bool adding = mcitem.adding; int pcnt = mh->GetNumParams(adding); std::string& parameter = mcitem.param; // crop mode parameter size to 250 characters if (parameter.length() > 250 && adding) parameter.erase(250); ModResult MOD_RESULT; FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, parameter, adding)); if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY)) return MODEACTION_DENY; const char modechar = mh->GetModeChar(); 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 :You must have channel %s access or above to %sset channel mode %c", chan->name.c_str(), neededmh->name.c_str(), adding ? "" : "un", modechar); else user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You cannot %sset channel mode %c", chan->name.c_str(), adding ? "" : "un", modechar); return MODEACTION_DENY; } } } // Ask mode watchers whether this mode change is OK std::pair<ModeWatcherMap::iterator, ModeWatcherMap::iterator> itpair = modewatchermap.equal_range(mh->name); for (ModeWatcherMap::iterator 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, ":Permission Denied - %s mode %c has been locked by the administrator", 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, ":Permission Denied - Oper type %s does not have access to set %s mode %c", user->oper->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar); } else { user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - Only operators may set %s mode %c", 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; itpair = modewatchermap.equal_range(mh->name); for (ModeWatcherMap::iterator 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; }