cs_log.cpp

Go to the documentation of this file.
00001 /* ChanServ core functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 #include "memoserv.h"
00016 
00017 class CommandCSLog : public Command
00018 {
00019 public:
00020         CommandCSLog(Module *creator) : Command(creator, "chanserv/log", 1, 4)
00021         {
00022                 this->SetDesc(_("Configures channel logging settings"));
00023                 this->SetSyntax(_("\037channel\037"));
00024                 this->SetSyntax(_("\037channel\037 \037command\037 \037method\037 [\037status\037]"));
00025         }
00026 
00027         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00028         {
00029                 const Anope::string &channel = params[0];
00030 
00031                 ChannelInfo *ci = ChannelInfo::Find(channel);
00032                 if (ci == NULL)
00033                         source.Reply(CHAN_X_NOT_REGISTERED, channel.c_str());
00034                 else if (!source.AccessFor(ci).HasPriv("SET") && !source.HasPriv("chanserv/set"))
00035                         source.Reply(ACCESS_DENIED);
00036                 else if (params.size() == 1)
00037                 {
00038                         if (ci->log_settings->empty())
00039                                 source.Reply(_("There currently are no logging configurations for %s."), ci->name.c_str());
00040                         else
00041                         {
00042                                 ListFormatter list;
00043                                 list.AddColumn("Number").AddColumn("Service").AddColumn("Command").AddColumn("Method").AddColumn("");
00044 
00045                                 for (unsigned i = 0; i < ci->log_settings->size(); ++i)
00046                                 {
00047                                         const LogSetting *log = ci->log_settings->at(i);
00048 
00049                                         ListFormatter::ListEntry entry;
00050                                         entry["Number"] = stringify(i + 1);
00051                                         entry["Service"] = log->command_service;
00052                                         entry["Command"] = log->command_name;
00053                                         entry["Method"] = log->method;
00054                                         entry[""] = log->extra;
00055                                         list.AddEntry(entry);
00056                                 }
00057 
00058                                 source.Reply(_("Log list for %s:"), ci->name.c_str());
00059 
00060                                 std::vector<Anope::string> replies;
00061                                 list.Process(replies);
00062 
00063                                 for (unsigned i = 0; i < replies.size(); ++i)
00064                                         source.Reply(replies[i]);
00065                         }
00066                 }
00067                 else if (params.size() > 2)
00068                 {
00069                         const Anope::string &command = params[1];
00070                         const Anope::string &method = params[2];
00071                         const Anope::string &extra = params.size() > 3 ? params[3] : "";
00072 
00073                         size_t sl = command.find('/');
00074                         if (sl == Anope::string::npos)
00075                         {
00076                                 source.Reply(_("%s is not a valid command."), command.c_str());
00077                                 return;
00078                         }
00079 
00080                         Anope::string service = command.substr(0, sl),
00081                                 command_name = command.substr(sl + 1);
00082                         BotInfo *bi = BotInfo::Find(service, true);
00083 
00084                         if (bi == NULL || bi->commands.count(command_name) == 0)
00085                         {
00086                                 source.Reply(_("%s is not a valid command."), command.c_str());
00087                                 return;
00088                         }
00089 
00090                         ServiceReference<Command> c_service("Command", bi->commands[command_name].name);
00091                         if (!c_service)
00092                         {
00093                                 source.Reply(_("%s is not a valid command."), command.c_str());
00094                                 return;
00095                         }
00096 
00097                         if (!method.equals_ci("MESSAGE") && !method.equals_ci("NOTICE") && !method.equals_ci("MEMO"))
00098                         {
00099                                 source.Reply(_("%s is not a valid logging method."), method.c_str());
00100                                 return;
00101                         }
00102 
00103                         for (unsigned i = 0; i < extra.length(); ++i)
00104                                 if (ModeManager::GetStatusChar(extra[i]) == 0)
00105                                 {
00106                                         source.Reply(_("%c is an unknown status mode."), extra[i]);
00107                                         return;
00108                                 }
00109 
00110                         bool override = !source.AccessFor(ci).HasPriv("SET");
00111 
00112                         for (unsigned i = ci->log_settings->size(); i > 0; --i)
00113                         {
00114                                 LogSetting *log = ci->log_settings->at(i - 1);
00115 
00116                                 if (log->service_name == bi->commands[command_name].name && log->method.equals_ci(method))
00117                                 {
00118                                         if (log->extra == extra)
00119                                         {
00120                                                 delete log;
00121                                                 ci->log_settings->erase(ci->log_settings->begin() + i - 1);
00122                                                 Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to remove logging for " << command << " with method " << method << (extra == "" ? "" : " ") << extra;
00123                                                 source.Reply(_("Logging for command %s on %s with log method %s%s%s has been removed."), command_name.c_str(), bi->nick.c_str(), method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str());
00124                                         }
00125                                         else
00126                                         {
00127                                                 log->extra = extra;
00128                                                 Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to change logging for " << command << " to method " << method << (extra == "" ? "" : " ") << extra;
00129                                                 source.Reply(_("Logging changed for command %s on %s, now using log method %s%s%s."), command_name.c_str(), bi->nick.c_str(), method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str());
00130                                         }
00131                                         return;
00132                                 }
00133                         }
00134 
00135                         LogSetting *log = new LogSetting();
00136                         log->ci = ci;
00137                         log->service_name = bi->commands[command_name].name;
00138                         log->command_service = bi->nick;
00139                         log->command_name = command_name;
00140                         log->method = method;
00141                         log->extra = extra;
00142                         log->created = Anope::CurTime;
00143                         log->creator = source.GetNick();
00144 
00145                         ci->log_settings->push_back(log);
00146                         Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to log " << command << " with method " << method << (extra == "" ? "" : " ") << extra;
00147 
00148                         source.Reply(_("Logging is now active for command %s on %s, using log method %s%s%s."), command_name.c_str(), bi->nick.c_str(), method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str());
00149                 }
00150                 else
00151                         this->OnSyntaxError(source, "");
00152         }
00153 
00154         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00155         {
00156                 this->SendSyntax(source);
00157                 source.Reply(" ");
00158                 source.Reply(_("The %s command allows users to configure logging settings\n"
00159                                 "for their channel. If no parameters are given this command\n"
00160                                 "lists the current logging methods in place for this channel.\n"
00161                                 " \n"
00162                                 "Otherwise, \037command\037 must be a command name, and \037method\037\n"
00163                                 "is one of the following logging methods:\n"
00164                                 " \n"
00165                                 " MESSAGE [status], NOTICE [status], MEMO\n"
00166                                 " \n"
00167                                 "Which are used to message, notice, and memo the channel respectively.\n"
00168                                 "With MESSAGE or NOTICE you must have a service bot assigned to and joined\n"
00169                                 "to your channel. Status may be a channel status such as @ or +.\n"
00170                                 " \n"
00171                                 "To remove a logging method use the same syntax as you would to add it.\n"
00172                                 " \n"
00173                                 "Example:\n"
00174                                 " %s #anope chanserv/access MESSAGE @%\n"
00175                                 " Would message any channel operators whenever someone used the\n"
00176                                 " ACCESS command on ChanServ on the channel."),
00177                                 source.command.c_str(), source.command.c_str());
00178                 return true;
00179         }
00180 };
00181 
00182 class CSLog : public Module
00183 {
00184         ServiceReference<MemoServService> MSService;
00185         CommandCSLog commandcslog;
00186 
00187  public:
00188         CSLog(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00189                 MSService("MemoServService", "MemoServ"), commandcslog(this)
00190         {
00191                 this->SetAuthor("Anope");
00192 
00193                 Implementation i[] = { I_OnLog };
00194                 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00195         }
00196 
00197         void OnLog(Log *l) anope_override
00198         {
00199                 if (l->type != LOG_COMMAND || l->u == NULL || l->c == NULL || l->ci == NULL || !Me || !Me->IsSynced())
00200                         return;
00201 
00202                 for (unsigned i = l->ci->log_settings->size(); i > 0; --i)
00203                 {
00204                         const LogSetting *log = l->ci->log_settings->at(i - 1);
00205 
00206                         if (log->service_name == l->c->name)
00207                         {
00208                                 Anope::string buffer = l->u->nick + " used " + log->command_name + " " + l->buf.str();
00209 
00210                                 if (log->method.equals_ci("MESSAGE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL)
00211                                 {
00212                                         IRCD->SendPrivmsg(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str());
00213                                         l->ci->bi->lastmsg = Anope::CurTime;
00214                                 }
00215                                 else if (log->method.equals_ci("NOTICE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL)
00216                                         IRCD->SendNotice(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str());
00217                                 else if (log->method.equals_ci("MEMO") && MSService && l->ci->WhoSends() != NULL)
00218                                         MSService->Send(l->ci->WhoSends()->nick, l->ci->name, buffer, true);
00219                         }
00220                 }
00221         }
00222 };
00223 
00224 MODULE_INIT(CSLog)