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