anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

command.cpp (8200B)

      1 /*
      2  *
      3  * (C) 2008-2011 Robin Burchell <w00t@inspircd.org>
      4  * (C) 2008-2022 Anope Team <team@anope.org>
      5  *
      6  * Please read COPYING and README for further details.
      7  */
      8 
      9 #include "services.h"
     10 #include "commands.h"
     11 #include "users.h"
     12 #include "language.h"
     13 #include "config.h"
     14 #include "bots.h"
     15 #include "opertype.h"
     16 #include "access.h"
     17 #include "regchannel.h"
     18 #include "channels.h"
     19 
     20 CommandSource::CommandSource(const Anope::string &n, User *user, NickCore *core, CommandReply *r, BotInfo *bi) : nick(n), u(user), nc(core), reply(r),
     21 	c(NULL), service(bi)
     22 {
     23 }
     24 
     25 const Anope::string &CommandSource::GetNick() const
     26 {
     27 	return this->nick;
     28 }
     29 
     30 User *CommandSource::GetUser()
     31 {
     32 	return this->u;
     33 }
     34 
     35 NickCore *CommandSource::GetAccount()
     36 {
     37 	return this->nc;
     38 }
     39 
     40 AccessGroup CommandSource::AccessFor(ChannelInfo *ci)
     41 {
     42 	if (this->u)
     43 		return ci->AccessFor(this->u);
     44 	else if (this->nc)
     45 		return ci->AccessFor(this->nc);
     46 	else
     47 		return AccessGroup();
     48 }
     49 
     50 bool CommandSource::IsFounder(ChannelInfo *ci)
     51 {
     52 	if (this->u)
     53 		return ::IsFounder(this->u, ci);
     54 	else if (this->nc)
     55 		return *this->nc == ci->GetFounder();
     56 	return false;
     57 }
     58 
     59 bool CommandSource::HasCommand(const Anope::string &cmd)
     60 {
     61 	if (this->u)
     62 		return this->u->HasCommand(cmd);
     63 	else if (this->nc && this->nc->o)
     64 		return this->nc->o->ot->HasCommand(cmd);
     65 	return false;
     66 }
     67 
     68 bool CommandSource::HasPriv(const Anope::string &cmd)
     69 {
     70 	if (this->u)
     71 		return this->u->HasPriv(cmd);
     72 	else if (this->nc && this->nc->o)
     73 		return this->nc->o->ot->HasPriv(cmd);
     74 	return false;
     75 }
     76 
     77 bool CommandSource::IsServicesOper()
     78 {
     79 	if (this->u)
     80 		return this->u->IsServicesOper();
     81 	else if (this->nc)
     82 		return this->nc->IsServicesOper();
     83 	return false;
     84 }
     85 
     86 bool CommandSource::IsOper()
     87 {
     88 	if (this->u)
     89 		return this->u->HasMode("OPER");
     90 	else if (this->nc)
     91 		return this->nc->IsServicesOper();
     92 	return false;
     93 }
     94 
     95 void CommandSource::Reply(const char *message, ...)
     96 {
     97 	va_list args;
     98 	char buf[4096]; // Messages can be really big.
     99 
    100 	const char *translated_message = Language::Translate(this->nc, message);
    101 
    102 	va_start(args, message);
    103 	vsnprintf(buf, sizeof(buf), translated_message, args);
    104 
    105 	this->Reply(Anope::string(buf));
    106 
    107 	va_end(args);
    108 }
    109 
    110 void CommandSource::Reply(const Anope::string &message)
    111 {
    112 	const char *translated_message = Language::Translate(this->nc, message.c_str());
    113 
    114 	sepstream sep(translated_message, '\n', true);
    115 	Anope::string tok;
    116 	while (sep.GetToken(tok))
    117 		this->reply->SendMessage(this->service, tok);
    118 }
    119 
    120 Command::Command(Module *o, const Anope::string &sname, size_t minparams, size_t maxparams) : Service(o, "Command", sname), max_params(maxparams), min_params(minparams), module(o)
    121 {
    122 	allow_unregistered = require_user = false;
    123 }
    124 
    125 Command::~Command()
    126 {
    127 }
    128 
    129 void Command::SetDesc(const Anope::string &d)
    130 {
    131 	this->desc = d;
    132 }
    133 
    134 void Command::ClearSyntax()
    135 {
    136 	this->syntax.clear();
    137 }
    138 
    139 void Command::SetSyntax(const Anope::string &s)
    140 {
    141 	this->syntax.push_back(s);
    142 }
    143 
    144 void Command::SendSyntax(CommandSource &source)
    145 {
    146 	Anope::string s = Language::Translate(source.GetAccount(), _("Syntax"));
    147 	if (!this->syntax.empty())
    148 	{
    149 		source.Reply("%s: \002%s %s\002", s.c_str(), source.command.c_str(), Language::Translate(source.GetAccount(), this->syntax[0].c_str()));
    150 		Anope::string spaces(s.length(), ' ');
    151 		for (unsigned i = 1, j = this->syntax.size(); i < j; ++i)
    152 			source.Reply("%s  \002%s %s\002", spaces.c_str(), source.command.c_str(), Language::Translate(source.GetAccount(), this->syntax[i].c_str()));
    153 	}
    154 	else
    155 		source.Reply("%s: \002%s\002", s.c_str(), source.command.c_str());
    156 }
    157 
    158 bool Command::AllowUnregistered() const
    159 {
    160 	return this->allow_unregistered;
    161 }
    162 
    163 void Command::AllowUnregistered(bool b)
    164 {
    165 	this->allow_unregistered = b;
    166 }
    167 
    168 bool Command::RequireUser() const
    169 {
    170 	return this->require_user;
    171 }
    172 
    173 void Command::RequireUser(bool b)
    174 {
    175 	this->require_user = b;
    176 }
    177 
    178 const Anope::string Command::GetDesc(CommandSource &) const
    179 {
    180 	return this->desc;
    181 }
    182 
    183 void Command::OnServHelp(CommandSource &source)
    184 {
    185 	source.Reply("    %-14s %s", source.command.c_str(), Language::Translate(source.nc, this->GetDesc(source).c_str()));
    186 }
    187 
    188 bool Command::OnHelp(CommandSource &source, const Anope::string &subcommand) { return false; }
    189 
    190 void Command::OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
    191 {
    192 	this->SendSyntax(source);
    193 	bool has_help = source.service->commands.find("HELP") != source.service->commands.end();
    194 	if (has_help)
    195 		source.Reply(MORE_INFO, Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), source.command.c_str());
    196 }
    197 
    198 void Command::Run(CommandSource &source, const Anope::string &message)
    199 {
    200 	std::vector<Anope::string> params;
    201 	spacesepstream(message).GetTokens(params);
    202 	bool has_help = source.service->commands.find("HELP") != source.service->commands.end();
    203 
    204 	CommandInfo::map::const_iterator it = source.service->commands.end();
    205 	unsigned count = 0;
    206 	for (unsigned max = params.size(); it == source.service->commands.end() && max > 0; --max)
    207 	{
    208 		Anope::string full_command;
    209 		for (unsigned i = 0; i < max; ++i)
    210 			full_command += " " + params[i];
    211 		full_command.erase(full_command.begin());
    212 
    213 		++count;
    214 		it = source.service->commands.find(full_command);
    215 	}
    216 
    217 	if (it == source.service->commands.end())
    218 	{
    219 		if (has_help)
    220 			source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->StrictPrivmsg.c_str(), source.service->nick.c_str());
    221 		else
    222 			source.Reply(_("Unknown command \002%s\002."), message.c_str());
    223 		return;
    224 	}
    225 
    226 	const CommandInfo &info = it->second;
    227 	ServiceReference<Command> c("Command", info.name);
    228 	if (!c)
    229 	{
    230 		if (has_help)
    231 			source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->StrictPrivmsg.c_str(), source.service->nick.c_str());
    232 		else
    233 			source.Reply(_("Unknown command \002%s\002."), message.c_str());
    234 		Log(source.service) << "Command " << it->first << " exists on me, but its service " << info.name << " was not found!";
    235 		return;
    236 	}
    237 
    238 	for (unsigned i = 0, j = params.size() - (count - 1); i < j; ++i)
    239 		params.erase(params.begin());
    240 
    241 	while (c->max_params > 0 && params.size() > c->max_params)
    242 	{
    243 		params[c->max_params - 1] += " " + params[c->max_params];
    244 		params.erase(params.begin() + c->max_params);
    245 	}
    246 
    247 	c->Run(source, it->first, info, params);
    248 }
    249 
    250 void Command::Run(CommandSource &source, const Anope::string &cmdname, const CommandInfo &info, std::vector<Anope::string> &params)
    251 {
    252 	if (this->RequireUser() && !source.GetUser())
    253 		return;
    254 
    255 	// Command requires registered users only
    256 	if (!this->AllowUnregistered() && !source.nc)
    257 	{
    258 		source.Reply(NICK_IDENTIFY_REQUIRED);
    259 		if (source.GetUser())
    260 			Log(LOG_NORMAL, "access_denied_unreg", source.service) << "Access denied for unregistered user " << source.GetUser()->GetMask() << " with command " << cmdname;
    261 		return;
    262 	}
    263 
    264 	source.command = cmdname;
    265 	source.permission = info.permission;
    266 
    267 	EventReturn MOD_RESULT;
    268 	FOREACH_RESULT(OnPreCommand, MOD_RESULT, (source, this, params));
    269 	if (MOD_RESULT == EVENT_STOP)
    270 		return;
    271 
    272 	if (params.size() < this->min_params)
    273 	{
    274 		this->OnSyntaxError(source, !params.empty() ? params[params.size() - 1] : "");
    275 		return;
    276 	}
    277 
    278 	// If the command requires a permission, and they aren't registered or don't have the required perm, DENIED
    279 	if (!info.permission.empty() && !source.HasCommand(info.permission))
    280 	{
    281 		source.Reply(ACCESS_DENIED);
    282 		if (source.GetUser())
    283 			Log(LOG_NORMAL, "access_denied", source.service) << "Access denied for user " << source.GetUser()->GetMask() << " with command " << cmdname;
    284 		return;
    285 	}
    286 
    287 	this->Execute(source, params);
    288 	FOREACH_MOD(OnPostCommand, (source, this, params));
    289 }
    290 
    291 bool Command::FindCommandFromService(const Anope::string &command_service, BotInfo* &bot, Anope::string &name)
    292 {
    293 	bot = NULL;
    294 
    295 	for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
    296 	{
    297 		BotInfo *bi = it->second;
    298 
    299 		for (CommandInfo::map::const_iterator cit = bi->commands.begin(), cit_end = bi->commands.end(); cit != cit_end; ++cit)
    300 		{
    301 			const Anope::string &c_name = cit->first;
    302 			const CommandInfo &info = cit->second;
    303 
    304 			if (info.name != command_service)
    305 				continue;
    306 
    307 			bot = bi;
    308 			name = c_name;
    309 			return true;
    310 		}
    311 	}
    312 
    313 	return false;
    314 }