]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_sqllog.cpp
Forgot to init it, clean up mem leakage too and log X-Lines proper.
[user/henk/code/inspircd.git] / src / modules / extra / m_sqllog.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "users.h"
15 #include "channels.h"
16 #include "modules.h"
17 #include "configreader.h"
18 #include "inspircd.h"
19 #include "m_sqlv2.h"
20
21
22 static Module* SQLModule;
23 static Module* MyMod;
24 static std::string dbid;
25
26 enum LogTypes { LT_OPER = 1, LT_KILL, LT_SERVLINK, LT_XLINE, LT_CONNECT, LT_DISCONNECT, LT_FLOOD, LT_LOADMODULE };
27
28 enum QueryState { FIND_SOURCE, INSERT_SOURCE, FIND_NICK, INSERT_NICK, FIND_HOST, INSERT_HOST, INSERT_LOGENTRY, DONE };
29
30 class QueryInfo;
31
32 std::map<unsigned long,QueryInfo*> active_queries;
33
34 class QueryInfo
35 {
36  public:
37         QueryState qs;
38         unsigned long id;
39         std::string nick;
40         std::string hostname;
41         int sourceid;
42         int nickid;
43         int hostid;
44         int category;
45         time_t date;
46         std::string lastquery;
47
48         QueryInfo(const std::string &n, const std::string &h, unsigned long i, int cat)
49         {
50                 qs = FIND_SOURCE;
51                 nick = n;
52                 hostname = h;
53                 id = i;
54                 category = cat;
55                 sourceid = nickid = hostid = -1;
56                 date = time(NULL);
57                 lastquery = "";
58         }
59
60         void Go(SQLresult* res)
61         {
62                 // Nothing here and not sent yet
63                 SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "", "");
64
65                 switch (qs)
66                 {
67                         case FIND_SOURCE:
68                                 // "SELECT id,actor FROM ircd_log_actors WHERE actor='"+nick+"'"
69                                 // If we find it, advance to FIND_NICK state, otherwise go to INSERT_SOURCE
70                                 if (res->Cols())
71                                 {
72                                         if (sourceid == -1)
73                                         {
74                                                 sourceid = atoi(res->GetValue(0,0).d.c_str());
75                                                 qs = FIND_NICK;
76                                         }
77                                         else qs = INSERT_SOURCE;
78                                 }
79                                 else
80                                 {
81                                         if (lastquery == "SELECT id,actor FROM ircd_log_actors WHERE actor='?'")
82                                         {
83                                                 qs = INSERT_SOURCE;
84                                         }
85                                         else
86                                         {
87                                                 lastquery = "SELECT id,actor FROM ircd_log_actors WHERE actor='?'";
88                                                 req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);
89                                                 if(req.Send())
90                                                 {
91                                                         qs = FIND_SOURCE;
92                                                         active_queries[req.id] = this;
93                                                 }
94                                                 else
95                                                 {
96                                                         //ServerInstance->Log(DEBUG, "SQLrequest failed: %s", req.error.Str());
97                                                 }
98                                                 break;
99                                         }
100                                 }
101                         case INSERT_SOURCE:
102                                 // "INSERT INTO ircd_log_actors VALUES('','"+nick+"')")
103                                 // after we've done this, go back to FIND_SOURCE
104                                 lastquery = "INSERT INTO ircd_log_actors VALUES('','?')";
105                                 req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick);
106                                 if(req.Send())
107                                 {
108                                         qs = FIND_NICK;
109                                         active_queries[req.id] = this;
110                                 }
111                                 else
112                                 {
113                                         //ServerInstance->Log(DEBUG, "SQLrequest failed: %s", req.error.Str());
114                                 }
115                                 
116                         break;
117                         case FIND_NICK:
118                                 // "SELECT id,actor FROM ircd_log_actors WHERE actor='"+nick+"'"
119                                 // If we find it, advance to FIND_HOST state, otherwise go to INSERT_NICK
120                                 if (res->Cols())
121                                 {
122                                         if (nickid == -1)
123                                         {
124                                                 nickid = atoi(res->GetValue(0,0).d.c_str());
125                                                 qs = FIND_HOST;
126                                         }
127                                         else qs = INSERT_NICK;
128                                 }
129                                 else
130                                 {
131                                         if (lastquery == "SELECT id,actor FROM ircd_log_actors WHERE actor='?'")
132                                         {
133                                                 qs = INSERT_NICK;
134                                         }
135                                         else
136                                         {
137                                                 req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);
138                                                 if(req.Send())
139                                                 {
140                                                         qs = FIND_NICK;
141                                                         active_queries[req.id] = this;
142                                                 }
143                                                 else
144                                                 {
145                                                         //ServerInstance->Log(DEBUG, "SQLrequest failed: %s", req.error.Str());
146                                                 }
147                                                 break;
148                                         }
149                                 }
150                         case INSERT_NICK:
151                                 // "INSERT INTO ircd_log_actors VALUES('','"+nick+"')")
152                                 // after we've done this, go back to FIND_NICK
153                                 req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')",nick);
154                                 if(req.Send())
155                                 {
156                                         qs = FIND_HOST;
157                                         active_queries[req.id] = this;
158                                 }
159                                 else
160                                 {
161                                         //ServerInstance->Log(DEBUG, "SQLrequest failed: %s", req.error.Str());
162                                 }
163                         break;
164                         case FIND_HOST:
165                                 // "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='"+host+"'"
166                                 // If we find it, advance to INSERT_LOGENTRY state, otherwise go to INSERT_HOST
167                                 if (res->Cols())
168                                 {
169                                         if (hostid == -1)
170                                         {
171                                                 hostid = atoi(res->GetValue(0,0).d.c_str());
172                                                 qs = INSERT_LOGENTRY;
173                                         }
174                                         else qs = INSERT_HOST;
175                                 }
176                                 else
177                                 {
178                                         if (lastquery == "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'")
179                                         {
180                                                 qs = INSERT_HOST;
181                                         }
182                                         else
183                                         {
184                                                 lastquery = "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'";
185                                                 req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'",hostname);
186                                                 if(req.Send())
187                                                 {
188                                                         qs = FIND_HOST;
189                                                         active_queries[req.id] = this;
190                                                 }
191                                                 else
192                                                 {
193                                                         //ServerInstance->Log(DEBUG, "SQLrequest failed: %s", req.error.Str());
194                                                 }
195                                                 break;
196                                         }
197                                 }
198                         case INSERT_HOST:
199                                 // "INSERT INTO ircd_log_hosts VALUES('','"+host+"')"
200                                 // after we've done this, go back to FIND_HOST
201                                 lastquery = "INSERT INTO ircd_log_hosts VALUES('','?')";
202                                 req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_hosts VALUES('','?')", hostname);
203                                 if(req.Send())
204                                 {
205                                         qs = INSERT_LOGENTRY;
206                                         active_queries[req.id] = this;
207                                 }
208                                 else
209                                 {
210                                         //ServerInstance->Log(DEBUG, "SQLrequest failed: %s", req.error.Str());
211                                 }
212                         break;
213                         case INSERT_LOGENTRY:
214                                 // INSERT INTO ircd_log VALUES('',%lu,%lu,%lu,%lu,%lu)",(unsigned long)category,(unsigned long)nickid,(unsigned long)hostid,(unsigned long)sourceid,(unsigned long)date
215                                 // aaand done! (discard result)
216                                 if ((nickid == -1) || (hostid == -1) || (sourceid == -1))
217                                 {
218                                         qs = FIND_SOURCE;
219                                         this->Go(res);
220                                 }
221                                 else
222                                 {
223                                         lastquery = "INSERT INTO ircd_log VALUES()";
224                                         req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log VALUES('',"+ConvToStr(category)+","+ConvToStr(nickid)+","+ConvToStr(hostid)+","+ConvToStr(sourceid)+","+ConvToStr(date)+")");
225                                                         /*,category,
226                                                         nickid,
227                                                         hostid,
228                                                         sourceid,
229                                                         date);*/
230                                         if(req.Send())
231                                         {
232                                                 qs = DONE;
233                                         }
234                                         else
235                                         {
236                                                 //ServerInstance->Log(DEBUG, "SQLrequest failed: %s", req.error.Str());
237                                         }
238                                 }
239                         break;
240                         case DONE:
241                                 delete active_queries[req.id];
242                                 active_queries[req.id] = NULL;
243                         break;
244                 }
245         }
246 };
247
248 /* $ModDesc: Logs network-wide data to an SQL database */
249
250 class ModuleSQLLog : public Module
251 {
252         InspIRCd* Srv;
253         ConfigReader* Conf;
254
255  public:
256         ModuleSQLLog(InspIRCd* Me)
257         : Module::Module(Me), Srv(Me)
258         {
259                 ServerInstance->UseInterface("SQLutils");
260                 ServerInstance->UseInterface("SQL");
261
262                 Module* SQLutils = ServerInstance->FindModule("m_sqlutils.so");
263                 if (!SQLutils)
264                         throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so.");
265
266                 SQLModule = Srv->FindFeature("SQL");
267
268                 OnRehash("");
269                 MyMod = this;
270                 active_queries.clear();
271         }
272
273         virtual ~ModuleSQLLog()
274         {
275                 ServerInstance->DoneWithInterface("SQL");
276                 ServerInstance->DoneWithInterface("SQLutils");
277         }
278
279         void Implements(char* List)
280         {
281                 List[I_OnRehash] = List[I_OnOper] = List[I_OnGlobalOper] = List[I_OnKill] = 1;
282                 List[I_OnPreCommand] = List[I_OnUserConnect] = 1;
283                 List[I_OnUserQuit] = List[I_OnLoadModule] = List[I_OnRequest] = 1;
284         }
285
286         void ReadConfig()
287         {
288                 ConfigReader Conf(Srv);
289                 dbid = Conf.ReadValue("sqllog","dbid",0);       // database id of a database configured in sql module
290         }
291
292         virtual void OnRehash(const std::string &parameter)
293         {
294                 ReadConfig();
295         }
296
297         virtual char* OnRequest(Request* request)
298         {
299                 if(strcmp(SQLRESID, request->GetId()) == 0)
300                 {
301                         SQLresult* res;
302                         std::map<unsigned long, QueryInfo*>::iterator n;
303
304                         res = static_cast<SQLresult*>(request);
305                         ServerInstance->Log(DEBUG, "Got SQL result (%s) with ID %lu", res->GetId(), res->id);
306
307                         n = active_queries.find(res->id);
308
309                         if (n != active_queries.end())
310                         {
311                                 ServerInstance->Log(DEBUG,"This is an active query");
312                                 n->second->Go(res);
313
314                                 std::map<unsigned long, QueryInfo*>::iterator n = active_queries.find(res->id);
315                                 active_queries.erase(n);
316                         }
317
318                         return SQLSUCCESS;
319                 }
320
321                 ServerInstance->Log(DEBUG, "Got unsupported API version string: %s", request->GetId());
322
323                 return NULL;
324         }
325
326         void AddLogEntry(int category, const std::string &nick, const std::string &host, const std::string &source)
327         {
328                 // is the sql module loaded? If not, we don't attempt to do anything.
329                 if (!SQLModule)
330                         return;
331
332                 SQLrequest req = SQLreq(this, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);
333                 if(req.Send())
334                 {
335                         QueryInfo* i = new QueryInfo(nick, host, req.id, category);
336                         i->qs = FIND_SOURCE;
337                         active_queries[req.id] = i;
338                         ServerInstance->Log(DEBUG,"Active query id %d",req.id);
339                 }
340                 else
341                 {
342                         ServerInstance->Log(DEBUG, "SQLrequest failed: %s", req.error.Str());
343                 }
344
345                 /*long nickid = InsertNick(nick);
346                 long sourceid = InsertNick(source);
347                 long hostid = InsertHost(host);
348                 InsertEntry((unsigned)category,(unsigned)nickid,(unsigned)hostid,(unsigned)sourceid,(unsigned long)time(NULL));*/
349         }
350
351         virtual void OnOper(userrec* user, const std::string &opertype)
352         {
353                 AddLogEntry(LT_OPER,user->nick,user->host,user->server);
354         }
355
356         virtual void OnGlobalOper(userrec* user)
357         {
358                 AddLogEntry(LT_OPER,user->nick,user->host,user->server);
359         }
360
361         virtual int OnKill(userrec* source, userrec* dest, const std::string &reason)
362         {
363                 AddLogEntry(LT_KILL,dest->nick,dest->host,source->nick);
364                 return 0;
365         }
366
367         virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
368         {
369                 if ((command == "GLINE" || command == "KLINE" || command == "ELINE" || command == "ZLINE") && validated)
370                 {
371                         AddLogEntry(LT_XLINE,user->nick,command[0]+std::string(":")+std::string(parameters[0]),user->server);
372                 }
373                 return 0;
374         }
375
376         virtual void OnUserConnect(userrec* user)
377         {
378                 AddLogEntry(LT_CONNECT,user->nick,user->host,user->server);
379         }
380
381         virtual void OnUserQuit(userrec* user, const std::string &reason)
382         {
383                 AddLogEntry(LT_DISCONNECT,user->nick,user->host,user->server);
384         }
385
386         virtual void OnLoadModule(Module* mod, const std::string &name)
387         {
388                 AddLogEntry(LT_LOADMODULE,name,Srv->Config->ServerName, Srv->Config->ServerName);
389         }
390
391         virtual Version GetVersion()
392         {
393                 return Version(1,1,0,1,VF_VENDOR,API_VERSION);
394         }
395         
396 };
397
398 class ModuleSQLLogFactory : public ModuleFactory
399 {
400  public:
401         ModuleSQLLogFactory()
402         {
403         }
404         
405         ~ModuleSQLLogFactory()
406         {
407         }
408         
409         virtual Module * CreateModule(InspIRCd* Me)
410         {
411                 return new ModuleSQLLog(Me);
412         }
413         
414 };
415
416
417 extern "C" void * init_module( void )
418 {
419         return new ModuleSQLLogFactory;
420 }