]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules.cpp
MetaData rework
[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 &sversion, int flags, int api_ver)
31 : version(sversion), 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(InspIRCd* ServerInstance)
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(InspIRCd* Me) : ServerInstance(Me) { }
108 Module::~Module() { }
109
110 int             Module::OnSendSnotice(char &snomask, std::string &type, const std::string &message) { return 0; }
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(User*, Channel*, bool, bool&, bool) { }
115 void            Module::OnPostJoin(User*, Channel*) { }
116 void            Module::OnUserPart(User*, Channel*, std::string&, bool&) { }
117 void            Module::OnPreRehash(User*, const std::string&) { }
118 void            Module::OnModuleRehash(User*, const std::string&) { }
119 void            Module::OnRehash(User*) { }
120 int             Module::OnUserPreJoin(User*, Channel*, const char*, std::string&, const std::string&) { return 0; }
121 void            Module::OnMode(User*, void*, int, const std::vector<std::string>&, const std::vector<TranslateType>&) { }
122 Version         Module::GetVersion() { return Version("Misconfigured", VF_VENDOR, -1); }
123 void            Module::OnOper(User*, const std::string&) { }
124 void            Module::OnPostOper(User*, const std::string&, const std::string &) { }
125 void            Module::OnInfo(User*) { }
126 void            Module::OnWhois(User*, User*) { }
127 int             Module::OnUserPreInvite(User*, User*, Channel*, time_t) { return 0; }
128 int             Module::OnUserPreMessage(User*, void*, int, std::string&, char, CUList&) { return 0; }
129 int             Module::OnUserPreNotice(User*, void*, int, std::string&, char, CUList&) { return 0; }
130 int             Module::OnUserPreNick(User*, const std::string&) { return 0; }
131 void            Module::OnUserPostNick(User*, const std::string&) { }
132 int             Module::OnAccessCheck(User*, User*, Channel*, int) { return ACR_DEFAULT; }
133 void            Module::On005Numeric(std::string&) { }
134 int             Module::OnKill(User*, User*, const std::string&) { return 0; }
135 void            Module::OnLoadModule(Module*, const std::string&) { }
136 void            Module::OnUnloadModule(Module*, const std::string&) { }
137 void            Module::OnBackgroundTimer(time_t) { }
138 int             Module::OnPreCommand(std::string&, std::vector<std::string>&, User *, bool, const std::string&) { return 0; }
139 void            Module::OnPostCommand(const std::string&, const std::vector<std::string>&, User *, CmdResult, const std::string&) { }
140 bool            Module::OnCheckReady(User*) { return true; }
141 int             Module::OnUserRegister(User*) { return 0; }
142 int             Module::OnUserPreKick(User*, User*, Channel*, const std::string&) { return 0; }
143 void            Module::OnUserKick(User*, User*, Channel*, const std::string&, bool&) { }
144 int             Module::OnRawMode(User*, Channel*, const char, const std::string &, bool, int, bool) { return 0; }
145 int             Module::OnCheckInvite(User*, Channel*) { return 0; }
146 int             Module::OnCheckKey(User*, Channel*, const std::string&) { return 0; }
147 int             Module::OnCheckLimit(User*, Channel*) { return 0; }
148 int             Module::OnCheckBan(User*, Channel*) { return 0; }
149 int             Module::OnCheckExtBan(User *, Channel *, char) { return 0; }
150 int             Module::OnCheckStringExtBan(const std::string &s, Channel *c, char type) { return 0; }
151 int             Module::OnStats(char, User*, string_list&) { return 0; }
152 int             Module::OnChangeLocalUserHost(User*, const std::string&) { return 0; }
153 int             Module::OnChangeLocalUserGECOS(User*, const std::string&) { return 0; }
154 int             Module::OnLocalTopicChange(User*, Channel*, const std::string&) { return 0; }
155 void            Module::OnEvent(Event*) { return; }
156 const char*             Module::OnRequest(Request*) { return NULL; }
157 int             Module::OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype) { return 0; }
158 void            Module::OnGlobalOper(User*) { }
159 void            Module::OnPostConnect(User*) { }
160 int             Module::OnAddBan(User*, Channel*, const std::string &) { return 0; }
161 int             Module::OnDelBan(User*, Channel*, const std::string &) { return 0; }
162 void            Module::OnRawSocketAccept(int, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { }
163 int             Module::OnRawSocketWrite(int, const char*, int) { return 0; }
164 void            Module::OnRawSocketClose(int) { }
165 void            Module::OnRawSocketConnect(int) { }
166 int             Module::OnRawSocketRead(int, char*, unsigned int, int&) { return 0; }
167 void            Module::OnUserMessage(User*, void*, int, const std::string&, char, const CUList&) { }
168 void            Module::OnUserNotice(User*, void*, int, const std::string&, char, const CUList&) { }
169 void            Module::OnRemoteKill(User*, User*, const std::string&, const std::string&) { }
170 void            Module::OnUserInvite(User*, User*, Channel*, time_t) { }
171 void            Module::OnPostLocalTopicChange(User*, Channel*, const std::string&) { }
172 void            Module::OnGetServerDescription(const std::string&, std::string&) { }
173 void            Module::OnSyncUser(User*, Module*, void*) { }
174 void            Module::OnSyncChannel(Channel*, Module*, void*) { }
175 void            Module::OnSyncNetwork(Module*, void*) { }
176 void            Module::ProtoSendMode(void*, TargetTypeFlags, void*, const std::vector<std::string>&, const std::vector<TranslateType>&) { }
177 void            Module::OnDecodeMetaData(Extensible*, const std::string&, const std::string&) { }
178 void            Module::ProtoSendMetaData(void*, Extensible*, const std::string&, const std::string&) { }
179 std::string     Module::ProtoTranslate(Extensible*) { return "?"; }
180 void            Module::OnWallops(User*, const std::string&) { }
181 void            Module::OnChangeHost(User*, const std::string&) { }
182 void            Module::OnChangeName(User*, const std::string&) { }
183 void            Module::OnAddLine(User*, XLine*) { }
184 void            Module::OnDelLine(User*, XLine*) { }
185 void            Module::OnExpireLine(XLine*) { }
186 void            Module::OnCleanup(int, void*) { }
187 int             Module::OnChannelPreDelete(Channel*) { return 0; }
188 void            Module::OnChannelDelete(Channel*) { }
189 int             Module::OnSetAway(User*, const std::string &) { return 0; }
190 int             Module::OnUserList(User*, Channel*, CUList*&) { return 0; }
191 int             Module::OnWhoisLine(User*, User*, int&, std::string&) { return 0; }
192 void            Module::OnBuildExemptList(MessageType, Channel*, User*, char, CUList&, const std::string&) { }
193 void            Module::OnGarbageCollect() { }
194 void            Module::OnBufferFlushed(User*) { }
195 void            Module::OnText(User*, void*, int, const std::string&, char, CUList&) { }
196 void            Module::OnRunTestSuite() { }
197 void            Module::OnNamesListItem(User*, User*, Channel*, std::string&, std::string&) { }
198 int             Module::OnNumeric(User*, unsigned int, const std::string&) { return 0; }
199 void            Module::OnHookUserIO(User*) { }
200 bool            Module::OnHostCycle(User* user) { return false; }
201
202 ModuleManager::ModuleManager(InspIRCd* Ins) : ModCount(0), Instance(Ins)
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(Instance->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",Instance->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                 Instance->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                 Instance->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(Instance, modfile, "init_module");
430                 newmod = newhandle->CallInit();
431
432                 if (newmod)
433                 {
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                                 Instance->Logs->Log("MODULE", DEFAULT, LastModuleError);
443                                 return false;
444                         }
445                         else
446                         {
447                                 Instance->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                         Instance->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                 Instance->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                 Instance->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                 Instance->Logs->Log("MODULE", DEFAULT, LastModuleError);
492                 return false;
493         }
494
495         this->ModCount++;
496         FOREACH_MOD_I(Instance,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                         Instance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + filename_str);
512         }
513
514         Instance->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                         Instance->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                         Instance->Logs->Log("MODULE", DEFAULT, LastModuleError);
536                         return false;
537                 }
538
539                 /* Give the module a chance to tidy out all its metadata */
540                 for (chan_hash::iterator c = Instance->chanlist->begin(); c != Instance->chanlist->end(); c++)
541                 {
542                         modfind->second.second->OnCleanup(TYPE_CHANNEL,c->second);
543                 }
544                 for (user_hash::iterator u = Instance->Users->clientlist->begin(); u != Instance->Users->clientlist->end(); u++)
545                 {
546                         modfind->second.second->OnCleanup(TYPE_USER,u->second);
547                 }
548
549                 /* Tidy up any dangling resolvers */
550                 Instance->Res->CleanResolvers(modfind->second.second);
551
552
553                 FOREACH_MOD_I(Instance,I_OnUnloadModule,OnUnloadModule(modfind->second.second, modfind->first));
554
555                 this->DetachAll(modfind->second.second);
556
557                 Instance->Parser->RemoveCommands(filename);
558
559                 delete modfind->second.second;
560                 delete modfind->second.first;
561                 Modules.erase(modfind);
562
563                 Instance->Logs->Log("MODULE", DEFAULT,"Module %s unloaded",filename);
564                 this->ModCount--;
565                 Instance->BuildISupport();
566                 return true;
567         }
568
569         LastModuleError = "Module " + filename_str + " is not loaded, cannot unload it!";
570         Instance->Logs->Log("MODULE", DEFAULT, LastModuleError);
571         return false;
572 }
573
574 /* We must load the modules AFTER initializing the socket engine, now */
575 void ModuleManager::LoadAll()
576 {
577         char configToken[MAXBUF];
578         ModCount = -1;
579
580         for(int count = 0; count < Instance->Config->ConfValueEnum("module"); count++)
581         {
582                 Instance->Config->ConfValue("module", "name", count, configToken, MAXBUF);
583                 printf_c("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken);
584
585                 if (!this->Load(configToken))
586                 {
587                         Instance->Logs->Log("MODULE", DEFAULT, this->LastError());
588                         printf_c("\n[\033[1;31m*\033[0m] %s\n\n", this->LastError().c_str());
589                         Instance->Exit(EXIT_STATUS_MODULE);
590                 }
591         }
592 }
593
594 bool ModuleManager::PublishFeature(const std::string &FeatureName, Module* Mod)
595 {
596         if (Features.find(FeatureName) == Features.end())
597         {
598                 Features[FeatureName] = Mod;
599                 return true;
600         }
601         return false;
602 }
603
604 bool ModuleManager::UnpublishFeature(const std::string &FeatureName)
605 {
606         featurelist::iterator iter = Features.find(FeatureName);
607
608         if (iter == Features.end())
609                 return false;
610
611         Features.erase(iter);
612         return true;
613 }
614
615 Module* ModuleManager::FindFeature(const std::string &FeatureName)
616 {
617         featurelist::iterator iter = Features.find(FeatureName);
618
619         if (iter == Features.end())
620                 return NULL;
621
622         return iter->second;
623 }
624
625 bool ModuleManager::PublishInterface(const std::string &InterfaceName, Module* Mod)
626 {
627         interfacelist::iterator iter = Interfaces.find(InterfaceName);
628
629         if (iter == Interfaces.end())
630         {
631                 modulelist ml;
632                 ml.push_back(Mod);
633                 Interfaces[InterfaceName] = std::make_pair(0, ml);
634         }
635         else
636         {
637                 iter->second.second.push_back(Mod);
638         }
639         return true;
640 }
641
642 bool ModuleManager::UnpublishInterface(const std::string &InterfaceName, Module* Mod)
643 {
644         interfacelist::iterator iter = Interfaces.find(InterfaceName);
645
646         if (iter == Interfaces.end())
647                 return false;
648
649         for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
650         {
651                 if (*x == Mod)
652                 {
653                         iter->second.second.erase(x);
654                         if (iter->second.second.empty())
655                                 Interfaces.erase(InterfaceName);
656                         return true;
657                 }
658         }
659         return false;
660 }
661
662 modulelist* ModuleManager::FindInterface(const std::string &InterfaceName)
663 {
664         interfacelist::iterator iter = Interfaces.find(InterfaceName);
665         if (iter == Interfaces.end())
666                 return NULL;
667         else
668                 return &(iter->second.second);
669 }
670
671 bool ModuleManager::ModuleHasInterface(Module* mod, const std::string& InterfaceName)
672 {
673         interfacelist::iterator iter = Interfaces.find(InterfaceName);
674         if (iter == Interfaces.end())
675                 return false;
676         else
677         {
678                 modulelist& ml = iter->second.second;
679                 modulelist::iterator mi = std::find(ml.begin(), ml.end(), mod);
680                 return (mi != ml.end());
681         }
682 }
683
684 void ModuleManager::UseInterface(const std::string &InterfaceName)
685 {
686         interfacelist::iterator iter = Interfaces.find(InterfaceName);
687         if (iter != Interfaces.end())
688                 iter->second.first++;
689
690 }
691
692 void ModuleManager::DoneWithInterface(const std::string &InterfaceName)
693 {
694         interfacelist::iterator iter = Interfaces.find(InterfaceName);
695         if (iter != Interfaces.end())
696                 iter->second.first--;
697 }
698
699 std::pair<int,std::string> ModuleManager::GetInterfaceInstanceCount(Module* m)
700 {
701         for (interfacelist::iterator iter = Interfaces.begin(); iter != Interfaces.end(); iter++)
702         {
703                 for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
704                 {
705                         if (*x == m)
706                         {
707                                 return std::make_pair(iter->second.first, iter->first);
708                         }
709                 }
710         }
711         return std::make_pair(0, "");
712 }
713
714 const std::string& ModuleManager::GetModuleName(Module* m)
715 {
716         static std::string nothing;
717
718         for (std::map<std::string, std::pair<ircd_module*, Module*> >::iterator n = Modules.begin(); n != Modules.end(); ++n)
719         {
720                 if (n->second.second == m)
721                         return n->first;
722         }
723
724         return nothing;
725 }
726
727 /* This is ugly, yes, but hash_map's arent designed to be
728  * addressed in this manner, and this is a bit of a kludge.
729  * Luckily its a specialist function and rarely used by
730  * many modules (in fact, it was specially created to make
731  * m_safelist possible, initially).
732  */
733
734 Channel* InspIRCd::GetChannelIndex(long index)
735 {
736         int target = 0;
737         for (chan_hash::iterator n = this->chanlist->begin(); n != this->chanlist->end(); n++, target++)
738         {
739                 if (index == target)
740                         return n->second;
741         }
742         return NULL;
743 }
744
745 CmdResult InspIRCd::CallCommandHandler(const std::string &commandname, const std::vector<std::string>& parameters, User* user)
746 {
747         return this->Parser->CallHandler(commandname, parameters, user);
748 }
749
750 bool InspIRCd::IsValidModuleCommand(const std::string &commandname, int pcnt, User* user)
751 {
752         return this->Parser->IsValidCommand(commandname, pcnt, user);
753 }
754
755 void InspIRCd::AddCommand(Command *f)
756 {
757         if (!this->Parser->CreateCommand(f))
758         {
759                 ModuleException err("Command "+std::string(f->command)+" already exists.");
760                 throw (err);
761         }
762 }
763
764 void InspIRCd::SendMode(const std::vector<std::string>& parameters, User *user)
765 {
766         this->Modes->Process(parameters, user, true);
767 }
768
769 void InspIRCd::DumpText(User* User, const std::string &LinePrefix, std::stringstream &TextStream)
770 {
771         std::string CompleteLine = LinePrefix;
772         std::string Word;
773         while (TextStream >> Word)
774         {
775                 if (CompleteLine.length() + Word.length() + 3 > 500)
776                 {
777                         User->WriteServ(CompleteLine);
778                         CompleteLine = LinePrefix;
779                 }
780                 CompleteLine = CompleteLine + Word + " ";
781         }
782         User->WriteServ(CompleteLine);
783 }
784
785 bool InspIRCd::AddResolver(Resolver* r, bool cached)
786 {
787         if (!cached)
788                 return this->Res->AddResolverClass(r);
789         else
790         {
791                 r->TriggerCachedResult();
792                 delete r;
793                 return true;
794         }
795 }
796
797 Module* ModuleManager::Find(const std::string &name)
798 {
799         std::map<std::string, std::pair<ircd_module*, Module*> >::iterator modfind = Modules.find(name);
800
801         if (modfind == Modules.end())
802                 return NULL;
803         else
804                 return modfind->second.second;
805 }
806
807 const std::vector<std::string> ModuleManager::GetAllModuleNames(int filter)
808 {
809         std::vector<std::string> retval;
810         for (std::map<std::string, std::pair<ircd_module*, Module*> >::iterator x = Modules.begin(); x != Modules.end(); ++x)
811                 if (!filter || (x->second.second->GetVersion().Flags & filter))
812                         retval.push_back(x->first);
813         return retval;
814 }
815
816 ConfigReader::ConfigReader(InspIRCd* Instance) : ServerInstance(Instance)
817 {
818         this->error = 0;
819 }
820
821
822 ConfigReader::~ConfigReader()
823 {
824 }
825
826
827 std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds)
828 {
829         /* Don't need to strlcpy() tag and name anymore, ReadConf() takes const char* */
830         std::string result;
831
832         if (!ServerInstance->Config->ConfValue(tag, name, default_value, index, result, allow_linefeeds))
833         {
834                 this->error = CONF_VALUE_NOT_FOUND;
835         }
836         return result;
837 }
838
839 std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds)
840 {
841         return ReadValue(tag, name, "", index, allow_linefeeds);
842 }
843
844 bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index)
845 {
846         return ServerInstance->Config->ConfValueBool(tag, name, default_value, index);
847 }
848
849 bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, int index)
850 {
851         return ReadFlag(tag, name, "", index);
852 }
853
854
855 int ConfigReader::ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool need_positive)
856 {
857         int result;
858
859         if(!ServerInstance->Config->ConfValueInteger(tag, name, default_value, index, result))
860         {
861                 this->error = CONF_VALUE_NOT_FOUND;
862                 return 0;
863         }
864
865         if ((need_positive) && (result < 0))
866         {
867                 this->error = CONF_INT_NEGATIVE;
868                 return 0;
869         }
870
871         return result;
872 }
873
874 int ConfigReader::ReadInteger(const std::string &tag, const std::string &name, int index, bool need_positive)
875 {
876         return ReadInteger(tag, name, "", index, need_positive);
877 }
878
879 long ConfigReader::GetError()
880 {
881         long olderr = this->error;
882         this->error = 0;
883         return olderr;
884 }
885
886 int ConfigReader::Enumerate(const std::string &tag)
887 {
888         return ServerInstance->Config->ConfValueEnum(tag);
889 }
890
891 int ConfigReader::EnumerateValues(const std::string &tag, int index)
892 {
893         return ServerInstance->Config->ConfVarEnum(tag, index);
894 }
895
896 FileReader::FileReader(InspIRCd* Instance, const std::string &filename) : ServerInstance(Instance)
897 {
898         LoadFile(filename);
899 }
900
901 FileReader::FileReader(InspIRCd* Instance) : ServerInstance(Instance)
902 {
903 }
904
905 std::string FileReader::Contents()
906 {
907         std::string x;
908         for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)
909         {
910                 x.append(*a);
911                 x.append("\r\n");
912         }
913         return x;
914 }
915
916 unsigned long FileReader::ContentSize()
917 {
918         return this->contentsize;
919 }
920
921 void FileReader::CalcSize()
922 {
923         unsigned long n = 0;
924         for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)
925                 n += (a->length() + 2);
926         this->contentsize = n;
927 }
928
929 void FileReader::LoadFile(const std::string &filename)
930 {
931         file_cache c;
932         c.clear();
933         if (ServerInstance->Config->ReadFile(c,filename.c_str()))
934         {
935                 this->fc = c;
936                 this->CalcSize();
937         }
938 }
939
940
941 FileReader::~FileReader()
942 {
943 }
944
945 bool FileReader::Exists()
946 {
947         return (!(fc.size() == 0));
948 }
949
950 std::string FileReader::GetLine(int x)
951 {
952         if ((x<0) || ((unsigned)x>fc.size()))
953                 return "";
954         return fc[x];
955 }
956
957 int FileReader::FileSize()
958 {
959         return fc.size();
960 }