]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_sqllog.cpp
55a74152bc4b90502397b93856f90a1d4b506464
[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                 if(strcmp(SQLRESID, request->GetData()) == 0)
266                 {
267                         SQLresult* res;
268                         std::map<unsigned long, QueryInfo*>::iterator n;
269
270                         res = static_cast<SQLresult*>(request);
271                         log(DEBUG, "Got SQL result (%s) with ID %lu", res->GetData(), res->id);
272
273                         n = active_queries.find(res->id);
274
275                         if (n != active_queries.end())
276                         {
277                                 log(DEBUG,"This is an active query");
278                                 n->second->Go(res);
279
280                                 std::map<unsigned long, QueryInfo*>::iterator n = active_queries.find(res->id);
281                                 active_queries.erase(n);
282                         }
283                 }
284                 return SQLSUCCESS;
285         }
286
287         void AddLogEntry(int category, const std::string &nick, const std::string &host, const std::string &source)
288         {
289                 // is the sql module loaded? If not, we don't attempt to do anything.
290                 if (!SQLModule)
291                         return;
292
293                 SQLrequest req = SQLreq(this, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);
294                 if(req.Send())
295                 {
296                         QueryInfo* i = new QueryInfo(nick, host, req.id, category);
297                         i->qs = FIND_SOURCE;
298                         active_queries[req.id] = i;
299                 }
300                 else
301                 {
302                         log(DEBUG, "SQLrequest failed: %s", req.error.Str());
303                 }
304
305                 /*long nickid = InsertNick(nick);
306                 long sourceid = InsertNick(source);
307                 long hostid = InsertHost(host);
308                 InsertEntry((unsigned)category,(unsigned)nickid,(unsigned)hostid,(unsigned)sourceid,(unsigned long)time(NULL));*/
309         }
310
311         virtual void OnOper(userrec* user, const std::string &opertype)
312         {
313                 AddLogEntry(LT_OPER,user->nick,user->host,user->server);
314         }
315
316         virtual void OnGlobalOper(userrec* user)
317         {
318                 AddLogEntry(LT_OPER,user->nick,user->host,user->server);
319         }
320
321         virtual int OnKill(userrec* source, userrec* dest, const std::string &reason)
322         {
323                 AddLogEntry(LT_KILL,dest->nick,dest->host,source->nick);
324                 return 0;
325         }
326
327         virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated)
328         {
329                 if ((command == "GLINE") || (command == "KLINE") || (command == "ELINE") || (command == "ZLINE"))
330                 {
331                         AddLogEntry(LT_XLINE,user->nick,command[0]+std::string(":")+std::string(parameters[0]),user->server);
332                 }
333                 return 0;
334         }
335
336         virtual void OnUserConnect(userrec* user)
337         {
338                 AddLogEntry(LT_CONNECT,user->nick,user->host,user->server);
339         }
340
341         virtual void OnGlobalConnect(userrec* user)
342         {
343                 AddLogEntry(LT_CONNECT,user->nick,user->host,user->server);
344         }
345
346         virtual void OnUserQuit(userrec* user, const std::string &reason)
347         {
348                 AddLogEntry(LT_DISCONNECT,user->nick,user->host,user->server);
349         }
350
351         virtual void OnLoadModule(Module* mod, const std::string &name)
352         {
353                 AddLogEntry(LT_LOADMODULE,name,Srv->GetServerName(),Srv->GetServerName());
354         }
355
356         virtual ~ModuleSQLLog()
357         {
358         }
359         
360         virtual Version GetVersion()
361         {
362                 return Version(1,0,0,1,VF_VENDOR);
363         }
364         
365 };
366
367 class ModuleSQLLogFactory : public ModuleFactory
368 {
369  public:
370         ModuleSQLLogFactory()
371         {
372         }
373         
374         ~ModuleSQLLogFactory()
375         {
376         }
377         
378         virtual Module * CreateModule(Server* Me)
379         {
380                 return new ModuleSQLLog(Me);
381         }
382         
383 };
384
385
386 extern "C" void * init_module( void )
387 {
388         return new ModuleSQLLogFactory;
389 }
390