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