]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_sqlutils.cpp
39cb97606a900b48c69bf7f9a72a1ba99fc76aa3
[user/henk/code/inspircd.git] / src / modules / extra / m_sqlutils.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 "inspircd.h"
15 #include <sstream>
16 #include <list>
17 #include "users.h"
18 #include "channels.h"
19 #include "modules.h"
20 #include "configreader.h"
21 #include "m_sqlutils.h"
22
23 /* $ModDesc: Provides some utilities to SQL client modules, such as mapping queries to users and channels */
24 /* $ModDep: m_sqlutils.h */
25
26 typedef std::map<unsigned long, User*> IdUserMap;
27 typedef std::map<unsigned long, Channel*> IdChanMap;
28 typedef std::list<unsigned long> AssocIdList;
29
30 class ModuleSQLutils : public Module
31 {
32 private:
33         IdUserMap iduser;
34         IdChanMap idchan;
35
36 public:
37         ModuleSQLutils(InspIRCd* Me)
38         : Module::Module(Me)
39         {
40                 ServerInstance->Modules->PublishInterface("SQLutils", this);
41                 Implementation eventlist[] = { I_OnChannelDelete, I_OnUnloadModule, I_OnRequest, I_OnUserDisconnect };
42                 ServerInstance->Modules->Attach(eventlist, this, 4);
43         }
44
45         virtual ~ModuleSQLutils()
46         {
47                 ServerInstance->Modules->UnpublishInterface("SQLutils", this);
48         }       
49
50         void Implements(char* List)
51         {
52                 List[I_OnChannelDelete] = List[I_OnUnloadModule] = List[I_OnRequest] =  List[I_OnUserDisconnect] = 1;
53         }
54
55         virtual char* OnRequest(Request* request)
56         {
57                 if(strcmp(SQLUTILAU, request->GetId()) == 0)
58                 {
59                         AssociateUser* req = (AssociateUser*)request;
60                         
61                         iduser.insert(std::make_pair(req->id, req->user));
62                         
63                         AttachList(req->user, req->id);
64                 }
65                 else if(strcmp(SQLUTILAC, request->GetId()) == 0)
66                 {
67                         AssociateChan* req = (AssociateChan*)request;
68                         
69                         idchan.insert(std::make_pair(req->id, req->chan));                      
70                         
71                         AttachList(req->chan, req->id);
72                 }
73                 else if(strcmp(SQLUTILUA, request->GetId()) == 0)
74                 {
75                         UnAssociate* req = (UnAssociate*)request;
76                         
77                         /* Unassociate a given query ID with all users and channels
78                          * it is associated with.
79                          */
80                         
81                         DoUnAssociate(iduser, req->id);
82                         DoUnAssociate(idchan, req->id);
83                 }
84                 else if(strcmp(SQLUTILGU, request->GetId()) == 0)
85                 {
86                         GetAssocUser* req = (GetAssocUser*)request;
87                         
88                         IdUserMap::iterator iter = iduser.find(req->id);
89                         
90                         if(iter != iduser.end())
91                         {
92                                 req->user = iter->second;
93                         }
94                 }
95                 else if(strcmp(SQLUTILGC, request->GetId()) == 0)
96                 {
97                         GetAssocChan* req = (GetAssocChan*)request;                     
98                         
99                         IdChanMap::iterator iter = idchan.find(req->id);
100                         
101                         if(iter != idchan.end())
102                         {
103                                 req->chan = iter->second;
104                         }
105                 }
106                 
107                 return SQLUTILSUCCESS;
108         }
109         
110         virtual void OnUserDisconnect(User* user)
111         {
112                 /* A user is disconnecting, first we need to check if they have a list of queries associated with them.
113                  * Then, if they do, we need to erase each of them from our IdUserMap (iduser) so when the module that
114                  * associated them asks to look them up then it gets a NULL result and knows to discard the query.
115                  */
116                 AssocIdList* il;
117                 
118                 if(user->GetExt("sqlutils_queryids", il))
119                 {
120                         for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++)
121                         {
122                                 IdUserMap::iterator iter;
123                         
124                                 iter = iduser.find(*listiter);
125                         
126                                 if(iter != iduser.end())
127                                 {
128                                         if(iter->second != user)
129                                         {
130                                                 ServerInstance->Log(DEBUG, "BUG: ID associated with user %s doesn't have the same User* associated with it in the map (erasing anyway)", user->nick);
131                                         }
132
133                                         iduser.erase(iter);
134                                 }
135                                 else
136                                 {
137                                         ServerInstance->Log(DEBUG, "BUG: user %s was extended with sqlutils_queryids but there was nothing matching in the map", user->nick);
138                                 }
139                         }
140                         
141                         user->Shrink("sqlutils_queryids");
142                         delete il;
143                 }
144         }
145         
146         void AttachList(Extensible* obj, unsigned long id)
147         {
148                 AssocIdList* il;
149                 
150                 if(!obj->GetExt("sqlutils_queryids", il))
151                 {
152                         /* Doesn't already exist, create a new list and attach it. */
153                         il = new AssocIdList;
154                         obj->Extend("sqlutils_queryids", il);
155                 }
156                 
157                 /* Now either way we have a valid list in il, attached. */
158                 il->push_back(id);
159         }
160         
161         void RemoveFromList(Extensible* obj, unsigned long id)
162         {
163                 AssocIdList* il;
164                 
165                 if(obj->GetExt("sqlutils_queryids", il))
166                 {
167                         /* Only do anything if the list exists... (which it ought to) */
168                         il->remove(id);
169                         
170                         if(il->empty())
171                         {
172                                 /* If we just emptied it.. */
173                                 delete il;
174                                 obj->Shrink("sqlutils_queryids");
175                         }
176                 }
177         }
178         
179         template <class T> void DoUnAssociate(T &map, unsigned long id)
180         {
181                 /* For each occurence of 'id' (well, only one..it's not a multimap) in 'map'
182                  * remove it from the map, take an Extensible* value from the map and remove
183                  * 'id' from the list of query IDs attached to it.
184                  */
185                 typename T::iterator iter = map.find(id);
186                 
187                 if(iter != map.end())
188                 {
189                         /* Found a value indexed by 'id', call RemoveFromList()
190                          * on it with 'id' to remove 'id' from the list attached
191                          * to the value.
192                          */
193                         RemoveFromList(iter->second, id);
194                 }
195         }
196         
197         virtual void OnChannelDelete(Channel* chan)
198         {
199                 /* A channel is being destroyed, first we need to check if it has a list of queries associated with it.
200                  * Then, if it does, we need to erase each of them from our IdChanMap (idchan) so when the module that
201                  * associated them asks to look them up then it gets a NULL result and knows to discard the query.
202                  */
203                 AssocIdList* il;
204                 
205                 if(chan->GetExt("sqlutils_queryids", il))
206                 {
207                         for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++)
208                         {
209                                 IdChanMap::iterator iter;
210                         
211                                 iter = idchan.find(*listiter);
212                         
213                                 if(iter != idchan.end())
214                                 {
215                                         if(iter->second != chan)
216                                         {
217                                                 ServerInstance->Log(DEBUG, "BUG: ID associated with channel %s doesn't have the same Channel* associated with it in the map (erasing anyway)", chan->name);
218                                         }
219                                         idchan.erase(iter);                                     
220                                 }
221                                 else
222                                 {
223                                         ServerInstance->Log(DEBUG, "BUG: channel %s was extended with sqlutils_queryids but there was nothing matching in the map", chan->name);
224                                 }
225                         }
226                         
227                         chan->Shrink("sqlutils_queryids");
228                         delete il;
229                 }
230         }
231                         
232         virtual Version GetVersion()
233         {
234                 return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);
235         }
236         
237 };
238
239 MODULE_INIT(ModuleSQLutils)