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