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