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