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