CmdResult Handle (const std::vector<std::string>& parameters, User *user) { User* target = ServerInstance->FindNick(parameters[0]); Channel* channel = ServerInstance->FindChan(parameters[1]); std::string message = parameters[2]; if ((target) && (target->registered == REG_ALL) && (channel)) { if (ServerInstance->ULine(target->server)) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client", user->nick.c_str()); return CMD_FAILURE; } if(!channel->HasUser(target)) { user->WriteServ("NOTICE %s :*** %s is not on the channel %s", user->nick.c_str(), target->nick.c_str(), channel->name.c_str()); return CMD_FAILURE; } channel->WriteChannel(target, "PRIVMSG %s :%s", channel->name.c_str(), message.c_str()); ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SASAY to make " + target->nick.c_str() + " say in " + channel->name.c_str() + ": \"" + message + "\""); return CMD_SUCCESS; } else { user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick.c_str()); } return CMD_FAILURE; }
/** 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(secretmode)) && (!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; }
CmdResult Handle (const std::vector<std::string>& parameters, User *user) { User* dest = ServerInstance->FindNick(parameters[0]); if (dest) { if (ServerInstance->ULine(dest->server)) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str()); return CMD_FAILURE; } if (IS_LOCAL(user) && !ServerInstance->IsChannel(parameters[1].c_str(), ServerInstance->Config->Limits.ChanMax)) { /* we didn't need to check this for each character ;) */ user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Invalid characters in channel name or name too long"); return CMD_FAILURE; } /* For local users, we send the JoinUser which may create a channel and set its TS. * For non-local users, we just return CMD_SUCCESS, knowing this will propagate it where it needs to be * and then that server will generate the users JOIN or FJOIN instead. */ if (IS_LOCAL(dest)) { Channel::JoinUser(ServerInstance, dest, parameters[1].c_str(), true, "", false, ServerInstance->Time()); /* Fix for dotslasher and w00t - if the join didnt succeed, return CMD_FAILURE so that it doesnt propagate */ Channel* n = ServerInstance->FindChan(parameters[1]); if (n) { if (n->HasUser(dest)) { ServerInstance->SNO->WriteToSnoMask('a', std::string(user->nick)+" used SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]); return CMD_SUCCESS; } else { user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]+" (User is probably banned, or blocking modes)"); return CMD_FAILURE; } } else { user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]); return CMD_FAILURE; } } else { ServerInstance->SNO->WriteToSnoMask('a', std::string(user->nick)+" sent remote SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]); return CMD_SUCCESS; } } else { user->WriteServ("NOTICE "+std::string(user->nick)+" :*** No such nickname "+parameters[0]); return CMD_FAILURE; } }
CmdResult Handle (const std::vector<std::string>& parameters, User *user) { User* dest = ServerInstance->FindNick(parameters[0]); if ((dest) && (dest->registered == REG_ALL)) { if (ServerInstance->ULine(dest->server)) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str()); return CMD_FAILURE; } if (IS_LOCAL(user) && !ServerInstance->IsChannel(parameters[1].c_str(), ServerInstance->Config->Limits.ChanMax)) { /* we didn't need to check this for each character ;) */ user->WriteNotice("*** Invalid characters in channel name or name too long"); return CMD_FAILURE; } /* For local users, we call Channel::JoinUser which may create a channel and set its TS. * For non-local users, we just return CMD_SUCCESS, knowing this will propagate it where it needs to be * and then that server will handle the command. */ LocalUser* localuser = IS_LOCAL(dest); if (localuser) { Channel* n = Channel::JoinUser(localuser, parameters[1], true); if (n) { if (n->HasUser(dest)) { ServerInstance->SNO->WriteToSnoMask('a', user->nick+" used SAJOIN to make "+dest->nick+" join "+parameters[1]); return CMD_SUCCESS; } else { user->WriteNotice("*** Could not join "+dest->nick+" to "+parameters[1]+" (User is probably banned, or blocking modes)"); return CMD_FAILURE; } } else { user->WriteNotice("*** Could not join "+dest->nick+" to "+parameters[1]); return CMD_FAILURE; } } else { ServerInstance->SNO->WriteToSnoMask('a', user->nick+" sent remote SAJOIN to make "+dest->nick+" join "+parameters[1]); return CMD_SUCCESS; } } else { user->WriteNotice("*** No such nickname "+parameters[0]); return CMD_FAILURE; } }
CmdResult Handle (const std::vector<std::string>& parameters, User *user) { User* dest = ServerInstance->FindNick(parameters[1]); Channel* channel = ServerInstance->FindChan(parameters[0]); const char* reason = ""; if ((dest) && (dest->registered == REG_ALL) && (channel)) { if (parameters.size() > 2) { reason = parameters[2].c_str(); } else { reason = dest->nick.c_str(); } if (ServerInstance->ULine(dest->server)) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client", user->nick.c_str()); return CMD_FAILURE; } /* For local clients, directly kick them. For remote clients, * just return CMD_SUCCESS knowing the protocol module will route the SAKICK to the user's * local server and that will kick them instead. */ if (IS_LOCAL(dest)) { channel->KickUser(ServerInstance->FakeClient, dest, reason); Channel *n = ServerInstance->FindChan(parameters[1]); if (n && n->HasUser(dest)) { /* Sort-of-bug: If the command was issued remotely, this message won't be sent */ user->WriteNotice("*** Unable to kick " + dest->nick + " from " + parameters[0]); return CMD_FAILURE; } } if (IS_LOCAL(user)) { /* Locally issued command; send the snomasks */ ServerInstance->SNO->WriteGlobalSno('a', user->nick + " SAKICKed " + dest->nick + " on " + parameters[0]); } return CMD_SUCCESS; } else { user->WriteNotice("*** Invalid nickname or channel"); } return CMD_FAILURE; }
CmdResult Handle (const std::vector<std::string>& parameters, User *user) { User* dest = ServerInstance->FindNick(parameters[0]); Channel* channel = ServerInstance->FindChan(parameters[1]); std::string reason; if ((dest) && (dest->registered == REG_ALL) && (channel)) { if (parameters.size() > 2) reason = parameters[2]; if (ServerInstance->ULine(dest->server)) { user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Cannot use an SA command on a u-lined client",user->nick.c_str()); return CMD_FAILURE; } /* For local clients, directly part them generating a PART message. For remote clients, * just return CMD_SUCCESS knowing the protocol module will route the SAPART to the users * local server and that will generate the PART instead */ if (IS_LOCAL(dest)) { channel->PartUser(dest, reason); Channel* n = ServerInstance->FindChan(parameters[1]); if (!n) { ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAPART to make "+dest->nick+" part "+parameters[1]); return CMD_SUCCESS; } else { if (!n->HasUser(dest)) { ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAPART to make "+dest->nick+" part "+parameters[1]); return CMD_SUCCESS; } else { user->WriteServ("NOTICE %s :*** Unable to make %s part %s",user->nick.c_str(), dest->nick.c_str(), parameters[1].c_str()); return CMD_FAILURE; } } } return CMD_SUCCESS; } else { user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick.c_str()); } return CMD_FAILURE; }
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; }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { Channel* channel = ServerInstance->FindChan(parameters[0]); std::string reason = ConvToStr("Cycling"); if (parameters.size() > 1) { /* reason provided, use it */ reason = reason + ": " + parameters[1]; } if (!channel) { user->WriteNumeric(403, "%s %s :No such channel", user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } if (channel->HasUser(user)) { /* * technically, this is only ever sent locally, but pays to be safe ;p */ if (IS_LOCAL(user)) { if (channel->GetPrefixValue(user) < VOICE_VALUE && channel->IsBanned(user)) { /* banned, boned. drop the message. */ user->WriteServ("NOTICE "+user->nick+" :*** You may not cycle, as you are banned on channel " + channel->name); return CMD_FAILURE; } channel->PartUser(user, reason); Channel::JoinUser(user, parameters[0], true, "", false, ServerInstance->Time()); } return CMD_SUCCESS; } else { user->WriteNumeric(442, "%s %s :You're not on that channel", user->nick.c_str(), channel->name.c_str()); } return CMD_FAILURE; }
CmdResult Handle (const std::vector<std::string>& parameters, User *user) { if (CommandParser::LoopCall(user, this, parameters, 1)) return CMD_FAILURE; User* dest = ServerInstance->FindNick(parameters[0]); Channel* channel = ServerInstance->FindChan(parameters[1]); std::string reason; if ((dest) && (dest->registered == REG_ALL) && (channel)) { if (parameters.size() > 2) reason = parameters[2]; if (dest->server->IsULine()) { user->WriteNumeric(ERR_NOPRIVILEGES, ":Cannot use an SA command on a u-lined client"); return CMD_FAILURE; } if (!channel->HasUser(dest)) { user->WriteNotice("*** " + dest->nick + " is not on " + channel->name); return CMD_FAILURE; } /* For local clients, directly part them generating a PART message. For remote clients, * just return CMD_SUCCESS knowing the protocol module will route the SAPART to the users * local server and that will generate the PART instead */ if (IS_LOCAL(dest)) { channel->PartUser(dest, reason); ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAPART to make "+dest->nick+" part "+channel->name); } return CMD_SUCCESS; } else { user->WriteNotice("*** Invalid nickname or channel"); } return CMD_FAILURE; }
CmdResult Handle(User* user, const Params& parameters) override { User* dest = ServerInstance->FindNick(parameters[1]); Channel* channel = ServerInstance->FindChan(parameters[0]); if ((dest) && (dest->registered == REG_ALL) && (channel)) { const std::string& reason = (parameters.size() > 2) ? parameters[2] : dest->nick; if (dest->server->IsULine()) { user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } if (!channel->HasUser(dest)) { user->WriteNotice("*** " + dest->nick + " is not on " + channel->name); return CMD_FAILURE; } /* For local clients, directly kick them. For remote clients, * just return CMD_SUCCESS knowing the protocol module will route the SAKICK to the user's * local server and that will kick them instead. */ if (IS_LOCAL(dest)) { // Target is on this server, kick them and send the snotice channel->KickUser(ServerInstance->FakeClient, dest, reason); ServerInstance->SNO.WriteGlobalSno('a', user->nick + " SAKICKed " + dest->nick + " on " + channel->name); } return CMD_SUCCESS; } else { user->WriteNotice("*** Invalid nickname or channel"); } return CMD_FAILURE; }
/** Handle /KICK */ CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User *user) { std::string reason; Channel* c = ServerInstance->FindChan(parameters[0]); User* u; if (ServerInstance->Parser->LoopCall(user, this, parameters, 1)) return CMD_SUCCESS; if (IS_LOCAL(user)) u = ServerInstance->FindNickOnly(parameters[1]); else u = ServerInstance->FindNick(parameters[1]); if (!u || !c) { user->WriteServ( "401 %s %s :No such nick/channel", user->nick.c_str(), u ? parameters[0].c_str() : parameters[1].c_str()); return CMD_FAILURE; } if ((IS_LOCAL(user)) && (!c->HasUser(user)) && (!ServerInstance->ULine(user->server))) { user->WriteServ( "442 %s %s :You're not on that channel!", user->nick.c_str(), parameters[0].c_str()); return CMD_FAILURE; } if (parameters.size() > 2) { reason.assign(parameters[2], 0, ServerInstance->Config->Limits.MaxKick); } else { reason.assign(user->nick, 0, ServerInstance->Config->Limits.MaxKick); } c->KickUser(user, u, reason); return CMD_SUCCESS; }
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; }
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 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; }
/** Handle /INVITE */ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, User *user) { ModResult MOD_RESULT; if (parameters.size() == 2 || parameters.size() == 3) { 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[1]); else timeout = ConvToInt(parameters[2]); } if ((!c) || (!u) || (u->registered != REG_ALL)) { user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), c ? parameters[0].c_str() : parameters[1].c_str()); return CMD_FAILURE; } if ((IS_LOCAL(user)) && (!c->HasUser(user))) { user->WriteNumeric(ERR_NOTONCHANNEL, "%s %s :You're not on that channel!",user->nick.c_str(), c->name.c_str()); return CMD_FAILURE; } if (c->HasUser(u)) { user->WriteNumeric(ERR_USERONCHANNEL, "%s %s %s :is already on channel",user->nick.c_str(),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 %s :You must be a channel %soperator", user->nick.c_str(), 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 %s",user->nick.c_str(),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 :%s",user->nick.c_str(), (*i)->chan->name.c_str()); } user->WriteNumeric(RPL_ENDOFINVITELIST, "%s :End of INVITE list",user->nick.c_str()); } return CMD_SUCCESS; }
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; }
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; }
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; }
CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *user) { /* * XXX - RFC says: * The <name> passed to WHO is matched against users' host, server, real * name and nickname * Currently, we support WHO #chan, WHO nick, WHO 0, WHO *, and the addition of a 'o' flag, as per RFC. */ /* WHO options */ opt_viewopersonly = false; opt_showrealhost = false; opt_realname = false; opt_mode = false; opt_ident = false; opt_metadata = false; opt_port = false; opt_away = false; opt_local = false; opt_far = false; opt_time = false; std::vector<std::string> whoresults; std::string initial = "352 " + user->nick + " "; /* Change '0' into '*' so the wildcard matcher can grok it */ std::string matchtext = ((parameters[0] == "0") ? "*" : parameters[0]); // WHO flags count as a wildcard bool usingwildcards = ((parameters.size() > 1) || (matchtext.find_first_of("*?.") != std::string::npos)); if (parameters.size() > 1) { for (std::string::const_iterator iter = parameters[1].begin(); iter != parameters[1].end(); ++iter) { switch (*iter) { case 'o': opt_viewopersonly = true; break; case 'h': if (user->HasPrivPermission("users/auspex")) opt_showrealhost = true; break; case 'r': opt_realname = true; break; case 'm': if (user->HasPrivPermission("users/auspex")) opt_mode = true; break; case 'M': if (user->HasPrivPermission("users/auspex")) opt_metadata = true; break; case 'i': opt_ident = true; break; case 'p': if (user->HasPrivPermission("users/auspex")) opt_port = true; break; case 'a': opt_away = true; break; case 'l': if (user->HasPrivPermission("users/auspex") || ServerInstance->Config->HideWhoisServer.empty()) opt_local = true; break; case 'f': if (user->HasPrivPermission("users/auspex") || ServerInstance->Config->HideWhoisServer.empty()) opt_far = true; break; case 't': opt_time = true; break; } } } /* who on a channel? */ Channel* ch = ServerInstance->FindChan(matchtext); if (ch) { if (CanView(ch,user)) { bool inside = ch->HasUser(user); /* who on a channel. */ const UserMembList *cu = ch->GetUsers(); for (UserMembCIter i = cu->begin(); i != cu->end(); i++) { /* None of this applies if we WHO ourselves */ if (user != i->first) { /* opers only, please */ if (opt_viewopersonly && !i->first->IsOper()) continue; /* If we're not inside the channel, hide +i users */ if (i->first->IsModeSet(invisiblemode) && !inside && !user->HasPrivPermission("users/auspex")) continue; } SendWhoLine(user, parameters, initial, ch, i->first, whoresults); } } } else { /* Match against wildcard of nick, server or host */ if (opt_viewopersonly) { /* Showing only opers */ for (std::list<User*>::iterator i = ServerInstance->Users->all_opers.begin(); i != ServerInstance->Users->all_opers.end(); i++) { User* oper = *i; if (whomatch(user, oper, matchtext.c_str())) { if (!user->SharesChannelWith(oper)) { if (usingwildcards && (!oper->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex"))) continue; } SendWhoLine(user, parameters, initial, NULL, oper, whoresults); } } } else { for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++) { if (whomatch(user, i->second, matchtext.c_str())) { if (!user->SharesChannelWith(i->second)) { if (usingwildcards && (i->second->IsModeSet(invisiblemode)) && (!user->HasPrivPermission("users/auspex"))) continue; } SendWhoLine(user, parameters, initial, NULL, i->second, whoresults); } } } } /* Send the results out */ for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++) user->WriteServ(*n); user->WriteNumeric(RPL_ENDOFWHO, "%s :End of /WHO list.", *parameters[0].c_str() ? parameters[0].c_str() : "*"); // Penalize the user a bit for large queries // (add one unit of penalty per 200 results) if (IS_LOCAL(user)) IS_LOCAL(user)->CommandFloodPenalty += whoresults.size() * 5; 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; }