command.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  * Copyright (C) 2008-2011 Robin Burchell <w00t@inspircd.org>
00004  * Copyright (C) 2008-2013 Anope Team <team@anope.org>
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  */
00009 
00010 #include "services.h"
00011 #include "commands.h"
00012 #include "users.h"
00013 #include "language.h"
00014 #include "config.h"
00015 #include "bots.h"
00016 #include "opertype.h"
00017 #include "access.h"
00018 #include "regchannel.h"
00019 #include "channels.h"
00020 
00021 CommandSource::CommandSource(const Anope::string &n, User *user, NickCore *core, CommandReply *r, BotInfo *bi) : nick(n), u(user), nc(core), reply(r),
00022         c(NULL), service(bi)
00023 {
00024 }
00025 
00026 const Anope::string &CommandSource::GetNick() const
00027 {
00028         return this->nick;
00029 }
00030 
00031 User *CommandSource::GetUser()
00032 {
00033         return this->u;
00034 }
00035 
00036 NickCore *CommandSource::GetAccount()
00037 {
00038         return this->nc;
00039 }
00040 
00041 AccessGroup CommandSource::AccessFor(ChannelInfo *ci)
00042 {
00043         if (this->u)
00044                 return ci->AccessFor(this->u);
00045         else if (this->nc)
00046                 return ci->AccessFor(this->nc);
00047         else
00048                 return AccessGroup();
00049 }
00050 
00051 bool CommandSource::IsFounder(ChannelInfo *ci)
00052 {
00053         if (this->u)
00054                 return ::IsFounder(this->u, ci);
00055         else if (this->nc)
00056                 return *this->nc == ci->GetFounder();
00057         return false;
00058 }
00059 
00060 bool CommandSource::HasCommand(const Anope::string &cmd)
00061 {
00062         if (this->u)
00063                 return this->u->HasCommand(cmd);
00064         else if (this->nc && this->nc->o)
00065                 return this->nc->o->ot->HasCommand(cmd);
00066         return false;
00067 }
00068 
00069 bool CommandSource::HasPriv(const Anope::string &cmd)
00070 {
00071         if (this->u)
00072                 return this->u->HasPriv(cmd);
00073         else if (this->nc && this->nc->o)
00074                 return this->nc->o->ot->HasPriv(cmd);
00075         return false;
00076 }
00077 
00078 bool CommandSource::IsServicesOper()
00079 {
00080         if (this->u)
00081                 return this->u->IsServicesOper();
00082         else if (this->nc)
00083                 return this->nc->IsServicesOper();
00084         return false;
00085 }
00086 
00087 bool CommandSource::IsOper()
00088 {
00089         if (this->u)
00090                 return this->u->HasMode("OPER");
00091         else if (this->nc)
00092                 return this->nc->IsServicesOper();
00093         return false;
00094 }
00095 
00096 void CommandSource::Reply(const char *message, ...)
00097 {
00098         va_list args;
00099         char buf[4096]; // Messages can be really big.
00100 
00101         const char *translated_message = Language::Translate(this->nc, message);
00102 
00103         va_start(args, message);
00104         vsnprintf(buf, sizeof(buf), translated_message, args);
00105 
00106         this->Reply(Anope::string(buf));
00107 
00108         va_end(args);
00109 }
00110 
00111 void CommandSource::Reply(const Anope::string &message)
00112 {
00113         const char *translated_message = Language::Translate(this->nc, message.c_str());
00114 
00115         sepstream sep(translated_message, '\n');
00116         Anope::string tok;
00117         while (sep.GetToken(tok))
00118                 this->reply->SendMessage(this->service, tok);
00119 }
00120 
00121 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(owner)
00122 {
00123         allow_unregistered = require_user = false;
00124 }
00125 
00126 Command::~Command()
00127 {
00128 }
00129 
00130 void Command::SetDesc(const Anope::string &d)
00131 {
00132         this->desc = d;
00133 }
00134 
00135 void Command::ClearSyntax()
00136 {
00137         this->syntax.clear();
00138 }
00139 
00140 void Command::SetSyntax(const Anope::string &s)
00141 {
00142         this->syntax.push_back(s);
00143 }
00144 
00145 void Command::SendSyntax(CommandSource &source)
00146 {
00147         if (!this->syntax.empty())
00148         {
00149                 source.Reply(_("Syntax: \002%s %s\002"), source.command.c_str(), this->syntax[0].c_str());
00150                 for (unsigned i = 1, j = this->syntax.size(); i < j; ++i)
00151                         source.Reply("        \002%s %s\002", source.command.c_str(), this->syntax[i].c_str());
00152         }
00153 }
00154 
00155 void Command::SendSyntax(CommandSource &source, const Anope::string &syn)
00156 {
00157         source.Reply(_("Syntax: \002%s %s\002"), source.command.c_str(), syn.c_str());
00158         source.Reply(MORE_INFO, Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str(), source.command.c_str());
00159 }
00160 
00161 bool Command::AllowUnregistered() const
00162 {
00163         return this->allow_unregistered;
00164 }
00165 
00166 void Command::AllowUnregistered(bool b)
00167 {
00168         this->allow_unregistered = b;
00169 }
00170 
00171 bool Command::RequireUser() const
00172 {
00173         return this->require_user;
00174 }
00175 
00176 void Command::RequireUser(bool b)
00177 {
00178         this->require_user = b;
00179 }
00180 
00181 const Anope::string &Command::GetDesc() const
00182 {
00183         return this->desc;
00184 }
00185 
00186 void Command::OnServHelp(CommandSource &source)
00187 {
00188         source.Reply("    %-14s %s", source.command.c_str(), Language::Translate(source.nc, this->GetDesc().c_str()));
00189 }
00190 
00191 bool Command::OnHelp(CommandSource &source, const Anope::string &subcommand) { return false; }
00192 
00193 void Command::OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
00194 {
00195         this->SendSyntax(source);
00196         source.Reply(MORE_INFO, Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str(), source.command.c_str());
00197 }
00198 
00199 void RunCommand(CommandSource &source, const Anope::string &message)
00200 {
00201         std::vector<Anope::string> params;
00202         spacesepstream(message).GetTokens(params);
00203         bool has_help = source.service->commands.find("HELP") != source.service->commands.end();
00204 
00205         CommandInfo::map::const_iterator it = source.service->commands.end();
00206         unsigned count = 0;
00207         for (unsigned max = params.size(); it == source.service->commands.end() && max > 0; --max)
00208         {
00209                 Anope::string full_command;
00210                 for (unsigned i = 0; i < max; ++i)
00211                         full_command += " " + params[i];
00212                 full_command.erase(full_command.begin());
00213 
00214                 ++count;
00215                 it = source.service->commands.find(full_command);
00216         }
00217 
00218         if (it == source.service->commands.end())
00219         {
00220                 if (has_help)
00221                         source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00222                 else
00223                         source.Reply(_("Unknown command \002%s\002."), message.c_str());
00224                 return;
00225         }
00226 
00227         const CommandInfo &info = it->second;
00228         ServiceReference<Command> c("Command", info.name);
00229         if (!c)
00230         {
00231                 if (has_help)
00232                         source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00233                 else
00234                         source.Reply(_("Unknown command \002%s\002."), message.c_str());
00235                 Log(source.service) << "Command " << it->first << " exists on me, but its service " << info.name << " was not found!";
00236                 return;
00237         }
00238 
00239         if (c->RequireUser() && !source.GetUser())
00240                 return;
00241 
00242         // Command requires registered users only
00243         if (!c->AllowUnregistered() && !source.nc)
00244         {
00245                 source.Reply(NICK_IDENTIFY_REQUIRED);
00246                 if (source.GetUser())
00247                         Log(LOG_NORMAL, "access_denied", source.service) << "Access denied for unregistered user " << source.GetUser()->GetMask() << " with command " << c->name;
00248                 return;
00249         }
00250 
00251         for (unsigned i = 0, j = params.size() - (count - 1); i < j; ++i)
00252                 params.erase(params.begin());
00253 
00254         while (c->max_params > 0 && params.size() > c->max_params)
00255         {
00256                 params[c->max_params - 1] += " " + params[c->max_params];
00257                 params.erase(params.begin() + c->max_params);
00258         }
00259 
00260         source.command = it->first;
00261         source.permission = info.permission;
00262 
00263         EventReturn MOD_RESULT;
00264         FOREACH_RESULT(I_OnPreCommand, OnPreCommand(source, c, params));
00265         if (MOD_RESULT == EVENT_STOP)
00266                 return;
00267 
00268         if (params.size() < c->min_params)
00269         {
00270                 c->OnSyntaxError(source, !params.empty() ? params[params.size() - 1] : "");
00271                 return;
00272         }
00273 
00274         // If the command requires a permission, and they aren't registered or don't have the required perm, DENIED
00275         if (!info.permission.empty() && !source.HasCommand(info.permission))
00276         {
00277                 source.Reply(ACCESS_DENIED);
00278                 if (source.GetUser())
00279                         Log(LOG_NORMAL, "access_denied", source.service) << "Access denied for user " << source.GetUser()->GetMask() << " with command " << c->name;
00280                 return;
00281         }
00282 
00283         Reference<NickCore> nc_reference(source.nc);
00284         c->Execute(source, params);
00285         if (!nc_reference)
00286                 source.nc = NULL;
00287         FOREACH_MOD(I_OnPostCommand, OnPostCommand(source, c, params));
00288 }
00289