CmdResult CommandTopic::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user) { Channel* c = ServerInstance->FindChan(parameters[0]); if (!c) { user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameters[0].c_str()); return CMD_FAILURE; } if (parameters.size() == 1) { if (c) { if ((c->IsModeSet(secretmode)) && (!c->HasUser(user))) { user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", c->name.c_str()); return CMD_FAILURE; } if (c->topic.length()) { user->WriteNumeric(RPL_TOPIC, "%s :%s", c->name.c_str(), c->topic.c_str()); user->WriteNumeric(RPL_TOPICTIME, "%s %s %lu", c->name.c_str(), c->setby.c_str(), (unsigned long)c->topicset); } else { user->WriteNumeric(RPL_NOTOPICSET, "%s :No topic is set.", c->name.c_str()); } } return CMD_SUCCESS; } std::string t = parameters[1]; // needed, in case a module wants to change it ModResult res; FIRST_MOD_RESULT(OnPreTopicChange, res, (user,c,t)); if (res == MOD_RES_DENY) return CMD_FAILURE; if (res != MOD_RES_ALLOW) { if (!c->HasUser(user)) { user->WriteNumeric(ERR_NOTONCHANNEL, "%s :You're not on that channel!", c->name.c_str()); return CMD_FAILURE; } if (c->IsModeSet(topiclockmode) && !ServerInstance->OnCheckExemption(user, c, "topiclock").check(c->GetPrefixValue(user) >= HALFOP_VALUE)) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You do not have access to change the topic on this channel", c->name.c_str()); return CMD_FAILURE; } } c->SetTopic(user, t); return CMD_SUCCESS; }
/** Handle /NAMES */ CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User *user) { Channel* c; if (!parameters.size()) { user->WriteNumeric(366, "%s * :End of /NAMES list.",user->nick.c_str()); return CMD_SUCCESS; } if (CommandParser::LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; c = ServerInstance->FindChan(parameters[0]); if (c) { if ((c->IsModeSet('s')) && (!c->HasUser(user))) { user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; } c->UserList(user); } else { user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); } return CMD_SUCCESS; }
std::string User::ChannelList(User* source, bool spy) { std::string list; for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++) { Channel* c = *i; /* If the target is the sender, neither +p nor +s is set, or * the channel contains the user, it is not a spy channel */ if (spy != (source == this || !(c->IsModeSet('p') || c->IsModeSet('s')) || c->HasUser(source))) list.append(c->GetPrefixChar(this)).append(c->name).append(" "); } return list; }
ModResult DoMsg(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list, bool privmsg) { if (!IS_LOCAL(user) || target_type != TYPE_CHANNEL || status) return MOD_RES_PASSTHRU; Channel* chan = static_cast<Channel*>(dest); ModResult res = ServerInstance->OnCheckExemption(user,chan,"opmoderated"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (!chan->GetExtBanStatus(user, 'u').check(!chan->IsModeSet(&mh)) && chan->GetPrefixValue(user) < VOICE_VALUE) { FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,exempt_list)); chan->WriteAllExcept(user, false, '@', exempt_list, "%s @%s :%s", privmsg ? "PRIVMSG" : "NOTICE", chan->name.c_str(), text.c_str()); if (privmsg) { FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,chan,TYPE_CHANNEL,text,'@',exempt_list)); } else FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,text,'@',exempt_list)); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; }
ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) override { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; std::string ctcpname; if (!details.IsCTCP(ctcpname) || irc::equals(ctcpname, "ACTION")) return MOD_RES_PASSTHRU; if (target.type == MessageTarget::TYPE_CHANNEL) { Channel* c = target.Get<Channel>(); ModResult res = CheckExemption::Call(exemptionprov, user, c, "noctcp"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet(nc))) { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send CTCP to channel (+C set)"); return MOD_RES_DENY; } } else if (target.type == MessageTarget::TYPE_USER) { User* u = target.Get<User>(); if (u->IsModeSet(ncu)) { user->WriteNumeric(ERR_CANTSENDTOUSER, u->nick, "Can't send CTCP to user (+T set)"); return MOD_RES_PASSTHRU; } } return MOD_RES_PASSTHRU; }
ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; std::string *account = accountname.get(user); bool is_registered = account && !account->empty(); if (target_type == TYPE_CHANNEL) { Channel* c = (Channel*)dest; ModResult res = ServerInstance->OnCheckExemption(user,c,"regmoderated"); if (c->IsModeSet('M') && !is_registered && res != MOD_RES_ALLOW) { // user messaging a +M channel and is not registered user->WriteNumeric(477, user->nick+" "+c->name+" :You need to be identified to a registered account to message this channel"); return MOD_RES_DENY; } } else if (target_type == TYPE_USER) { User* u = (User*)dest; if (u->IsModeSet('R') && !is_registered) { // user messaging a +R user and is not registered user->WriteNumeric(477, ""+ user->nick +" "+ u->nick +" :You need to be identified to a registered account to message this user"); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; }
virtual ModResult OnUserPreNick(User* user, const std::string &newnick) { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; // Allow forced nick changes. if (ServerInstance->NICKForced.get(user)) return MOD_RES_PASSTHRU; for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) { Channel* curr = *i; ModResult res = ServerInstance->OnCheckExemption(user,curr,"nonick"); if (res == MOD_RES_ALLOW) continue; if (override && IS_OPER(user)) continue; if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet('N'))) { user->WriteNumeric(ERR_CANTCHANGENICK, "%s :Can't change nickname while on %s (+N is set)", user->nick.c_str(), curr->name.c_str()); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; }
std::string CommandWhois::ChannelList(User* source, User* dest, bool spy) { std::string list; for (UCListIter i = dest->chans.begin(); i != dest->chans.end(); i++) { Channel* c = *i; /* If the target is the sender, neither +p nor +s is set, or * the channel contains the user, it is not a spy channel */ if (spy != (source == dest || !(c->IsModeSet(privatemode) || c->IsModeSet(secretmode)) || c->HasUser(source))) list.append(c->GetPrefixChar(dest)).append(c->name).append(" "); } return list; }
Channel* get_first_visible_channel(User *u) { UCListIter i = u->chans.begin(); while (i != u->chans.end()) { Channel* c = *i++; if (!c->IsModeSet(secretmode)) return c; } return NULL; }
std::string CommandWhois::ChannelList(User* source, User* dest, bool spy) { std::string list; for (User::ChanList::iterator i = dest->chans.begin(); i != dest->chans.end(); i++) { Membership* memb = *i; Channel* c = memb->chan; /* If the target is the sender, neither +p nor +s is set, or * the channel contains the user, it is not a spy channel */ if (spy != (source == dest || !(c->IsModeSet(privatemode) || c->IsModeSet(secretmode)) || c->HasUser(source))) { char prefix = memb->GetPrefixChar(); if (prefix) list.push_back(prefix); list.append(c->name).push_back(' '); } } return list; }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { Channel* c = ServerInstance->FindChan(parameters[0]); if (!c) { user->WriteNumeric(Numerics::NoSuchNick(parameters[0])); return CMD_FAILURE; } if (c->HasUser(user)) { user->WriteNumeric(ERR_KNOCKONCHAN, c->name, InspIRCd::Format("Can't KNOCK on %s, you are already on that channel.", c->name.c_str())); return CMD_FAILURE; } if (c->IsModeSet(noknockmode)) { user->WriteNumeric(480, InspIRCd::Format("Can't KNOCK on %s, +K is set.", c->name.c_str())); return CMD_FAILURE; } if (!c->IsModeSet(inviteonlymode)) { user->WriteNumeric(ERR_CHANOPEN, c->name, InspIRCd::Format("Can't KNOCK on %s, channel is not invite only so knocking is pointless!", c->name.c_str())); return CMD_FAILURE; } if (sendnotice) c->WriteNotice(InspIRCd::Format("User %s is KNOCKing on %s (%s)", user->nick.c_str(), c->name.c_str(), parameters[1].c_str())); if (sendnumeric) c->WriteChannelWithServ(ServerInstance->Config->ServerName, "710 %s %s %s :is KNOCKing: %s", c->name.c_str(), c->name.c_str(), user->GetFullHost().c_str(), parameters[1].c_str()); user->WriteNotice("KNOCKing on " + c->name); return CMD_SUCCESS; }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { Channel* c = ServerInstance->FindChan(parameters[0]); if (!c) { user->WriteNumeric(401, "%s %s :No such channel",user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } if (c->HasUser(user)) { user->WriteNumeric(480, "%s :Can't KNOCK on %s, you are already on that channel.", user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; } if (c->IsModeSet('K')) { user->WriteNumeric(480, "%s :Can't KNOCK on %s, +K is set.",user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; } if (!c->IsModeSet('i')) { user->WriteNumeric(480, "%s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!",user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; } if (sendnotice) c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :User %s is KNOCKing on %s (%s)", c->name.c_str(), user->nick.c_str(), c->name.c_str(), parameters[1].c_str()); if (sendnumeric) c->WriteChannelWithServ(ServerInstance->Config->ServerName, "710 %s %s %s :is KNOCKing: %s", c->name.c_str(), c->name.c_str(), user->GetFullHost().c_str(), parameters[1].c_str()); user->WriteNotice("KNOCKing on " + c->name); return CMD_SUCCESS; }
virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { ModResult res; if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) { Channel* c = (Channel*)dest; if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet('T'))) { res = ServerInstance->OnCheckExemption(user,c,"nonotice"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; else { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s %s :Can't send NOTICE to channel (+T set)",user->nick.c_str(), c->name.c_str()); return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; }
virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { if (target_type == TYPE_CHANNEL) { if ((!IS_LOCAL(user)) || (text.length() < minlen)) return MOD_RES_PASSTHRU; Channel* c = (Channel*)dest; ModResult res = ServerInstance->OnCheckExemption(user,c,"blockcaps"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet('B'))) { int caps = 0; const char* actstr = "\1ACTION "; int act = 0; for (std::string::iterator i = text.begin(); i != text.end(); i++) { /* Smart fix for suggestion from Jobe, ignore CTCP ACTION (part of /ME) */ if (*actstr && *i == *actstr++ && act != -1) { act++; continue; } else act = -1; caps += capsmap[(unsigned char)*i]; } if ( ((caps*100)/(int)text.length()) >= percent ) { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s %s :Your message cannot contain more than %d%% capital letters if it's longer than %d characters", user->nick.c_str(), c->name.c_str(), percent, minlen); return MOD_RES_DENY; } } } return MOD_RES_PASSTHRU; }
void ValidateChans() { Modes::ChangeList removepermchan; badchan = true; const chan_hash& chans = ServerInstance->GetChans(); for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ) { Channel* c = i->second; // Move iterator before we begin kicking ++i; if (ServerInstance->IsChannel(c->name)) continue; // The name of this channel is still valid if (c->IsModeSet(permchannelmode) && c->GetUserCounter()) { removepermchan.clear(); removepermchan.push_remove(*permchannelmode); ServerInstance->Modes.Process(ServerInstance->FakeClient, c, NULL, removepermchan); } Channel::MemberMap& users = c->userlist; for (Channel::MemberMap::iterator j = users.begin(); j != users.end(); ) { if (IS_LOCAL(j->first)) { // KickUser invalidates the iterator Channel::MemberMap::iterator it = j++; c->KickUser(ServerInstance->FakeClient, it, "Channel name no longer valid"); } else ++j; } } badchan = false; }
void ValidateChans() { badchan = true; std::vector<Channel*> chanvec; for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); ++i) { if (!ServerInstance->IsChannel(i->second->name)) chanvec.push_back(i->second); } std::vector<Channel*>::reverse_iterator c2 = chanvec.rbegin(); while (c2 != chanvec.rend()) { Channel* c = *c2++; if (c->IsModeSet(permchannelmode) && c->GetUserCounter()) { std::vector<std::string> modes; modes.push_back(c->name); modes.push_back(std::string("-") + permchannelmode->GetModeChar()); ServerInstance->Modes->Process(modes, ServerInstance->FakeClient); } const UserMembList* users = c->GetUsers(); for(UserMembCIter j = users->begin(); j != users->end(); ) { if (IS_LOCAL(j->first)) { // KickUser invalidates the iterator UserMembCIter it = j++; c->KickUser(ServerInstance->FakeClient, it->first, "Channel name no longer valid"); } else ++j; } } badchan = false; }
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; }
CmdResult HandleChannelTarget(User* source, const Params& parameters, const char* target, PrefixMode* pm) { Channel* chan = ServerInstance->FindChan(target); if (!chan) { // The target channel does not exist. source->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); return CMD_FAILURE; } if (IS_LOCAL(source)) { if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(source)) { // The noextmsg mode is set and the source is not in the channel. source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (no external messages)"); return CMD_FAILURE; } bool no_chan_priv = chan->GetPrefixValue(source) < VOICE_VALUE; if (no_chan_priv && chan->IsModeSet(moderatedmode)) { // The moderated mode is set and the source has no status rank. source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (+m)"); return CMD_FAILURE; } if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(source)) { // The source is banned in the channel and restrictbannedusers is enabled. if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY) source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're banned)"); return CMD_FAILURE; } } // Fire the pre-message events. MessageTarget msgtarget(chan, pm ? pm->GetPrefix() : 0); CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); if (!FirePreEvents(source, msgtarget, msgdetails)) return CMD_FAILURE; unsigned int minrank = pm ? pm->GetPrefixRank() : 0; CTCTags::TagMessage message(source, chan, parameters.GetTags()); const Channel::MemberMap& userlist = chan->GetUsers(); for (Channel::MemberMap::const_iterator iter = userlist.begin(); iter != userlist.end(); ++iter) { LocalUser* luser = IS_LOCAL(iter->first); // Don't send to remote users or the user who is the source. if (!luser || luser == source) continue; // Don't send to unprivileged or exempt users. if (iter->second->getRank() < minrank || msgdetails.exemptions.count(luser)) continue; // Send to users if they have the capability. if (cap.get(luser)) luser->Send(msgevprov, message); } return FirePostEvent(source, msgtarget, msgdetails); }
CmdResult HandleRMB(User* user, const CommandBase::Params& parameters, bool fpart) { User* target; Channel* channel; std::string reason; // If the command is a /REMOVE then detect the parameter order bool neworder = ((fpart) || (parameters[0][0] == '#')); /* Set these to the parameters needed, the new version of this module switches it's parameters around * supplying a new command with the new order while keeping the old /remove with the older order. * /remove <nick> <channel> [reason ...] * /fpart <channel> <nick> [reason ...] */ const std::string& channame = parameters[neworder ? 0 : 1]; const std::string& username = parameters[neworder ? 1 : 0]; /* Look up the user we're meant to be removing from the channel */ if (IS_LOCAL(user)) target = ServerInstance->FindNickOnly(username); else target = ServerInstance->FindNick(username); /* And the channel we're meant to be removing them from */ channel = ServerInstance->FindChan(channame); /* Fix by brain - someone needs to learn to validate their input! */ if (!channel) { user->WriteNumeric(Numerics::NoSuchChannel(channame)); return CMD_FAILURE; } if ((!target) || (target->registered != REG_ALL)) { user->WriteNumeric(Numerics::NoSuchNick(username)); return CMD_FAILURE; } if (!channel->HasUser(target)) { user->WriteNotice(InspIRCd::Format("*** The user %s is not on channel %s", target->nick.c_str(), channel->name.c_str())); return CMD_FAILURE; } if (target->server->IsULine()) { user->WriteNumeric(ERR_CHANOPRIVSNEEDED, channame, "Only a u-line may remove a u-line from a channel."); return CMD_FAILURE; } /* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */ if ((!IS_LOCAL(user)) || (!supportnokicks) || (!channel->IsModeSet(nokicksmode))) { /* We'll let everyone remove their level and below, eg: * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1) a ulined target will get a higher level than it's possible for a /remover to get..so they're safe. * Nobody may remove people with >= protectedrank rank. */ unsigned int ulevel = channel->GetPrefixValue(user); unsigned int tlevel = channel->GetPrefixValue(target); if ((!IS_LOCAL(user)) || ((ulevel > VOICE_VALUE) && (ulevel >= tlevel) && ((protectedrank == 0) || (tlevel < protectedrank)))) { // REMOVE will be sent to the target's server and it will reply with a PART (or do nothing if it doesn't understand the command) if (!IS_LOCAL(target)) { // Send an ENCAP REMOVE with parameters being in the old <user> <chan> order which is // compatible with both 2.0 and 3.0. This also turns FPART into REMOVE. CommandBase::Params p; p.push_back(target->uuid); p.push_back(channel->name); if (parameters.size() > 2) p.push_back(":" + parameters[2]); ServerInstance->PI->SendEncapsulatedData(target->server->GetName(), "REMOVE", p, user); return CMD_SUCCESS; } std::string reasonparam; /* If a reason is given, use it */ if(parameters.size() > 2) reasonparam = parameters[2]; else reasonparam = "No reason given"; /* Build up the part reason string. */ reason = "Removed by " + user->nick + ": " + reasonparam; channel->WriteNotice(InspIRCd::Format("%s removed %s from the channel", user->nick.c_str(), target->nick.c_str())); target->WriteNotice("*** " + user->nick + " removed you from " + channel->name + " with the message: " + reasonparam); channel->PartUser(target, reason); } else { user->WriteNotice(InspIRCd::Format("*** You do not have access to /remove %s from %s", target->nick.c_str(), channel->name.c_str())); return CMD_FAILURE; } } else { /* m_nokicks.so was loaded and +Q was set, block! */ user->WriteNumeric(ERR_RESTRICTED, channel->name, InspIRCd::Format("Can't remove user %s from channel (nokicks mode is set)", target->nick.c_str())); return CMD_FAILURE; } return CMD_SUCCESS; }
void ModeParser::Process(const std::vector<std::string>& parameters, User* user, ModeProcessFlag flags) { std::string target = parameters[0]; Channel* targetchannel = ServerInstance->FindChan(target); User* targetuser = ServerInstance->FindNick(target); ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER; LastParse.clear(); LastParseParams.clear(); LastParseTranslate.clear(); if ((!targetchannel) && ((!targetuser) || (IS_SERVER(targetuser)))) { user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str()); return; } if (parameters.size() == 1) { this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str()); return; } ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters)); bool SkipAccessChecks = false; if (!IS_LOCAL(user) || ServerInstance->ULine(user->server) || MOD_RESULT == MOD_RES_ALLOW) SkipAccessChecks = true; else if (MOD_RESULT == MOD_RES_DENY) return; if (targetuser && !SkipAccessChecks && user != targetuser) { user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str()); return; } std::string mode_sequence = parameters[1]; std::string output_mode; std::ostringstream output_parameters; LastParseParams.push_back(output_mode); LastParseTranslate.push_back(TR_TEXT); bool adding = true; char output_pm = '\0'; // current output state, '+' or '-' unsigned int param_at = 2; for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++) { unsigned char modechar = *letter; if (modechar == '+' || modechar == '-') { adding = (modechar == '+'); continue; } ModeHandler *mh = this->FindMode(modechar, type); if (!mh) { /* No mode handler? Unknown mode character then. */ user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar); continue; } std::string parameter; int pcnt = mh->GetNumParams(adding); if (pcnt && param_at == parameters.size()) { /* No parameter, continue to the next mode */ mh->OnParameterMissing(user, targetuser, targetchannel); continue; } else if (pcnt) { parameter = parameters[param_at++]; /* Make sure the user isn't trying to slip in an invalid parameter */ if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos)) continue; if ((flags & MODE_MERGE) && targetchannel && targetchannel->IsModeSet(mh) && !mh->IsListMode()) { std::string ours = targetchannel->GetModeParameter(mh); if (!mh->ResolveModeConflict(parameter, ours, targetchannel)) /* we won the mode merge, don't apply this mode */ continue; } } ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks); if (ma != MODEACTION_ALLOW) continue; char needed_pm = adding ? '+' : '-'; if (needed_pm != output_pm) { output_pm = needed_pm; output_mode.append(1, output_pm); } output_mode.append(1, modechar); if (pcnt) { output_parameters << " " << parameter; LastParseParams.push_back(parameter); LastParseTranslate.push_back(mh->GetTranslateType()); } if ( (output_mode.length() + output_parameters.str().length() > 450) || (output_mode.length() > 100) || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes)) { /* mode sequence is getting too long */ break; } } LastParseParams[0] = output_mode; if (!output_mode.empty()) { LastParse = targetchannel ? targetchannel->name : targetuser->nick; LastParse.append(" "); LastParse.append(output_mode); LastParse.append(output_parameters.str()); if (!(flags & MODE_LOCALONLY)) ServerInstance->PI->SendMode(user, targetuser, targetchannel, LastParseParams, LastParseTranslate); if (targetchannel) targetchannel->WriteChannel(user, "MODE " + LastParse); else targetuser->WriteFrom(user, "MODE " + LastParse); FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastParseParams, LastParseTranslate)); } else if (targetchannel && parameters.size() == 2) { /* Special case for displaying the list for listmodes, * e.g. MODE #chan b, or MODE #chan +b without a parameter */ this->DisplayListModes(user, targetchannel, mode_sequence); } }
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) { ListModeData lm; // Bans are managed by the core, so we have to process them separately static_cast<ListModeBase*>(*ban)->DoSyncChannel(chan, mod, &lm); // All other listmodes are managed by modules, so we need to ask them (call their // OnSyncChannel() handler) to give our ProtoSendMode() a list of modes that are // set on the channel. The ListModeData struct is passed as an opaque pointer // that will be passed back to us by the module handling the mode. FOREACH_MOD(OnSyncChannel, (chan, mod, &lm)); if (!lm.modes.empty()) { // Remove the last space lm.params.erase(lm.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 += lm.modes; else chanmodes.insert(p, lm.modes); // Append the listmode parameters (the masks themselves) chanmodes += ' '; chanmodes += lm.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; }
static bool WriteDatabase() { /* * 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("m_permchannels", LOG_DEFAULT, "permchannels: 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('P')) continue; stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name) << "\" topic=\"" << ServerConfig::Escape(chan->topic) << "\" modes=\"" << ServerConfig::Escape(chan->ChanModes(true)) << "\">" << std::endl; } if (stream.fail()) { ServerInstance->Logs->Log("m_permchannels", LOG_DEFAULT, "permchannels: 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("m_permchannels", LOG_DEFAULT, "permchannels: 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("m_permchannels", LOG_DEFAULT, "permchannels: 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 CommandNotice::Handle (const std::vector<std::string>& parameters, User *user) { User *dest; Channel *chan; CUList exempt_list; user->idle_lastmsg = ServerInstance->Time(); if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; if (parameters[0][0] == '$') { if (!user->HasPrivPermission("users/mass-message")) return CMD_SUCCESS; int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, exempt_list)); if (MOD_RESULT) return CMD_FAILURE; const char* text = temp.c_str(); const char* servermask = (parameters[0].c_str()) + 1; FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list)); if (InspIRCd::Match(ServerInstance->Config->ServerName,servermask, NULL)) { user->SendAll("NOTICE", "%s", text); } FOREACH_MOD(I_OnUserNotice,OnUserNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list)); return CMD_SUCCESS; } char status = 0; const char* target = parameters[0].c_str(); if (ServerInstance->Modes->FindPrefix(*target)) { status = *target; target++; } if (*target == '#') { chan = ServerInstance->FindChan(target); exempt_list[user] = user->nick; if (chan) { if (IS_LOCAL(user)) { if ((chan->IsModeSet('n')) && (!chan->HasUser(user))) { user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } if ((chan->IsModeSet('m')) && (chan->GetStatus(user) < STATUS_VOICE)) { user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } } int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,chan,TYPE_CHANNEL,temp,status, exempt_list)); if (MOD_RESULT) { return CMD_FAILURE; } const char* text = temp.c_str(); if (temp.empty()) { user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); return CMD_FAILURE; } FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,exempt_list)); if (status) { if (ServerInstance->Config->UndernetMsgPrefix) { chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%c %s", status, chan->name.c_str(), status, text); } else { chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%s", status, chan->name.c_str(), text); } } else { chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %s :%s", chan->name.c_str(), text); } FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,text,status,exempt_list)); } else { /* no such nick/channel */ user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target); return CMD_FAILURE; } return CMD_SUCCESS; } const char* destnick = parameters[0].c_str(); if (IS_LOCAL(user)) { const char* targetserver = strchr(destnick, '@'); if (targetserver) { std::string nickonly; nickonly.assign(destnick, 0, targetserver - destnick); dest = ServerInstance->FindNickOnly(nickonly); if (dest && strcasecmp(dest->server, targetserver + 1)) { /* Incorrect server for user */ user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } } else dest = ServerInstance->FindNickOnly(destnick); } else dest = ServerInstance->FindNick(destnick); if (dest) { if (parameters[1].empty()) { user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); return CMD_FAILURE; } int MOD_RESULT = 0; std::string temp = parameters[1]; FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,dest,TYPE_USER,temp,0,exempt_list)); if (MOD_RESULT) { return CMD_FAILURE; } const char* text = temp.c_str(); FOREACH_MOD(I_OnText,OnText(user,dest,TYPE_USER,text,0,exempt_list)); if (IS_LOCAL(dest)) { // direct write, same server user->WriteTo(dest, "NOTICE %s :%s", dest->nick.c_str(), text); } FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,dest,TYPE_USER,text,0,exempt_list)); } else { /* no such nick/channel */ user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } return CMD_SUCCESS; }
static bool WriteDatabase() { FILE *f; if (permchannelsconf.empty()) { // Fake success. return true; } std::string tempname = permchannelsconf + ".tmp"; /* * We need to perform an atomic write so as not to f**k things up. * So, let's write to a temporary file, flush and sync the FD, then rename the file.. * -- w00t */ f = fopen(tempname.c_str(), "w"); if (!f) { ServerInstance->Logs->Log("m_permchannels",LOG_DEFAULT, "permchannels: Cannot create database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno); return false; } fputs("# Permchannels DB\n# This file is autogenerated; any changes will be overwritten!\n<config format=\"compat\">\n", f); // Now, let's write. for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { Channel* chan = i->second; if (!chan->IsModeSet('P')) continue; char line[1024]; const char* items[] = { "<permchannels channel=", chan->name.c_str(), " topic=", chan->topic.c_str(), " modes=", chan->ChanModes(true), ">\n" }; int lpos = 0, item = 0, ipos = 0; while (lpos < 1022 && item < 7) { char c = items[item][ipos++]; if (c == 0) { // end of this string; hop to next string, insert a quote item++; ipos = 0; c = '"'; } else if (c == '\\' || c == '"') { line[lpos++] = '\\'; } line[lpos++] = c; } line[--lpos] = 0; fputs(line, f); } int write_error = 0; write_error = ferror(f); write_error |= fclose(f); if (write_error) { ServerInstance->Logs->Log("m_permchannels",LOG_DEFAULT, "permchannels: 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; } #ifdef _WIN32 if (remove(permchannelsconf.c_str())) { ServerInstance->Logs->Log("m_permchannels",LOG_DEFAULT, "permchannels: 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(tempname.c_str(), permchannelsconf.c_str()) < 0) { ServerInstance->Logs->Log("m_permchannels",LOG_DEFAULT, "permchannels: 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 HandleRMB(const std::vector<std::string>& parameters, User *user, bool neworder) { User* target; Channel* channel; std::string reason; std::string protectkey; std::string founderkey; bool hasnokicks; /* Set these to the parameters needed, the new version of this module switches it's parameters around * supplying a new command with the new order while keeping the old /remove with the older order. * /remove <nick> <channel> [reason ...] * /fpart <channel> <nick> [reason ...] */ const std::string& channame = parameters[neworder ? 0 : 1]; const std::string& username = parameters[neworder ? 1 : 0]; /* Look up the user we're meant to be removing from the channel */ target = ServerInstance->FindNick(username); /* And the channel we're meant to be removing them from */ channel = ServerInstance->FindChan(channame); /* Fix by brain - someone needs to learn to validate their input! */ if ((!target) || (target->registered != REG_ALL) || (!channel)) { user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), !channel ? channame.c_str() : username.c_str()); return CMD_FAILURE; } if (!channel->HasUser(target)) { user->WriteServ( "NOTICE %s :*** The user %s is not on channel %s", user->nick.c_str(), target->nick.c_str(), channel->name.c_str()); return CMD_FAILURE; } int ulevel = channel->GetPrefixValue(user); int tlevel = channel->GetPrefixValue(target); hasnokicks = (ServerInstance->Modules->Find("m_nokicks.so") && channel->IsModeSet('Q')); if (ServerInstance->ULine(target->server)) { user->WriteNumeric(482, "%s %s :Only a u-line may remove a u-line from a channel.", user->nick.c_str(), channame.c_str()); return CMD_FAILURE; } /* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */ if ((!IS_LOCAL(user)) || (!supportnokicks || !hasnokicks)) { /* We'll let everyone remove their level and below, eg: * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1) * a ulined target will get a higher level than it's possible for a /remover to get..so they're safe. * Nobody may remove a founder. */ if ((!IS_LOCAL(user)) || ((ulevel > VOICE_VALUE) && (ulevel >= tlevel) && (tlevel != 50000))) { // REMOVE/FPART will be sent to the target's server and it will reply with a PART (or do nothing if it doesn't understand the command) if (!IS_LOCAL(target)) return CMD_SUCCESS; std::string reasonparam; /* If a reason is given, use it */ if(parameters.size() > 2) reasonparam = parameters[2]; else reasonparam = "No reason given"; /* Build up the part reason string. */ reason = "Removed by " + user->nick + ": " + reasonparam; channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s removed %s from the channel", channel->name.c_str(), user->nick.c_str(), target->nick.c_str()); target->WriteServ("NOTICE %s :*** %s removed you from %s with the message: %s", target->nick.c_str(), user->nick.c_str(), channel->name.c_str(), reasonparam.c_str()); channel->PartUser(target, reason); } else { user->WriteServ( "NOTICE %s :*** You do not have access to /remove %s from %s", user->nick.c_str(), target->nick.c_str(), channel->name.c_str()); return CMD_FAILURE; } } else { /* m_nokicks.so was loaded and +Q was set, block! */ user->WriteServ( "484 %s %s :Can't remove user %s from channel (+Q set)", user->nick.c_str(), channel->name.c_str(), target->nick.c_str()); return CMD_FAILURE; } return CMD_SUCCESS; }
CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, User *user) { User *dest; Channel *chan; CUList except_list; LocalUser* localuser = IS_LOCAL(user); if (localuser) localuser->idle_lastmsg = ServerInstance->Time(); if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) return CMD_SUCCESS; if (parameters[0][0] == '$') { if (!user->HasPrivPermission("users/mass-message")) return CMD_SUCCESS; ModResult MOD_RESULT; std::string temp = parameters[1]; FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list, MSG_PRIVMSG)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; const char* text = temp.c_str(); const char* servermask = (parameters[0].c_str()) + 1; FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list)); if (InspIRCd::Match(ServerInstance->Config->ServerName, servermask, NULL)) { user->SendAll("PRIVMSG", "%s", text); } FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list, MSG_PRIVMSG)); return CMD_SUCCESS; } char status = 0; const char* target = parameters[0].c_str(); if (ServerInstance->Modes->FindPrefix(*target)) { status = *target; target++; } if (*target == '#') { chan = ServerInstance->FindChan(target); except_list.insert(user); if (chan) { if (localuser && chan->GetPrefixValue(user) < VOICE_VALUE) { if (chan->IsModeSet('n') && !chan->HasUser(user)) { user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } if (chan->IsModeSet('m')) { user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } if (ServerInstance->Config->RestrictBannedUsers) { if (chan->IsBanned(user)) { user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } } } ModResult MOD_RESULT; std::string temp = parameters[1]; FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, chan, TYPE_CHANNEL, temp, status, except_list, MSG_PRIVMSG)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; const char* text = temp.c_str(); /* Check again, a module may have zapped the input string */ if (temp.empty()) { user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); return CMD_FAILURE; } FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,except_list)); if (status) { if (ServerInstance->Config->UndernetMsgPrefix) { chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%c %s", status, chan->name.c_str(), status, text); } else { chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%s", status, chan->name.c_str(), text); } } else { chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %s :%s", chan->name.c_str(), text); } FOREACH_MOD(I_OnUserMessage, OnUserMessage(user,chan, TYPE_CHANNEL, text, status, except_list, MSG_PRIVMSG)); } else { /* no such nick/channel */ user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), target); return CMD_FAILURE; } return CMD_SUCCESS; } const char* destnick = parameters[0].c_str(); if (localuser) { const char* targetserver = strchr(destnick, '@'); if (targetserver) { std::string nickonly; nickonly.assign(destnick, 0, targetserver - destnick); dest = ServerInstance->FindNickOnly(nickonly); if (dest && strcasecmp(dest->server.c_str(), targetserver + 1)) { /* Incorrect server for user */ user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } } else dest = ServerInstance->FindNickOnly(destnick); } else dest = ServerInstance->FindNick(destnick); if ((dest) && (dest->registered == REG_ALL)) { if (parameters[1].empty()) { user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); return CMD_FAILURE; } if (dest->IsAway()) { /* auto respond with aweh msg */ user->WriteNumeric(301, "%s %s :%s", user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str()); } ModResult MOD_RESULT; std::string temp = parameters[1]; FIRST_MOD_RESULT(OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list, MSG_PRIVMSG)); if (MOD_RESULT == MOD_RES_DENY) return CMD_FAILURE; const char* text = temp.c_str(); FOREACH_MOD(I_OnText,OnText(user, dest, TYPE_USER, text, 0, except_list)); if (IS_LOCAL(dest)) { // direct write, same server user->WriteTo(dest, "PRIVMSG %s :%s", dest->nick.c_str(), text); } FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, dest, TYPE_USER, text, 0, except_list, MSG_PRIVMSG)); } else { /* no such nick/channel */ user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } return CMD_SUCCESS; }
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; }