void TreeSocket::SendListModes(Channel* chan) { FModeBuilder fmode(chan); const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes(); for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i) { ListModeBase* mh = *i; ListModeBase::ModeList* list = mh->GetList(chan); if (!list) continue; // Add all items on the list to the FMODE, send it whenever it becomes too long const char modeletter = mh->GetModeChar(); for (ListModeBase::ModeList::const_iterator j = list->begin(); j != list->end(); ++j) { const std::string& mask = j->mask; if (!fmode.has_room(mask)) { // No room for this mask, send the current line as-is then add the mask to a // new, empty FMODE message this->WriteLine(fmode.finalize()); fmode.clear(); } fmode.push_mode(modeletter, mask); } } if (!fmode.empty()) this->WriteLine(fmode.finalize()); }
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); }
ModResult ProcessMessages(User* user,Channel* chan,std::string &text) { ModResult res = ServerInstance->OnCheckExemption(user,chan,"filter"); if (!IS_LOCAL(user) || res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; ListModeBase::ModeList* list = cf.GetList(chan); if (list) { for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); i++) { if (InspIRCd::Match(text, i->mask)) { if (hidemask) user->WriteNumeric(404, "%s %s :Cannot send to channel (your message contained a censored word)",user->nick.c_str(), chan->name.c_str()); else user->WriteNumeric(404, "%s %s %s :Cannot send to channel (your message contained a censored word)",user->nick.c_str(), chan->name.c_str(), i->mask.c_str()); return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; }
ModResult OnCheckInvite(User* user, Channel* chan) { ListModeBase::ModeList* list = ie.GetList(chan); if (list) { for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (chan->CheckBan(user, it->mask)) { return MOD_RES_ALLOW; } } } return MOD_RES_PASSTHRU; }
static bool WriteDatabase(PermChannel& permchanmode, Module* mod, bool save_listmodes) { ChanModeReference ban(mod, "ban"); /* * We need to perform an atomic write so as not to f**k things up. * So, let's write to a temporary file, flush it, then rename the file.. * -- w00t */ // If the user has not specified a configuration file then we don't write one. if (permchannelsconf.empty()) return true; std::string permchannelsnewconf = permchannelsconf + ".tmp"; std::ofstream stream(permchannelsnewconf.c_str()); if (!stream.is_open()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot create database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno); return false; } stream << "# This file is automatically generated by m_permchannels. Any changes will be overwritten." << std::endl << "<config format=\"xml\">" << std::endl; for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { Channel* chan = i->second; if (!chan->IsModeSet(permchanmode)) continue; std::string chanmodes = chan->ChanModes(true); if (save_listmodes) { std::string modes; std::string params; const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes(); for (ModeParser::ListModeList::const_iterator j = listmodes.begin(); j != listmodes.end(); ++j) { ListModeBase* lm = *j; ListModeBase::ModeList* list = lm->GetList(chan); if (!list || list->empty()) continue; size_t n = 0; // Append the parameters for (ListModeBase::ModeList::const_iterator k = list->begin(); k != list->end(); ++k, n++) { params += k->mask; params += ' '; } // Append the mode letters (for example "IIII", "gg") modes.append(n, lm->GetModeChar()); } if (!params.empty()) { // Remove the last space params.erase(params.end()-1); // If there is at least a space in chanmodes (that is, a non-listmode has a parameter) // insert the listmode mode letters before the space. Otherwise just append them. std::string::size_type p = chanmodes.find(' '); if (p == std::string::npos) chanmodes += modes; else chanmodes.insert(p, modes); // Append the listmode parameters (the masks themselves) chanmodes += ' '; chanmodes += params; } } stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name) << "\" ts=\"" << chan->age << "\" topic=\"" << ServerConfig::Escape(chan->topic) << "\" topicts=\"" << chan->topicset << "\" topicsetby=\"" << ServerConfig::Escape(chan->setby) << "\" modes=\"" << ServerConfig::Escape(chanmodes) << "\">" << std::endl; } if (stream.fail()) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot write to new database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno); return false; } stream.close(); #ifdef _WIN32 if (remove(permchannelsconf.c_str())) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot remove old database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno); return false; } #endif // Use rename to move temporary to new db - this is guarenteed not to f**k up, even in case of a crash. if (rename(permchannelsnewconf.c_str(), permchannelsconf.c_str()) < 0) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot move new to old database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno); return false; } return true; }
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; }
bool BeforeMode(User* source, User* dest, Channel* channel, std::string ¶m, bool adding) { /* nick!ident@host -> nick!ident@host * nick!ident@host#chan -> nick!ident@host#chan * nick@host#chan -> nick!*@host#chan * nick!ident#chan -> nick!ident@*#chan * nick#chan -> nick!*@*#chan */ if ((channel) && !param.empty()) { BanRedirectList* redirects; std::string mask[4]; enum { NICK, IDENT, HOST, CHAN } current = NICK; std::string::iterator start_pos = param.begin(); if (param.length() >= 2 && param[1] == ':') return true; if (param.find('#') == std::string::npos) return true; ListModeBase* banlm = static_cast<ListModeBase*>(*ban); unsigned int maxbans = banlm->GetLimit(channel); ListModeBase::ModeList* list = banlm->GetList(channel); if ((list) && (adding) && (maxbans <= list->size())) { source->WriteNumeric(ERR_BANLISTFULL, "%s :Channel ban list for %s is full (maximum entries for this channel is %u)", channel->name.c_str(), channel->name.c_str(), maxbans); return false; } for(std::string::iterator curr = start_pos; curr != param.end(); curr++) { switch(*curr) { case '!': if (current != NICK) break; mask[current].assign(start_pos, curr); current = IDENT; start_pos = curr+1; break; case '@': if (current != IDENT) break; mask[current].assign(start_pos, curr); current = HOST; start_pos = curr+1; break; case '#': if (current == CHAN) break; mask[current].assign(start_pos, curr); current = CHAN; start_pos = curr; break; } } if(mask[current].empty()) { mask[current].assign(start_pos, param.end()); } /* nick@host wants to be changed to *!nick@host rather than nick!*@host... */ if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty()) { /* std::string::swap() is fast - it runs in constant time */ mask[NICK].swap(mask[IDENT]); } if (!mask[NICK].empty() && mask[IDENT].empty() && mask[HOST].empty()) { if (mask[NICK].find('.') != std::string::npos || mask[NICK].find(':') != std::string::npos) { mask[NICK].swap(mask[HOST]); } } for(int i = 0; i < 3; i++) { if(mask[i].empty()) { mask[i].assign("*"); } } param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]); if(mask[CHAN].length()) { if (adding && IS_LOCAL(source)) { if (!ServerInstance->IsChannel(mask[CHAN])) { source->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :Invalid channel name in redirection (%s)", channel->name.c_str(), mask[CHAN].c_str()); return false; } Channel *c = ServerInstance->FindChan(mask[CHAN]); if (!c) { source->WriteNumeric(690, ":Target channel %s must exist to be set as a redirect.", mask[CHAN].c_str()); return false; } else if (adding && c->GetPrefixValue(source) < OP_VALUE) { source->WriteNumeric(690, ":You must be opped on %s to set it as a redirect.", mask[CHAN].c_str()); return false; } if (assign(channel->name) == mask[CHAN]) { source->WriteNumeric(690, "%s :You cannot set a ban redirection to the channel the ban is on", channel->name.c_str()); return false; } } if(adding) { /* It's a properly valid redirecting ban, and we're adding it */ redirects = extItem.get(channel); if (!redirects) { redirects = new BanRedirectList; extItem.set(channel, redirects); } /* Here 'param' doesn't have the channel on it yet */ redirects->push_back(BanRedirectEntry(mask[CHAN], param)); /* Now it does */ param.append(mask[CHAN]); } else { /* Removing a ban, if there's no extensible there are no redirecting bans and we're fine. */ redirects = extItem.get(channel); if (redirects) { /* But there were, so we need to remove the matching one if there is one */ for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++) { /* Ugly as f**k */ if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str()))) { redirects->erase(redir); if(redirects->empty()) { extItem.unset(channel); } break; } } } /* Append the channel so the default +b handler can remove the entry too */ param.append(mask[CHAN]); } } } return true; }
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; } unsigned int prefixrank; char prefixchar; std::string pattern = parameters.size() > 2 ? parameters[2] : "*"; ListModeBase* lm; ListModeBase::ModeList* ml; irc::modestacker modestack(false); if (!mh->IsListMode()) { if (chan->IsModeSet(mh)) modestack.Push(modeletter); } else if (((prefixrank = mh->GetPrefixRank()) && (prefixchar = mh->GetPrefix()))) { // As user prefix modes don't have a GetList() method, let's iterate through the channel's users. for (UserMembIter it = chan->userlist.begin(); it != chan->userlist.end(); ++it) { if (!InspIRCd::Match(it->first->nick, pattern)) continue; if (((strchr(chan->GetAllPrefixChars(user), prefixchar)) != NULL) && !(it->first == user && prefixrank > VOICE_VALUE)) modestack.Push(modeletter, it->first->nick); } } else if (((lm = dynamic_cast<ListModeBase*>(mh)) != NULL) && ((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 { user->WriteNotice("Could not remove channel mode " + ConvToStr(modeletter)); return CMD_FAILURE; } 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; }