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