Anope IRC Services  Version 2.0
cs_log.cpp
Go to the documentation of this file.
1 /* ChanServ core functions
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  */
11 
12 #include "module.h"
13 #include "modules/cs_log.h"
14 
16 {
17  LogSettingImpl() : Serializable("LogSetting")
18  {
19  }
20 
22  {
24  if (ci)
25  {
26  LogSettings *ls = ci->GetExt<LogSettings>("logsettings");
27  if (ls)
28  {
29  LogSettings::iterator it = std::find((*ls)->begin(), (*ls)->end(), this);
30  if (it != (*ls)->end())
31  (*ls)->erase(it);
32  }
33  }
34  }
35 
37  {
38  data["ci"] << chan;
39  data["service_name"] << service_name;
40  data["command_service"] << command_service;
41  data["command_name"] << command_name;
42  data["method"] << method;
43  data["extra"] << extra;
44  data["creator"] << creator;
45  data.SetType("created", Serialize::Data::DT_INT); data["created"] << created;
46  }
47 
49  {
50  Anope::string sci;
51  data["ci"] >> sci;
52 
54  if (ci == NULL)
55  return NULL;
56 
57  LogSettingImpl *ls;
58  if (obj)
60  else
61  {
62  LogSettings *lsettings = ci->Require<LogSettings>("logsettings");
63  ls = new LogSettingImpl();
64  (*lsettings)->push_back(ls);
65  }
66 
67  ls->chan = ci->name;
68  data["service_name"] >> ls->service_name;
69  data["command_service"] >> ls->command_service;
70  data["command_name"] >> ls->command_name;
71  data["method"] >> ls->method;
72  data["extra"] >> ls->extra;
73  data["creator"] >> ls->creator;
74  data["created"] >> ls->created;
75 
76  return ls;
77  }
78 };
79 
81 {
83 
85  {
86  for (iterator it = (*this)->begin(); it != (*this)->end();)
87  {
88  LogSetting *ls = *it;
89  ++it;
90  delete ls;
91  }
92  }
93 
95  {
96  return new LogSettingImpl();
97  }
98 };
99 
100 class CommandCSLog : public Command
101 {
102 public:
103  CommandCSLog(Module *creator) : Command(creator, "chanserv/log", 1, 4)
104  {
105  this->SetDesc(_("Configures channel logging settings"));
106  this->SetSyntax(_("\037channel\037"));
107  this->SetSyntax(_("\037channel\037 \037command\037 \037method\037 [\037status\037]"));
108  }
109 
110  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
111  {
112  const Anope::string &channel = params[0];
113 
114  ChannelInfo *ci = ChannelInfo::Find(channel);
115  if (ci == NULL)
116  source.Reply(CHAN_X_NOT_REGISTERED, channel.c_str());
117  else if (!source.AccessFor(ci).HasPriv("SET") && !source.HasPriv("chanserv/administration"))
118  source.Reply(ACCESS_DENIED);
119  else if (params.size() == 1)
120  {
121  LogSettings *ls = ci->Require<LogSettings>("logsettings");
122  if (!ls || (*ls)->empty())
123  source.Reply(_("There currently are no logging configurations for %s."), ci->name.c_str());
124  else
125  {
126  ListFormatter list(source.GetAccount());
127  list.AddColumn(_("Number")).AddColumn(_("Service")).AddColumn(_("Command")).AddColumn(_("Method")).AddColumn("");
128 
129  for (unsigned i = 0; i < (*ls)->size(); ++i)
130  {
131  const LogSetting *log = (*ls)->at(i);
132 
134  entry["Number"] = stringify(i + 1);
135  entry["Service"] = log->command_service;
136  entry["Command"] = !log->command_name.empty() ? log->command_name : log->service_name;
137  entry["Method"] = log->method;
138  entry[""] = log->extra;
139  list.AddEntry(entry);
140  }
141 
142  source.Reply(_("Log list for %s:"), ci->name.c_str());
143 
144  std::vector<Anope::string> replies;
145  list.Process(replies);
146 
147  for (unsigned i = 0; i < replies.size(); ++i)
148  source.Reply(replies[i]);
149  }
150  }
151  else if (params.size() > 2)
152  {
153  if (Anope::ReadOnly)
154  {
155  source.Reply(READ_ONLY_MODE);
156  return;
157  }
158 
159  LogSettings *ls = ci->Require<LogSettings>("logsettings");
160  const Anope::string &command = params[1];
161  const Anope::string &method = params[2];
162  const Anope::string &extra = params.size() > 3 ? params[3] : "";
163 
164  size_t sl = command.find('/');
165  if (sl == Anope::string::npos)
166  {
167  source.Reply(_("%s is not a valid command."), command.c_str());
168  return;
169  }
170 
171  Anope::string service = command.substr(0, sl),
172  command_name = command.substr(sl + 1);
173  BotInfo *bi = BotInfo::Find(service, true);
174 
175  Anope::string service_name;
176 
177  /* Allow either a command name or a service name. */
178  if (bi && bi->commands.count(command_name))
179  {
180  /* Get service name from command */
181  service_name = bi->commands[command_name].name;
182  }
183  else if (ServiceReference<Command>("Command", command.lower()))
184  {
185  /* This is the service name, don't use any specific command */
186  service_name = command;
187  bi = NULL;
188  command_name.clear();
189  }
190  else
191  {
192  source.Reply(_("%s is not a valid command."), command.c_str());
193  return;
194  }
195 
196  if (!method.equals_ci("MESSAGE") && !method.equals_ci("NOTICE") && !method.equals_ci("MEMO"))
197  {
198  source.Reply(_("%s is not a valid logging method."), method.c_str());
199  return;
200  }
201 
202  for (unsigned i = 0; i < extra.length(); ++i)
203  if (ModeManager::GetStatusChar(extra[i]) == 0)
204  {
205  source.Reply(_("%c is an unknown status mode."), extra[i]);
206  return;
207  }
208 
209  bool override = !source.AccessFor(ci).HasPriv("SET");
210 
211  for (unsigned i = (*ls)->size(); i > 0; --i)
212  {
213  LogSetting *log = (*ls)->at(i - 1);
214 
215  if (log->service_name == service_name && log->method.equals_ci(method) && command_name.equals_ci(log->command_name))
216  {
217  if (log->extra == extra)
218  {
219  Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to remove logging for " << command << " with method " << method << (extra == "" ? "" : " ") << extra;
220  source.Reply(_("Logging for command %s on %s with log method %s%s%s has been removed."), !log->command_name.empty() ? log->command_name.c_str() : log->service_name.c_str(), !log->command_service.empty() ? log->command_service.c_str() : "any service", method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str());
221  delete log;
222  }
223  else
224  {
225  log->extra = extra;
226  Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to change logging for " << command << " to method " << method << (extra == "" ? "" : " ") << extra;
227  source.Reply(_("Logging changed for command %s on %s, now using log method %s%s%s."), !log->command_name.empty() ? log->command_name.c_str() : log->service_name.c_str(), !log->command_service.empty() ? log->command_service.c_str() : "any service", method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str());
228  }
229  return;
230  }
231  }
232 
233  LogSetting *log = new LogSettingImpl();
234  log->chan = ci->name;
235  log->service_name = service_name;
236  if (bi)
237  log->command_service = bi->nick;
238  log->command_name = command_name;
239  log->method = method;
240  log->extra = extra;
241  log->created = Anope::CurTime;
242  log->creator = source.GetNick();
243 
244  (*ls)->push_back(log);
245 
246  Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to log " << command << " with method " << method << (extra == "" ? "" : " ") << extra;
247 
248  source.Reply(_("Logging is now active for command %s on %s, using log method %s%s%s."), !command_name.empty() ? command_name.c_str() : service_name.c_str(), bi ? bi->nick.c_str() : "any service", method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str());
249  }
250  else
251  this->OnSyntaxError(source, "");
252  }
253 
254  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
255  {
256  this->SendSyntax(source);
257  source.Reply(" ");
258  source.Reply(_("The %s command allows users to configure logging settings\n"
259  "for their channel. If no parameters are given this command\n"
260  "lists the current logging methods in place for this channel.\n"
261  " \n"
262  "Otherwise, \037command\037 must be a command name, and \037method\037\n"
263  "is one of the following logging methods:\n"
264  " \n"
265  " MESSAGE [status], NOTICE [status], MEMO\n"
266  " \n"
267  "Which are used to message, notice, and memo the channel respectively.\n"
268  "With MESSAGE or NOTICE you must have a service bot assigned to and joined\n"
269  "to your channel. Status may be a channel status such as @ or +.\n"
270  " \n"
271  "To remove a logging method use the same syntax as you would to add it.\n"
272  " \n"
273  "Example:\n"
274  " %s #anope chanserv/access MESSAGE @%\n"
275  " Would message any channel operators whenever someone used the\n"
276  " ACCESS command on ChanServ on the channel."),
277  source.command.upper().c_str(), source.command.upper().c_str());
278  return true;
279  }
280 };
281 
282 class CSLog : public Module
283 {
288 
289  struct LogDefault
290  {
292  };
293 
294  std::vector<LogDefault> defaults;
295 
296  public:
297  CSLog(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
298  MSService("MemoServService", "MemoServ"), commandcslog(this),
299  logsettings(this, "logsettings"), logsetting_type("LogSetting", LogSettingImpl::Unserialize)
300  {
301 
302  }
303 
305  {
306  Configuration::Block *block = conf->GetModule(this);
307  defaults.clear();
308 
309  for (int i = 0; i < block->CountBlock("default"); ++i)
310  {
311  Configuration::Block *def = block->GetBlock("default", i);
312 
313  LogDefault ld;
314 
315  ld.service = def->Get<const Anope::string>("service");
316  ld.command = def->Get<const Anope::string>("command");
317  ld.method = def->Get<const Anope::string>("method");
318 
319  defaults.push_back(ld);
320  }
321  }
322 
324  {
325  if (defaults.empty())
326  return;
327 
328  LogSettings *ls = logsettings.Require(ci);
329  for (unsigned i = 0; i < defaults.size(); ++i)
330  {
331  LogDefault &d = defaults[i];
332 
333  LogSetting *log = new LogSettingImpl();
334  log->chan = ci->name;
335 
336  if (!d.service.empty())
337  {
338  log->service_name = d.service.lower() + "/" + d.command.lower();
339  log->command_service = d.service;
340  log->command_name = d.command;
341  }
342  else
343  log->service_name = d.command;
344 
345  spacesepstream sep(d.method);
346  sep.GetToken(log->method);
347  log->extra = sep.GetRemaining();
348 
349  log->created = Anope::CurTime;
350  log->creator = ci->GetFounder() ? ci->GetFounder()->display : "(default)";
351 
352  (*ls)->push_back(log);
353  }
354  }
355 
357  {
358  if (l->type != LOG_COMMAND || l->u == NULL || l->c == NULL || l->ci == NULL || !Me || !Me->IsSynced())
359  return;
360 
361  LogSettings *ls = logsettings.Get(l->ci);
362  if (ls)
363  for (unsigned i = 0; i < (*ls)->size(); ++i)
364  {
365  const LogSetting *log = (*ls)->at(i);
366 
367  /* wrong command */
368  if (log->service_name != l->c->name)
369  continue;
370 
371  /* if a command name is given check the service and the command */
372  if (!log->command_name.empty())
373  {
374  /* wrong service (only check if not a fantasy command, though) */
375  if (!l->source->c && log->command_service != l->source->service->nick)
376  continue;
377 
378  if (!log->command_name.equals_ci(l->source->command))
379  continue;
380  }
381 
382  Anope::string buffer = l->u->nick + " used " + l->source->command.upper() + " " + l->buf.str();
383 
384  if (log->method.equals_ci("MEMO") && MSService && l->ci->WhoSends() != NULL)
385  MSService->Send(l->ci->WhoSends()->nick, l->ci->name, buffer, true);
386  else if (l->source->c)
387  /* Sending a channel message or notice in response to a fantasy command */;
388  else if (log->method.equals_ci("MESSAGE") && l->ci->c)
389  {
390  IRCD->SendPrivmsg(l->ci->WhoSends(), log->extra + l->ci->c->name, "%s", buffer.c_str());
391  l->ci->WhoSends()->lastmsg = Anope::CurTime;
392  }
393  else if (log->method.equals_ci("NOTICE") && l->ci->c)
394  IRCD->SendNotice(l->ci->WhoSends(), log->extra + l->ci->c->name, "%s", buffer.c_str());
395  }
396  }
397 };
398 
Anope::string service
Definition: cs_log.cpp:291
Definition: bots.h:24
ExtensibleItem< LogSettingsImpl > logsettings
Definition: cs_log.cpp:286
CoreExport bool ReadOnly
Definition: main.cpp:28
CSLog(const Anope::string &modname, const Anope::string &creator)
Definition: cs_log.cpp:297
Anope::string method
Definition: cs_log.h:21
Serialize::Type logsetting_type
Definition: cs_log.cpp:287
int CountBlock(const Anope::string &name)
Definition: config.cpp:35
bool IsSynced() const
Definition: servers.cpp:298
Definition: hashcomp.h:84
Anope::string name
Definition: regchannel.h:63
std::string & str()
Definition: anope.h:119
void push_back(char c)
Definition: anope.h:142
CommandCSLog(Module *creator)
Definition: cs_log.cpp:103
ServiceReference< MemoServService > MSService
Definition: cs_log.cpp:284
virtual void SendPrivmsg(const MessageSource &source, const Anope::string &dest, const char *fmt,...)
Definition: protocol.cpp:242
virtual void SendNotice(const MessageSource &source, const Anope::string &dest, const char *fmt,...)
Definition: protocol.cpp:221
#define ACCESS_DENIED
Definition: language.h:73
CommandInfo::map commands
Definition: bots.h:33
Anope::string extra
Definition: cs_log.h:21
std::vector< LogDefault > defaults
Definition: cs_log.cpp:294
string upper() const
Definition: anope.h:266
CommandCSLog commandcslog
Definition: cs_log.cpp:285
#define READ_ONLY_MODE
Definition: language.h:71
void OnReload(Configuration::Conf *conf) anope_override
Definition: cs_log.cpp:304
void SetDesc(const Anope::string &d)
Definition: command.cpp:130
bool equals_ci(const char *_str) const
Definition: anope.h:78
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
Definition: cs_log.cpp:254
Anope::string command_name
Definition: cs_log.h:20
string lower() const
Definition: anope.h:255
T * Require(const Anope::string &name)
Definition: extensible.h:244
CoreExport time_t CurTime
Definition: main.cpp:41
Anope::string service_name
Definition: cs_log.h:16
static ChannelInfo * Find(const Anope::string &name)
Definition: regchannel.cpp:630
string substr(size_type pos=0, size_type n=npos) const
Definition: anope.h:277
T * Require(Extensible *obj)
Definition: extensible.h:116
LogSetting * Create() anope_override
Definition: cs_log.cpp:94
std::map< Anope::string, Anope::string > ListEntry
Definition: lists.h:68
void OnLog(Log *l) anope_override
Definition: cs_log.cpp:356
size_type length() const
Definition: anope.h:131
Block * GetBlock(const Anope::string &name, int num=0)
Definition: config.cpp:43
time_t created
Definition: cs_log.h:23
virtual void OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
Definition: command.cpp:191
static char GetStatusChar(char symbol)
Definition: modes.cpp:558
void Serialize(Serialize::Data &data) const anope_override
Definition: cs_log.cpp:36
static const size_type npos
Definition: anope.h:44
static Serializable * Unserialize(Serializable *obj, Serialize::Data &data)
Definition: cs_log.cpp:48
Anope::string creator
Definition: cs_log.h:22
bool HasPriv(const Anope::string &privstr)
Definition: users.cpp:487
#define anope_override
Definition: services.h:56
bool empty() const
Definition: anope.h:126
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: cs_log.cpp:110
CoreExport IRCDProto * IRCD
Definition: protocol.cpp:23
const Anope::string GetRemaining()
Definition: hashcomp.cpp:156
Anope::string method
Definition: cs_log.cpp:291
#define MODULE_INIT(x)
Definition: modules.h:45
Anope::string chan
Definition: cs_log.h:14
void SetSyntax(const Anope::string &s)
Definition: command.cpp:140
Anope::string command
Definition: cs_log.cpp:291
Anope::string stringify(const T &x)
Definition: anope.h:710
LogSettingsImpl(Extensible *)
Definition: cs_log.cpp:82
#define CHAN_X_NOT_REGISTERED
Definition: language.h:84
Anope::string nick
Definition: users.h:62
std::vector< LogSetting * >::iterator iterator
Definition: cs_log.h:32
void OnChanRegistered(ChannelInfo *ci) anope_override
Definition: cs_log.cpp:323
bool GetToken(Anope::string &token)
Definition: hashcomp.cpp:99
T * Get(const Extensible *obj) const
Definition: extensible.h:103
T anope_dynamic_static_cast(O ptr)
Definition: anope.h:774
CoreExport Server * Me
Definition: servers.cpp:24
void SendSyntax(CommandSource &)
Definition: command.cpp:145
Anope::string command_service
Definition: cs_log.h:18
const char * c_str() const
Definition: anope.h:117
Definition: logger.h:53
T Get(const Anope::string &tag)
Definition: config.h:44
T * GetExt(const Anope::string &name) const
Definition: extensible.h:213
size_type find(const string &_str, size_type pos=0) const
Definition: anope.h:192
#define _(x)
Definition: services.h:50
static BotInfo * Find(const Anope::string &nick, bool nick_only=false)
Definition: bots.cpp:249
ListFormatter & AddColumn(const Anope::string &name)
Definition: misc.cpp:128
Type(const Anope::string &n, unserialize_func f, Module *owner=NULL)