]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules.cpp
Update m_cloaking to use free-form keys instead of weakening the hash IV
[user/henk/code/inspircd.git] / src / modules.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core */
15
16 #include "inspircd.h"
17 #include "xline.h"
18 #include "socket.h"
19 #include "socketengine.h"
20 #include "command_parse.h"
21 #include "dns.h"
22 #include "exitcodes.h"
23
24 #ifndef WIN32
25         #include <dirent.h>
26 #endif
27
28
29 // version is a simple class for holding a modules version number
30 template<>
31 VersionBase<API_VERSION>::VersionBase(const std::string &modv, int flags, int, const std::string& rev)
32 : description(modv), version(rev), Flags(flags)
33 {
34 }
35
36 Request::Request(Module* src, Module* dst, const char* idstr)
37 : id(idstr), source(src), dest(dst)
38 {
39 }
40
41 void Request::Send()
42 {
43         if (dest)
44                 dest->OnRequest(*this);
45 }
46
47 Event::Event(Module* src, const std::string &eventid) : source(src), id(eventid) { }
48
49 void Event::Send()
50 {
51         FOREACH_MOD(I_OnEvent,OnEvent(*this));
52 }
53
54 // These declarations define the behavours of the base class Module (which does nothing at all)
55
56 Module::Module() { }
57 bool Module::cull()
58 {
59         ServerInstance->GlobalCulls.AddItem(ModuleDLLFactory);
60         return true;
61 }
62 Module::~Module() { }
63
64 ModResult       Module::OnSendSnotice(char &snomask, std::string &type, const std::string &message) { return MOD_RES_PASSTHRU; }
65 void            Module::OnUserConnect(User*) { }
66 void            Module::OnUserQuit(User*, const std::string&, const std::string&) { }
67 void            Module::OnUserDisconnect(User*) { }
68 void            Module::OnUserJoin(Membership*, bool, bool, CUList&) { }
69 void            Module::OnPostJoin(Membership*) { }
70 void            Module::OnUserPart(Membership*, std::string&, CUList&) { }
71 void            Module::OnPreRehash(User*, const std::string&) { }
72 void            Module::OnModuleRehash(User*, const std::string&) { }
73 void            Module::OnRehash(User*) { }
74 ModResult       Module::OnUserPreJoin(User*, Channel*, const char*, std::string&, const std::string&) { return MOD_RES_PASSTHRU; }
75 void            Module::OnMode(User*, void*, int, const std::vector<std::string>&, const std::vector<TranslateType>&) { }
76 void            Module::OnOper(User*, const std::string&) { }
77 void            Module::OnPostOper(User*, const std::string&, const std::string &) { }
78 void            Module::OnInfo(User*) { }
79 void            Module::OnWhois(User*, User*) { }
80 ModResult       Module::OnUserPreInvite(User*, User*, Channel*, time_t) { return MOD_RES_PASSTHRU; }
81 ModResult       Module::OnUserPreMessage(User*, void*, int, std::string&, char, CUList&) { return MOD_RES_PASSTHRU; }
82 ModResult       Module::OnUserPreNotice(User*, void*, int, std::string&, char, CUList&) { return MOD_RES_PASSTHRU; }
83 ModResult       Module::OnUserPreNick(User*, const std::string&) { return MOD_RES_PASSTHRU; }
84 void            Module::OnUserPostNick(User*, const std::string&) { }
85 ModResult       Module::OnPreMode(User*, User*, Channel*, const std::vector<std::string>&) { return MOD_RES_PASSTHRU; }
86 void            Module::On005Numeric(std::string&) { }
87 ModResult       Module::OnKill(User*, User*, const std::string&) { return MOD_RES_PASSTHRU; }
88 void            Module::OnLoadModule(Module*, const std::string&) { }
89 void            Module::OnUnloadModule(Module*, const std::string&) { }
90 void            Module::OnBackgroundTimer(time_t) { }
91 ModResult       Module::OnPreCommand(std::string&, std::vector<std::string>&, User *, bool, const std::string&) { return MOD_RES_PASSTHRU; }
92 void            Module::OnPostCommand(const std::string&, const std::vector<std::string>&, User *, CmdResult, const std::string&) { }
93 ModResult       Module::OnCheckReady(User*) { return MOD_RES_PASSTHRU; }
94 ModResult       Module::OnUserRegister(User*) { return MOD_RES_PASSTHRU; }
95 ModResult       Module::OnUserPreKick(User*, Membership*, const std::string&) { return MOD_RES_PASSTHRU; }
96 void            Module::OnUserKick(User*, Membership*, const std::string&, CUList&) { }
97 ModResult       Module::OnRawMode(User*, Channel*, const char, const std::string &, bool, int) { return MOD_RES_PASSTHRU; }
98 ModResult       Module::OnCheckInvite(User*, Channel*) { return MOD_RES_PASSTHRU; }
99 ModResult       Module::OnCheckKey(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; }
100 ModResult       Module::OnCheckLimit(User*, Channel*) { return MOD_RES_PASSTHRU; }
101 ModResult       Module::OnCheckChannelBan(User*, Channel*) { return MOD_RES_PASSTHRU; }
102 ModResult       Module::OnCheckBan(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; }
103 ModResult       Module::OnExtBanCheck(User*, Channel*, char) { return MOD_RES_PASSTHRU; }
104 ModResult       Module::OnStats(char, User*, string_list&) { return MOD_RES_PASSTHRU; }
105 ModResult       Module::OnChangeLocalUserHost(User*, const std::string&) { return MOD_RES_PASSTHRU; }
106 ModResult       Module::OnChangeLocalUserGECOS(User*, const std::string&) { return MOD_RES_PASSTHRU; }
107 ModResult       Module::OnPreTopicChange(User*, Channel*, const std::string&) { return MOD_RES_PASSTHRU; }
108 void            Module::OnEvent(Event&) { }
109 void            Module::OnRequest(Request&) { }
110 ModResult       Module::OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype) { return MOD_RES_PASSTHRU; }
111 void            Module::OnGlobalOper(User*) { }
112 void            Module::OnPostConnect(User*) { }
113 ModResult       Module::OnAddBan(User*, Channel*, const std::string &) { return MOD_RES_PASSTHRU; }
114 ModResult       Module::OnDelBan(User*, Channel*, const std::string &) { return MOD_RES_PASSTHRU; }
115 void            Module::OnStreamSocketAccept(StreamSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { }
116 int             Module::OnStreamSocketWrite(StreamSocket*, std::string&) { return -1; }
117 void            Module::OnStreamSocketClose(StreamSocket*) { }
118 void            Module::OnStreamSocketConnect(StreamSocket*) { }
119 int             Module::OnStreamSocketRead(StreamSocket*, std::string&) { return -1; }
120 void            Module::OnUserMessage(User*, void*, int, const std::string&, char, const CUList&) { }
121 void            Module::OnUserNotice(User*, void*, int, const std::string&, char, const CUList&) { }
122 void            Module::OnRemoteKill(User*, User*, const std::string&, const std::string&) { }
123 void            Module::OnUserInvite(User*, User*, Channel*, time_t) { }
124 void            Module::OnPostTopicChange(User*, Channel*, const std::string&) { }
125 void            Module::OnGetServerDescription(const std::string&, std::string&) { }
126 void            Module::OnSyncUser(User*, Module*, void*) { }
127 void            Module::OnSyncChannel(Channel*, Module*, void*) { }
128 void            Module::OnSyncNetwork(Module*, void*) { }
129 void            Module::ProtoSendMode(void*, TargetTypeFlags, void*, const std::vector<std::string>&, const std::vector<TranslateType>&) { }
130 void            Module::OnDecodeMetaData(Extensible*, const std::string&, const std::string&) { }
131 void            Module::ProtoSendMetaData(void*, Extensible*, const std::string&, const std::string&) { }
132 void            Module::OnWallops(User*, const std::string&) { }
133 void            Module::OnChangeHost(User*, const std::string&) { }
134 void            Module::OnChangeName(User*, const std::string&) { }
135 void            Module::OnChangeIdent(User*, const std::string&) { }
136 void            Module::OnAddLine(User*, XLine*) { }
137 void            Module::OnDelLine(User*, XLine*) { }
138 void            Module::OnExpireLine(XLine*) { }
139 void            Module::OnCleanup(int, void*) { }
140 ModResult       Module::OnChannelPreDelete(Channel*) { return MOD_RES_PASSTHRU; }
141 void            Module::OnChannelDelete(Channel*) { }
142 ModResult       Module::OnSetAway(User*, const std::string &) { return MOD_RES_PASSTHRU; }
143 ModResult       Module::OnUserList(User*, Channel*) { return MOD_RES_PASSTHRU; }
144 ModResult       Module::OnWhoisLine(User*, User*, int&, std::string&) { return MOD_RES_PASSTHRU; }
145 void            Module::OnBuildNeighborList(User*, UserChanList&, std::map<User*,bool>&) { }
146 void            Module::OnGarbageCollect() { }
147 void            Module::OnText(User*, void*, int, const std::string&, char, CUList&) { }
148 void            Module::OnRunTestSuite() { }
149 void            Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) { }
150 ModResult       Module::OnNumeric(User*, unsigned int, const std::string&) { return MOD_RES_PASSTHRU; }
151 void            Module::OnHookIO(StreamSocket*, ListenSocketBase*) { }
152 void            Module::OnSendWhoLine(User*, User*, Channel*, std::string&) { }
153
154 ModuleManager::ModuleManager() : ModCount(0)
155 {
156 }
157
158 ModuleManager::~ModuleManager()
159 {
160 }
161
162 bool ModuleManager::Attach(Implementation i, Module* mod)
163 {
164         if (std::find(EventHandlers[i].begin(), EventHandlers[i].end(), mod) != EventHandlers[i].end())
165                 return false;
166
167         EventHandlers[i].push_back(mod);
168         return true;
169 }
170
171 bool ModuleManager::Detach(Implementation i, Module* mod)
172 {
173         EventHandlerIter x = std::find(EventHandlers[i].begin(), EventHandlers[i].end(), mod);
174
175         if (x == EventHandlers[i].end())
176                 return false;
177
178         EventHandlers[i].erase(x);
179         return true;
180 }
181
182 void ModuleManager::Attach(Implementation* i, Module* mod, size_t sz)
183 {
184         for (size_t n = 0; n < sz; ++n)
185                 Attach(i[n], mod);
186 }
187
188 void ModuleManager::DetachAll(Module* mod)
189 {
190         for (size_t n = I_BEGIN + 1; n != I_END; ++n)
191                 Detach((Implementation)n, mod);
192 }
193
194 bool ModuleManager::SetPriority(Module* mod, Priority s)
195 {
196         for (size_t n = I_BEGIN + 1; n != I_END; ++n)
197                 SetPriority(mod, (Implementation)n, s);
198
199         return true;
200 }
201
202 bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Module** modules, size_t sz)
203 {
204         /** To change the priority of a module, we first find its position in the vector,
205          * then we find the position of the other modules in the vector that this module
206          * wants to be before/after. We pick off either the first or last of these depending
207          * on which they want, and we make sure our module is *at least* before or after
208          * the first or last of this subset, depending again on the type of priority.
209          */
210         size_t swap_pos = 0;
211         size_t source = 0;
212         bool swap = true;
213         bool found = false;
214
215         /* Locate our module. This is O(n) but it only occurs on module load so we're
216          * not too bothered about it
217          */
218         for (size_t x = 0; x != EventHandlers[i].size(); ++x)
219         {
220                 if (EventHandlers[i][x] == mod)
221                 {
222                         source = x;
223                         found = true;
224                         break;
225                 }
226         }
227
228         /* Eh? this module doesnt exist, probably trying to set priority on an event
229          * theyre not attached to.
230          */
231         if (!found)
232                 return false;
233
234         switch (s)
235         {
236                 /* Dummy value */
237                 case PRIORITY_DONTCARE:
238                         swap = false;
239                 break;
240                 /* Module wants to be first, sod everything else */
241                 case PRIORITY_FIRST:
242                         if (prioritizationState != PRIO_STATE_FIRST)
243                                 swap = false;
244                         else
245                                 swap_pos = 0;
246                 break;
247                 /* Module wants to be last. */
248                 case PRIORITY_LAST:
249                         if (prioritizationState != PRIO_STATE_FIRST)
250                                 swap = false;
251                         else if (EventHandlers[i].empty())
252                                 swap_pos = 0;
253                         else
254                                 swap_pos = EventHandlers[i].size() - 1;
255                 break;
256                 /* Place this module after a set of other modules */
257                 case PRIORITY_AFTER:
258                 {
259                         /* Find the latest possible position */
260                         swap_pos = 0;
261                         swap = false;
262                         for (size_t x = 0; x != EventHandlers[i].size(); ++x)
263                         {
264                                 for (size_t n = 0; n < sz; ++n)
265                                 {
266                                         if ((modules[n]) && (EventHandlers[i][x] == modules[n]) && (x >= swap_pos) && (source <= swap_pos))
267                                         {
268                                                 swap_pos = x;
269                                                 swap = true;
270                                         }
271                                 }
272                         }
273                 }
274                 break;
275                 /* Place this module before a set of other modules */
276                 case PRIORITY_BEFORE:
277                 {
278                         swap_pos = EventHandlers[i].size() - 1;
279                         swap = false;
280                         for (size_t x = 0; x != EventHandlers[i].size(); ++x)
281                         {
282                                 for (size_t n = 0; n < sz; ++n)
283                                 {
284                                         if ((modules[n]) && (EventHandlers[i][x] == modules[n]) && (x <= swap_pos) && (source >= swap_pos))
285                                         {
286                                                 swap = true;
287                                                 swap_pos = x;
288                                         }
289                                 }
290                         }
291                 }
292                 break;
293         }
294
295         /* Do we need to swap? */
296         if (swap && (swap_pos != source))
297         {
298                 // We are going to change positions; we'll need to run again to verify all requirements
299                 if (prioritizationState == PRIO_STATE_LAST)
300                         prioritizationState = PRIO_STATE_AGAIN;
301                 /* Suggestion from Phoenix, "shuffle" the modules to better retain call order */
302                 int incrmnt = 1;
303
304                 if (source > swap_pos)
305                         incrmnt = -1;
306
307                 for (unsigned int j = source; j != swap_pos; j += incrmnt)
308                 {
309                         if (( j + incrmnt > EventHandlers[i].size() - 1) || (j + incrmnt < 0))
310                                 continue;
311
312                         std::swap(EventHandlers[i][j], EventHandlers[i][j+incrmnt]);
313                 }
314         }
315
316         return true;
317 }
318
319 std::string& ModuleManager::LastError()
320 {
321         return LastModuleError;
322 }
323
324 bool ModuleManager::Load(const char* filename)
325 {
326         /* Do we have a glob pattern in the filename?
327          * The user wants to load multiple modules which
328          * match the pattern.
329          */
330         if (strchr(filename,'*') || (strchr(filename,'?')))
331         {
332                 int n_match = 0;
333                 DIR* library = opendir(ServerInstance->Config->ModPath.c_str());
334                 if (library)
335                 {
336                         /* Try and locate and load all modules matching the pattern */
337                         dirent* entry = NULL;
338                         while (0 != (entry = readdir(library)))
339                         {
340                                 if (InspIRCd::Match(entry->d_name, filename, ascii_case_insensitive_map))
341                                 {
342                                         if (!this->Load(entry->d_name))
343                                                 n_match++;
344                                 }
345                         }
346                         closedir(library);
347                 }
348                 /* Loadmodule will now return false if any one of the modules failed
349                  * to load (but wont abort when it encounters a bad one) and when 1 or
350                  * more modules were actually loaded.
351                  */
352                 return (n_match > 0 ? false : true);
353         }
354
355         char modfile[MAXBUF];
356         snprintf(modfile,MAXBUF,"%s/%s",ServerInstance->Config->ModPath.c_str(),filename);
357         std::string filename_str = filename;
358
359         if (!ServerConfig::FileExists(modfile))
360         {
361                 LastModuleError = "Module file could not be found: " + filename_str;
362                 ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
363                 return false;
364         }
365
366         if (Modules.find(filename_str) != Modules.end())
367         {
368                 LastModuleError = "Module " + filename_str + " is already loaded, cannot load a module twice!";
369                 ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
370                 return false;
371         }
372
373         Module* newmod = NULL;
374         DLLFactory* newhandle = NULL;
375
376         try
377         {
378                 /* This will throw a CoreException if there's a problem loading
379                  * the module file or getting a pointer to the init_module symbol.
380                  */
381                 newhandle = new DLLFactory(modfile, "init_module");
382                 if (newhandle->init_func)
383                         newmod = newhandle->init_func();
384
385                 if (newmod)
386                 {
387                         newmod->ModuleSourceFile = filename_str;
388                         newmod->ModuleDLLFactory = newhandle;
389                         Version v = newmod->GetVersion();
390
391                         ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s (Module version %s)%s", filename, v.version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]"));
392
393                         Modules[filename_str] = newmod;
394                 }
395                 else
396                 {
397                         delete newhandle;
398                         LastModuleError = "Unable to load " + filename_str + ": Probably missing init_module() entrypoint, but dlsym() didn't notice a problem";
399                         ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
400                         return false;
401                 }
402         }
403         /** XXX: Is there anything we can do about this mess? -- Brain
404          * Yeah, don't use exceptions without RAII. -- Daniel
405          */
406         catch (LoadModuleException& modexcept)
407         {
408                 DetachAll(newmod);
409                 if (newmod)
410                         delete newmod;
411                 if (newhandle)
412                         delete newhandle;
413                 LastModuleError = "Unable to load " + filename_str + ": Error when loading: " + modexcept.GetReason();
414                 ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
415                 return false;
416         }
417         catch (FindSymbolException& modexcept)
418         {
419                 DetachAll(newmod);
420                 if (newmod)
421                         delete newmod;
422                 if (newhandle)
423                         delete newhandle;
424                 LastModuleError = "Unable to load " + filename_str + ": Error finding symbol: " + modexcept.GetReason();
425                 ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
426                 return false;
427         }
428         catch (CoreException& modexcept)
429         {
430                 DetachAll(newmod);
431                 if (newmod)
432                         delete newmod;
433                 if (newhandle)
434                         delete newhandle;
435                 LastModuleError = "Unable to load " + filename_str + ": " + modexcept.GetReason();
436                 ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
437                 return false;
438         }
439
440         this->ModCount++;
441         FOREACH_MOD(I_OnLoadModule,OnLoadModule(newmod, filename_str));
442
443         /* We give every module a chance to re-prioritize when we introduce a new one,
444          * not just the one thats loading, as the new module could affect the preference
445          * of others
446          */
447         for(int tries = 0; tries < 20; tries++)
448         {
449                 prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
450                 for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
451                         n->second->Prioritize();
452
453                 if (prioritizationState == PRIO_STATE_LAST)
454                         break;
455                 if (tries == 19)
456                         ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + filename_str);
457         }
458
459         ServerInstance->BuildISupport();
460         return true;
461 }
462
463 bool ModuleManager::Unload(const char* filename)
464 {
465         std::string filename_str(filename);
466         std::map<std::string, Module*>::iterator modfind = Modules.find(filename);
467
468         if (modfind != Modules.end())
469         {
470                 if (modfind->second->GetVersion().Flags & VF_STATIC)
471                 {
472                         LastModuleError = "Module " + filename_str + " not unloadable (marked static)";
473                         ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
474                         return false;
475                 }
476                 std::pair<int,std::string> intercount = GetInterfaceInstanceCount(modfind->second);
477                 if (intercount.first > 0)
478                 {
479                         LastModuleError = "Failed to unload module " + filename_str + ", being used by " + ConvToStr(intercount.first) + " other(s) via interface '" + intercount.second + "'";
480                         ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
481                         return false;
482                 }
483
484                 std::vector<ExtensionItem*> items = Extensible::BeginUnregister(modfind->second);
485                 /* Give the module a chance to tidy out all its metadata */
486                 for (chan_hash::iterator c = ServerInstance->chanlist->begin(); c != ServerInstance->chanlist->end(); c++)
487                 {
488                         modfind->second->OnCleanup(TYPE_CHANNEL,c->second);
489                         c->second->doUnhookExtensions(items);
490                         const UserMembList* users = c->second->GetUsers();
491                         for(UserMembCIter mi = users->begin(); mi != users->end(); mi++)
492                                 mi->second->doUnhookExtensions(items);
493                 }
494                 for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++)
495                 {
496                         modfind->second->OnCleanup(TYPE_USER,u->second);
497                         u->second->doUnhookExtensions(items);
498                 }
499
500                 /* Tidy up any dangling resolvers */
501                 ServerInstance->Res->CleanResolvers(modfind->second);
502
503                 FOREACH_MOD(I_OnUnloadModule,OnUnloadModule(modfind->second, modfind->first));
504
505                 this->DetachAll(modfind->second);
506
507                 ServerInstance->Parser->RemoveCommands(modfind->second);
508                 ServerInstance->Modes->RemoveModes(modfind->second);
509
510                 ServerInstance->GlobalCulls.AddItem(modfind->second);
511                 Modules.erase(modfind);
512
513                 ServerInstance->Logs->Log("MODULE", DEFAULT,"Module %s unloaded",filename);
514                 this->ModCount--;
515                 ServerInstance->BuildISupport();
516                 return true;
517         }
518
519         LastModuleError = "Module " + filename_str + " is not loaded, cannot unload it!";
520         ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
521         return false;
522 }
523
524 /* We must load the modules AFTER initializing the socket engine, now */
525 void ModuleManager::LoadAll()
526 {
527         char configToken[MAXBUF];
528         ModCount = -1;
529
530         printf("\nLoading core commands");
531         fflush(stdout);
532
533         DIR* library = opendir(ServerInstance->Config->ModPath.c_str());
534         if (library)
535         {
536                 dirent* entry = NULL;
537                 while (0 != (entry = readdir(library)))
538                 {
539                         if (InspIRCd::Match(entry->d_name, "cmd_*.so", ascii_case_insensitive_map))
540                         {
541                                 printf(".");
542                                 fflush(stdout);
543
544                                 if (!Load(entry->d_name))
545                                 {
546                                         ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError());
547                                         printf_c("\n[\033[1;31m*\033[0m] %s\n\n", this->LastError().c_str());
548                                         ServerInstance->Exit(EXIT_STATUS_MODULE);
549                                 }
550                         }
551                 }
552                 closedir(library);
553                 printf("\n");
554         }
555
556         for(int count = 0; count < ServerInstance->Config->ConfValueEnum("module"); count++)
557         {
558                 ServerInstance->Config->ConfValue("module", "name", count, configToken, MAXBUF);
559                 printf_c("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken);
560
561                 if (!this->Load(configToken))
562                 {
563                         ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError());
564                         printf_c("\n[\033[1;31m*\033[0m] %s\n\n", this->LastError().c_str());
565                         ServerInstance->Exit(EXIT_STATUS_MODULE);
566                 }
567         }
568 }
569
570 bool ModuleManager::PublishFeature(const std::string &FeatureName, Module* Mod)
571 {
572         if (Features.find(FeatureName) == Features.end())
573         {
574                 Features[FeatureName] = Mod;
575                 return true;
576         }
577         return false;
578 }
579
580 bool ModuleManager::UnpublishFeature(const std::string &FeatureName)
581 {
582         featurelist::iterator iter = Features.find(FeatureName);
583
584         if (iter == Features.end())
585                 return false;
586
587         Features.erase(iter);
588         return true;
589 }
590
591 Module* ModuleManager::FindFeature(const std::string &FeatureName)
592 {
593         featurelist::iterator iter = Features.find(FeatureName);
594
595         if (iter == Features.end())
596                 return NULL;
597
598         return iter->second;
599 }
600
601 bool ModuleManager::PublishInterface(const std::string &InterfaceName, Module* Mod)
602 {
603         interfacelist::iterator iter = Interfaces.find(InterfaceName);
604
605         if (iter == Interfaces.end())
606         {
607                 modulelist ml;
608                 ml.push_back(Mod);
609                 Interfaces[InterfaceName] = std::make_pair(0, ml);
610         }
611         else
612         {
613                 iter->second.second.push_back(Mod);
614         }
615         return true;
616 }
617
618 bool ModuleManager::UnpublishInterface(const std::string &InterfaceName, Module* Mod)
619 {
620         interfacelist::iterator iter = Interfaces.find(InterfaceName);
621
622         if (iter == Interfaces.end())
623                 return false;
624
625         for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
626         {
627                 if (*x == Mod)
628                 {
629                         iter->second.second.erase(x);
630                         if (iter->second.second.empty())
631                                 Interfaces.erase(InterfaceName);
632                         return true;
633                 }
634         }
635         return false;
636 }
637
638 modulelist* ModuleManager::FindInterface(const std::string &InterfaceName)
639 {
640         interfacelist::iterator iter = Interfaces.find(InterfaceName);
641         if (iter == Interfaces.end())
642                 return NULL;
643         else
644                 return &(iter->second.second);
645 }
646
647 bool ModuleManager::ModuleHasInterface(Module* mod, const std::string& InterfaceName)
648 {
649         interfacelist::iterator iter = Interfaces.find(InterfaceName);
650         if (iter == Interfaces.end())
651                 return false;
652         else
653         {
654                 modulelist& ml = iter->second.second;
655                 modulelist::iterator mi = std::find(ml.begin(), ml.end(), mod);
656                 return (mi != ml.end());
657         }
658 }
659
660 void ModuleManager::UseInterface(const std::string &InterfaceName)
661 {
662         interfacelist::iterator iter = Interfaces.find(InterfaceName);
663         if (iter != Interfaces.end())
664                 iter->second.first++;
665
666 }
667
668 void ModuleManager::DoneWithInterface(const std::string &InterfaceName)
669 {
670         interfacelist::iterator iter = Interfaces.find(InterfaceName);
671         if (iter != Interfaces.end())
672                 iter->second.first--;
673 }
674
675 std::pair<int,std::string> ModuleManager::GetInterfaceInstanceCount(Module* m)
676 {
677         for (interfacelist::iterator iter = Interfaces.begin(); iter != Interfaces.end(); iter++)
678         {
679                 for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
680                 {
681                         if (*x == m)
682                         {
683                                 return std::make_pair(iter->second.first, iter->first);
684                         }
685                 }
686         }
687         return std::make_pair(0, "");
688 }
689
690 const std::string& ModuleManager::GetModuleName(Module* m)
691 {
692         static std::string nothing;
693
694         for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
695         {
696                 if (n->second == m)
697                         return n->first;
698         }
699
700         return nothing;
701 }
702
703 /* This is ugly, yes, but hash_map's arent designed to be
704  * addressed in this manner, and this is a bit of a kludge.
705  * Luckily its a specialist function and rarely used by
706  * many modules (in fact, it was specially created to make
707  * m_safelist possible, initially).
708  */
709
710 Channel* InspIRCd::GetChannelIndex(long index)
711 {
712         int target = 0;
713         for (chan_hash::iterator n = this->chanlist->begin(); n != this->chanlist->end(); n++, target++)
714         {
715                 if (index == target)
716                         return n->second;
717         }
718         return NULL;
719 }
720
721 CmdResult InspIRCd::CallCommandHandler(const std::string &commandname, const std::vector<std::string>& parameters, User* user)
722 {
723         return this->Parser->CallHandler(commandname, parameters, user);
724 }
725
726 bool InspIRCd::IsValidModuleCommand(const std::string &commandname, int pcnt, User* user)
727 {
728         return this->Parser->IsValidCommand(commandname, pcnt, user);
729 }
730
731 void InspIRCd::AddCommand(Command *f)
732 {
733         if (!this->Parser->CreateCommand(f))
734         {
735                 ModuleException err("Command "+std::string(f->command)+" already exists.");
736                 throw (err);
737         }
738 }
739
740 void InspIRCd::SendMode(const std::vector<std::string>& parameters, User *user)
741 {
742         this->Modes->Process(parameters, user);
743 }
744
745 void InspIRCd::DumpText(User* user, const std::string &text)
746 {
747         if (IS_LOCAL(user))
748         {
749                 user->Write(text);
750         }
751         else
752         {
753                 PI->PushToClient(user, text);
754         }
755 }
756
757 void InspIRCd::DumpText(User* user, const char *text, ...)
758 {
759         va_list argsPtr;
760         char line[MAXBUF];
761
762         va_start(argsPtr, text);
763         vsnprintf(line, MAXBUF, text, argsPtr);
764         va_end(argsPtr);
765
766         DumpText(user, std::string(line));
767 }
768
769 void InspIRCd::DumpText(User* user, const std::string &LinePrefix, std::stringstream &TextStream)
770 {
771         char line[MAXBUF];
772         int start_pos = LinePrefix.length();
773         int pos = start_pos;
774         memcpy(line, LinePrefix.data(), pos);
775         std::string Word;
776         while (TextStream >> Word)
777         {
778                 int len = Word.length();
779                 if (pos + len + 12 > MAXBUF)
780                 {
781                         line[pos] = '\0';
782                         DumpText(user, std::string(line));
783                         pos = start_pos;
784                 }
785                 line[pos] = ' ';
786                 memcpy(line + pos + 1, Word.data(), len);
787                 pos += len + 1;
788         }
789         line[pos] = '\0';
790         DumpText(user, std::string(line));
791 }
792
793 bool InspIRCd::AddResolver(Resolver* r, bool cached)
794 {
795         if (!cached)
796                 return this->Res->AddResolverClass(r);
797         else
798         {
799                 r->TriggerCachedResult();
800                 delete r;
801                 return true;
802         }
803 }
804
805 Module* ModuleManager::Find(const std::string &name)
806 {
807         std::map<std::string, Module*>::iterator modfind = Modules.find(name);
808
809         if (modfind == Modules.end())
810                 return NULL;
811         else
812                 return modfind->second;
813 }
814
815 const std::vector<std::string> ModuleManager::GetAllModuleNames(int filter)
816 {
817         std::vector<std::string> retval;
818         for (std::map<std::string, Module*>::iterator x = Modules.begin(); x != Modules.end(); ++x)
819                 if (!filter || (x->second->GetVersion().Flags & filter))
820                         retval.push_back(x->first);
821         return retval;
822 }
823
824 ConfigReader::ConfigReader()
825 {
826         this->error = 0;
827 }
828
829
830 ConfigReader::~ConfigReader()
831 {
832 }
833
834
835 std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds)
836 {
837         /* Don't need to strlcpy() tag and name anymore, ReadConf() takes const char* */
838         std::string result;
839
840         if (!ServerInstance->Config->ConfValue(tag, name, default_value, index, result, allow_linefeeds))
841         {
842                 this->error = CONF_VALUE_NOT_FOUND;
843         }
844         return result;
845 }
846
847 std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds)
848 {
849         return ReadValue(tag, name, "", index, allow_linefeeds);
850 }
851
852 bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index)
853 {
854         return ServerInstance->Config->ConfValueBool(tag, name, default_value, index);
855 }
856
857 bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, int index)
858 {
859         return ReadFlag(tag, name, "", index);
860 }
861
862
863 int ConfigReader::ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool need_positive)
864 {
865         int result;
866
867         if(!ServerInstance->Config->ConfValueInteger(tag, name, default_value, index, result))
868         {
869                 this->error = CONF_VALUE_NOT_FOUND;
870                 return 0;
871         }
872
873         if ((need_positive) && (result < 0))
874         {
875                 this->error = CONF_INT_NEGATIVE;
876                 return 0;
877         }
878
879         return result;
880 }
881
882 int ConfigReader::ReadInteger(const std::string &tag, const std::string &name, int index, bool need_positive)
883 {
884         return ReadInteger(tag, name, "", index, need_positive);
885 }
886
887 long ConfigReader::GetError()
888 {
889         long olderr = this->error;
890         this->error = 0;
891         return olderr;
892 }
893
894 int ConfigReader::Enumerate(const std::string &tag)
895 {
896         return ServerInstance->Config->ConfValueEnum(tag);
897 }
898
899 int ConfigReader::EnumerateValues(const std::string &tag, int index)
900 {
901         return ServerInstance->Config->ConfVarEnum(tag, index);
902 }
903
904 FileReader::FileReader(const std::string &filename)
905 {
906         LoadFile(filename);
907 }
908
909 FileReader::FileReader()
910 {
911 }
912
913 std::string FileReader::Contents()
914 {
915         std::string x;
916         for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)
917         {
918                 x.append(*a);
919                 x.append("\r\n");
920         }
921         return x;
922 }
923
924 unsigned long FileReader::ContentSize()
925 {
926         return this->contentsize;
927 }
928
929 void FileReader::CalcSize()
930 {
931         unsigned long n = 0;
932         for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)
933                 n += (a->length() + 2);
934         this->contentsize = n;
935 }
936
937 void FileReader::LoadFile(const std::string &filename)
938 {
939         file_cache c;
940         c.clear();
941         if (ServerInstance->Config->ReadFile(c,filename.c_str()))
942         {
943                 this->fc = c;
944                 this->CalcSize();
945         }
946 }
947
948
949 FileReader::~FileReader()
950 {
951 }
952
953 bool FileReader::Exists()
954 {
955         return (!(fc.size() == 0));
956 }
957
958 std::string FileReader::GetLine(int x)
959 {
960         if ((x<0) || ((unsigned)x>fc.size()))
961                 return "";
962         return fc[x];
963 }
964
965 int FileReader::FileSize()
966 {
967         return fc.size();
968 }