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