Anope IRC Services  Version 2.0
os_logsearch.cpp
Go to the documentation of this file.
1 /* OperServ 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 
15 {
16  static inline Anope::string CreateLogName(const Anope::string &file, time_t t = Anope::CurTime)
17  {
18  char timestamp[32];
19 
20  tm *tm = localtime(&t);
21 
22  strftime(timestamp, sizeof(timestamp), "%Y%m%d", tm);
23 
24  return Anope::LogDir + "/" + file + "." + timestamp;
25  }
26 
27  public:
28  CommandOSLogSearch(Module *creator) : Command(creator, "operserv/logsearch", 1, 3)
29  {
30  this->SetDesc(_("Searches logs for a matching pattern"));
31  this->SetSyntax(_("[+\037days\037d] [+\037limit\037l] \037pattern\037"));
32  }
33 
34  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
35  {
36  int days = 7, replies = 50;
37 
38  unsigned i;
39  for (i = 0; i < params.size() && params[i][0] == '+'; ++i)
40  {
41  switch (params[i][params[i].length() - 1])
42  {
43  case 'd':
44  if (params[i].length() > 2)
45  {
46  Anope::string dur = params[i].substr(1, params[i].length() - 2);
47  try
48  {
49  days = convertTo<int>(dur);
50  if (days <= 0)
51  throw ConvertException();
52  }
53  catch (const ConvertException &)
54  {
55  source.Reply(_("Invalid duration %s, using %d days."), dur.c_str(), days);
56  }
57  }
58  break;
59  case 'l':
60  if (params[i].length() > 2)
61  {
62  Anope::string dur = params[i].substr(1, params[i].length() - 2);
63  try
64  {
65  replies = convertTo<int>(dur);
66  if (replies <= 0)
67  throw ConvertException();
68  }
69  catch (const ConvertException &)
70  {
71  source.Reply(_("Invalid limit %s, using %d."), dur.c_str(), replies);
72  }
73  }
74  break;
75  default:
76  source.Reply(_("Unknown parameter: %s"), params[i].c_str());
77  }
78  }
79 
80  if (i >= params.size())
81  {
82  this->OnSyntaxError(source, "");
83  return;
84  }
85 
86  Anope::string search_string = params[i++];
87  for (; i < params.size(); ++i)
88  search_string += " " + params[i];
89 
90  Log(LOG_ADMIN, source, this) << "for " << search_string;
91 
92  const Anope::string &logfile_name = Config->GetModule(this->owner)->Get<const Anope::string>("logname");
93  std::list<Anope::string> matches;
94  for (int d = days - 1; d >= 0; --d)
95  {
96  Anope::string lf_name = CreateLogName(logfile_name, Anope::CurTime - (d * 86400));
97  Log(LOG_DEBUG) << "Searching " << lf_name;
98  std::fstream fd(lf_name.c_str(), std::ios_base::in);
99  if (!fd.is_open())
100  continue;
101 
102  for (Anope::string buf, token; std::getline(fd, buf.str());)
103  if (Anope::Match(buf, "*" + search_string + "*"))
104  matches.push_back(buf);
105 
106  fd.close();
107  }
108 
109  unsigned found = matches.size();
110  if (!found)
111  {
112  source.Reply(_("No matches for \002%s\002 found."), search_string.c_str());
113  return;
114  }
115 
116  while (matches.size() > static_cast<unsigned>(replies))
117  matches.pop_front();
118 
119  source.Reply(_("Matches for \002%s\002:"), search_string.c_str());
120  unsigned count = 0;
121  for (std::list<Anope::string>::iterator it = matches.begin(), it_end = matches.end(); it != it_end; ++it)
122  source.Reply("#%d: %s", ++count, it->c_str());
123  source.Reply(_("Showed %d/%d matches for \002%s\002."), matches.size(), found, search_string.c_str());
124  }
125 
126  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
127  {
128  this->SendSyntax(source);
129  source.Reply(" ");
130  source.Reply(_("This command searches the Services logfiles for messages\n"
131  "that match the given pattern. The day and limit argument\n"
132  "may be used to specify how many days of logs to search\n"
133  "and the number of replies to limit to. By default this\n"
134  "command searches one week of logs, and limits replies\n"
135  "to 50.\n"
136  " \n"
137  "For example:\n"
138  " \002LOGSEARCH +21d +500l Anope\002\n"
139  " Searches the last 21 days worth of logs for messages\n"
140  " containing Anope and lists the most recent 500 of them."));
141  return true;
142  }
143 };
144 
145 class OSLogSearch : public Module
146 {
148 
149  public:
150  OSLogSearch(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
151  commandoslogsearch(this)
152  {
153  }
154 };
155 
std::string & str()
Definition: anope.h:119
void push_back(char c)
Definition: anope.h:142
static Anope::string CreateLogName(const Anope::string &file, time_t t=Anope::CurTime)
OSLogSearch(const Anope::string &modname, const Anope::string &creator)
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
void SetDesc(const Anope::string &d)
Definition: command.cpp:130
CoreExport time_t CurTime
Definition: main.cpp:41
string substr(size_type pos=0, size_type n=npos) const
Definition: anope.h:277
CommandOSLogSearch(Module *creator)
Definition: Config.cs:26
CoreExport bool Match(const string &str, const string &mask, bool case_sensitive=false, bool use_regex=false)
Definition: misc.cpp:407
virtual void OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
Definition: command.cpp:191
#define anope_override
Definition: services.h:56
#define MODULE_INIT(x)
Definition: modules.h:45
CoreExport Anope::string LogDir
Definition: init.cpp:33
void SetSyntax(const Anope::string &s)
Definition: command.cpp:140
CommandOSLogSearch commandoslogsearch
void SendSyntax(CommandSource &)
Definition: command.cpp:145
const char * c_str() const
Definition: anope.h:117
Definition: logger.h:53
CoreExport Anope::string strftime(time_t t, const NickCore *nc=NULL, bool short_output=false)
Definition: misc.cpp:356
#define _(x)
Definition: services.h:50
Module * owner
Definition: service.h:84
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override