void ModeParser::AddMode(ModeHandler* mh) { /* Yes, i know, this might let people declare modes like '_' or '^'. * If they do that, thats their problem, and if i ever EVER see an * official InspIRCd developer do that, i'll beat them with a paddle! */ if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z')) throw ModuleException("Invalid letter for mode " + mh->name); /* A mode prefix of ',' is not acceptable, it would f**k up server to server. * A mode prefix of ':' will f**k up both server to server, and client to server. * A mode prefix of '#' will mess up /whois and /privmsg */ PrefixMode* pm = mh->IsPrefixMode(); if (pm) { if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#')) throw ModuleException("Invalid prefix for mode " + mh->name); if (FindPrefix(pm->GetPrefix())) throw ModuleException("Prefix already exists for mode " + mh->name); } ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65]; if (slot) throw ModuleException("Letter is already in use for mode " + mh->name); // The mode needs an id if it is either a user mode, a simple mode (flag) or a parameter mode. // Otherwise (for listmodes and prefix modes) the id remains MODEID_MAX, which is invalid. ModeHandler::Id modeid = MODEID_MAX; if ((mh->GetModeType() == MODETYPE_USER) || (mh->IsParameterMode()) || (!mh->IsListMode())) modeid = AllocateModeId(mh->GetModeType()); if (!modehandlersbyname[mh->GetModeType()].insert(std::make_pair(mh->name, mh)).second) throw ModuleException("Mode name already in use: " + mh->name); // Everything is fine, add the mode // If we allocated an id for this mode then save it and put the mode handler into the slot if (modeid != MODEID_MAX) { mh->modeid = modeid; modehandlersbyid[mh->GetModeType()][modeid] = mh; } slot = mh; if (pm) mhlist.prefix.push_back(pm); else if (mh->IsListModeBase()) mhlist.list.push_back(mh->IsListModeBase()); RecreateModeListFor004Numeric(); }
CmdResult Handle(User* user, const Params& parameters) override { Channel* channel = ServerInstance->FindChan(parameters[0]); if (!channel) { user->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } unsigned int cm = channel->GetPrefixValue(user); if (cm < HALFOP_VALUE) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, channel->name, "You do not have permission to set bans on this channel"); return CMD_FAILURE; } TimedBan T; unsigned long duration; if (!InspIRCd::Duration(parameters[1], duration)) { user->WriteNotice("Invalid ban time"); return CMD_FAILURE; } unsigned long expire = duration + ServerInstance->Time(); std::string mask = parameters[2]; bool isextban = ((mask.size() > 2) && (mask[1] == ':')); if (!isextban && !InspIRCd::IsValidMask(mask)) mask.append("!*@*"); if (IsBanSet(channel, mask)) { user->WriteNotice("Ban already set"); return CMD_FAILURE; } Modes::ChangeList setban; setban.push_add(ServerInstance->Modes.FindMode('b', MODETYPE_CHANNEL), mask); // Pass the user (instead of ServerInstance->FakeClient) to ModeHandler::Process() to // make it so that the user sets the mode themselves ServerInstance->Modes.Process(user, channel, NULL, setban); if (ServerInstance->Modes.GetLastChangeList().empty()) { user->WriteNotice("Invalid ban mask"); return CMD_FAILURE; } T.mask = mask; T.expire = expire + (IS_REMOTE(user) ? 5 : 0); T.chan = channel; TimedBanList.push_back(T); const std::string addban = user->nick + " added a timed ban on " + mask + " lasting for " + InspIRCd::DurationString(duration) + "."; // If halfop is loaded, send notice to halfops and above, otherwise send to ops and above PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h'); char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@'; ClientProtocol::Messages::Privmsg notice(ServerInstance->FakeClient, channel, addban, MSG_NOTICE); channel->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar); ServerInstance->PI->SendChannelNotice(channel, pfxchar, addban); return CMD_SUCCESS; }
void OnBackgroundTimer(time_t curtime) override { timedbans expired; for (timedbans::iterator i = TimedBanList.begin(); i != TimedBanList.end();) { if (curtime > i->expire) { expired.push_back(*i); i = TimedBanList.erase(i); } else ++i; } for (timedbans::iterator i = expired.begin(); i != expired.end(); i++) { std::string mask = i->mask; Channel* cr = i->chan; { const std::string expiry = "*** Timed ban on " + cr->name + " expired."; // If halfop is loaded, send notice to halfops and above, otherwise send to ops and above PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h'); char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@'; ClientProtocol::Messages::Privmsg notice(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, cr, expiry, MSG_NOTICE); cr->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar); ServerInstance->PI->SendChannelNotice(cr, pfxchar, expiry); Modes::ChangeList setban; setban.push_remove(ServerInstance->Modes.FindMode('b', MODETYPE_CHANNEL), mask); ServerInstance->Modes.Process(ServerInstance->FakeClient, cr, NULL, setban); } } }
bool ModeParser::AddMode(ModeHandler* mh) { unsigned char mask = 0; unsigned char pos = 0; /* Yes, i know, this might let people declare modes like '_' or '^'. * If they do that, thats their problem, and if i ever EVER see an * official InspIRCd developer do that, i'll beat them with a paddle! */ if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z')) return false; /* A mode prefix of ',' is not acceptable, it would f**k up server to server. * A mode prefix of ':' will f**k up both server to server, and client to server. * A mode prefix of '#' will mess up /whois and /privmsg */ PrefixMode* pm = mh->IsPrefixMode(); if (pm) { if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#')) return false; if (FindPrefix(pm->GetPrefix())) return false; } mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL; pos = (mh->GetModeChar()-65) | mask; if (modehandlers[pos]) return false; // Everything is fine, add the mode modehandlers[pos] = mh; if (pm) mhlist.prefix.push_back(pm); else if (mh->IsListModeBase()) mhlist.list.push_back(mh->IsListModeBase()); RecreateModeListFor004Numeric(); return true; }
PrefixMode* ModeParser::FindPrefix(unsigned const char pfxletter) { const PrefixModeList& list = GetPrefixModes(); for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i) { PrefixMode* pm = *i; if (pm->GetPrefix() == pfxletter) return pm; } return NULL; }
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; }
std::string ModeParser::GiveModeList(ModeMasks m) { 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++) { unsigned char pos = (mode-65) | m; /* One parameter when adding */ if (modehandlers[pos]) { if (modehandlers[pos]->GetNumParams(true)) { PrefixMode* pm = modehandlers[pos]->IsPrefixMode(); if ((modehandlers[pos]->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0))) { type1 += modehandlers[pos]->GetModeChar(); } else { /* ... and one parameter when removing */ if (modehandlers[pos]->GetNumParams(false)) { /* But not a list mode */ if (!pm) { type2 += modehandlers[pos]->GetModeChar(); } } else { /* No parameters when removing */ type3 += modehandlers[pos]->GetModeChar(); } } } else { type4 += modehandlers[pos]->GetModeChar(); } } } return type1 + "," + type2 + "," + type3 + "," + type4; }
/** Handle /INVITE */ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, User *user) { ModResult MOD_RESULT; if (parameters.size() >= 2) { User* u; if (IS_LOCAL(user)) u = ServerInstance->FindNickOnly(parameters[0]); else u = ServerInstance->FindNick(parameters[0]); Channel* c = ServerInstance->FindChan(parameters[1]); time_t timeout = 0; if (parameters.size() >= 3) { if (IS_LOCAL(user)) timeout = ServerInstance->Time() + InspIRCd::Duration(parameters[2]); else if (parameters.size() > 3) timeout = ConvToInt(parameters[3]); } if ((!c) || (!u) || (u->registered != REG_ALL)) { user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c ? parameters[0].c_str() : parameters[1].c_str()); return CMD_FAILURE; } // Verify channel timestamp if the INVITE is coming from a remote server if (!IS_LOCAL(user)) { // Remote INVITE commands must carry a channel timestamp if (parameters.size() < 3) return CMD_INVALID; // Drop the invite if our channel TS is lower time_t RemoteTS = ConvToInt(parameters[2]); if (c->age < RemoteTS) return CMD_FAILURE; } if ((IS_LOCAL(user)) && (!c->HasUser(user))) { user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel!", c->name.c_str()); return CMD_FAILURE; } if (c->HasUser(u)) { user->WriteNumeric(ERR_USERONCHANNEL, "%s %s :is already on channel", u->nick.c_str(), c->name.c_str()); return CMD_FAILURE; } FIRST_MOD_RESULT(OnUserPreInvite, MOD_RESULT, (user,u,c,timeout)); if (MOD_RESULT == MOD_RES_DENY) { return CMD_FAILURE; } else if (MOD_RESULT == MOD_RES_PASSTHRU) { if (IS_LOCAL(user)) { unsigned int rank = c->GetPrefixValue(user); if (rank < HALFOP_VALUE) { // Check whether halfop mode is available and phrase error message accordingly ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL); user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must be a channel %soperator", c->name.c_str(), (mh && mh->name == "halfop" ? "half-" : "")); return CMD_FAILURE; } } } if (IS_LOCAL(u)) { Invitation::Create(c, IS_LOCAL(u), timeout); u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str()); } if (IS_LOCAL(user)) user->WriteNumeric(RPL_INVITING, "%s %s", u->nick.c_str(),c->name.c_str()); if (ServerInstance->Config->AnnounceInvites != ServerConfig::INVITE_ANNOUNCE_NONE) { char prefix; switch (ServerInstance->Config->AnnounceInvites) { case ServerConfig::INVITE_ANNOUNCE_OPS: { prefix = '@'; break; } case ServerConfig::INVITE_ANNOUNCE_DYNAMIC: { PrefixMode* mh = ServerInstance->Modes->FindPrefixMode('h'); prefix = (mh && mh->name == "halfop" ? mh->GetPrefix() : '@'); break; } default: { prefix = 0; break; } } c->WriteAllExceptSender(user, true, prefix, "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str()); } FOREACH_MOD(OnUserInvite, (user,u,c,timeout)); } else if (IS_LOCAL(user)) { // pinched from ircu - invite with not enough parameters shows channels // youve been invited to but haven't joined yet. InviteList& il = IS_LOCAL(user)->GetInviteList(); for (InviteList::const_iterator i = il.begin(); i != il.end(); ++i) { user->WriteNumeric(RPL_INVITELIST, ":%s", (*i)->chan->name.c_str()); } user->WriteNumeric(RPL_ENDOFINVITELIST, ":End of INVITE list"); } return CMD_SUCCESS; }