diff options
author | Adam <Adam@Anope.org> | 2010-05-25 00:57:25 -0500 |
---|---|---|
committer | Adam <Adam@anope.org> | 2010-06-18 21:04:07 -0400 |
commit | 4a2b9ebcf38d6c0a2860b966421b3af125438488 (patch) | |
tree | e4af4e59fd29352138db0fb0ff614d50233850b8 /src/modules.cpp | |
parent | 2fba686904e6f78ebab35df171c5757afeebf05d (diff) |
Renamed all of source files from .c to .cpp
Diffstat (limited to 'src/modules.cpp')
-rw-r--r-- | src/modules.cpp | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/src/modules.cpp b/src/modules.cpp new file mode 100644 index 000000000..0044bcc56 --- /dev/null +++ b/src/modules.cpp @@ -0,0 +1,413 @@ +/* Modular support + * + * (C) 2003-2010 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * + */ +#include "modules.h" +#include "language.h" +#include "version.h" + +std::multimap<std::string, Message *> MessageMap; +std::deque<Module *> Modules; + +char *mod_current_buffer = NULL; + +char *ModuleGetErrStr(int status) +{ + const char *module_err_str[] = { + "Module, Okay - No Error", /* MOD_ERR_OK */ + "Module Error, Allocating memory", /* MOD_ERR_MEMORY */ + "Module Error, Not enough parameters", /* MOD_ERR_PARAMS */ + "Module Error, Already loaded", /* MOD_ERR_EXISTS */ + "Module Error, File does not exist", /* MOD_ERR_NOEXIST */ + "Module Error, No User", /* MOD_ERR_NOUSER */ + "Module Error, Error during load time or module returned MOD_STOP", /* MOD_ERR_NOLOAD */ + "Module Error, Unable to unload", /* MOD_ERR_NOUNLOAD */ + "Module Error, Incorrect syntax", /* MOD_ERR_SYNTAX */ + "Module Error, Unable to delete", /* MOD_ERR_NODELETE */ + "Module Error, Unknown Error occuried", /* MOD_ERR_UNKOWN */ + "Module Error, File I/O Error", /* MOD_ERR_FILE_IO */ + "Module Error, No Service found for request", /* MOD_ERR_NOSERVICE */ + "Module Error, No module name for request" /* MOD_ERR_NO_MOD_NAME */ + }; + return const_cast<char *>(module_err_str[status]); +} + + +/************************************************/ + +/** + * Load the ircd protocol module up + **/ +int protocol_module_init() +{ + int ret = 0; + + Alog() << "Loading IRCD Protocol Module: [" << Config.IRCDModule << "]"; + ret = ModuleManager::LoadModule(Config.IRCDModule, NULL); + + if (ret == MOD_ERR_OK) + { + FindModule(Config.IRCDModule)->SetType(PROTOCOL); + /* This is really NOT the correct place to do config checks, but + * as we only have the ircd struct filled here, we have to over + * here. -GD + */ + if (ircd->ts6) + { + if (!Config.Numeric) + { + Alog() << "This IRCd protocol requires a server id to be set in Anope's configuration."; + ret = -1; + } + } + } + + return ret; +} + +void Module::InsertLanguage(int langNumber, int ac, const char **av) +{ + int i; + + Alog(LOG_DEBUG) << this->name << "Adding " << ac << " texts for language " << langNumber; + + if (this->lang[langNumber].argc > 0) { + this->DeleteLanguage(langNumber); + } + + this->lang[langNumber].argc = ac; + this->lang[langNumber].argv = new char *[ac]; + for (i = 0; i < ac; i++) { + this->lang[langNumber].argv[i] = sstrdup(av[i]); + } +} + +/** + * Search the list of loaded modules for the given name. + * @param name the name of the module to find + * @return a pointer to the module found, or NULL + */ +Module *FindModule(const std::string &name) +{ + for (std::deque<Module *>::iterator it = Modules.begin(); it != Modules.end(); ++it) + { + Module *m = *it; + + if (m->name == name) + { + return m; + } + } + + return NULL; +} + +/** Add a message to Anope + * @param name The message name as sent by the IRCd + * @param func A callback function that will be called when this message is received + * @return The new message object + */ +Message *Anope::AddMessage(const std::string &name, int (*func)(const char *source, int ac, const char **av)) +{ + Message *m = new Message; + + m->name = name; + m->func = func; + + MessageMap.insert(std::make_pair(m->name, m)); + + return m; +} + +/** Deletes a message from Anope + * XXX Im not sure what will happen if this function is called indirectly from a message function pointed to by this message and there + * is more than one hook for this message.. must check + * @param m The message + * @return true if the message was found and deleted, else false + */ +bool Anope::DelMessage(Message *m) +{ + std::multimap<std::string, Message *>::iterator it = MessageMap.find(m->name); + + if (it == MessageMap.end()) + { + return false; + } + + std::multimap<std::string, Message *>::iterator upper = MessageMap.upper_bound(m->name); + + for (; it != upper; ++it) + { + if (it->second == m) + { + delete m; + MessageMap.erase(it); + return true; + } + } + + return false; +} + +/******************************************************************************* + * Command Functions + *******************************************************************************/ + +int Module::AddCommand(BotInfo *bi, Command *c) +{ + if (!bi || !c) + return MOD_ERR_PARAMS; + + c->module = this; + c->service = bi; + + std::pair<std::map<ci::string, Command *>::iterator, bool> it = bi->Commands.insert(std::make_pair(c->name, c)); + + if (it.second != true) + { + Alog() << "Error creating command " << c->name << ". Command already exists!"; + delete c; + return MOD_ERR_EXISTS; + } + + return MOD_ERR_OK; +} + +/** + * Delete a command from the service given. + * @param cmdTable the cmdTable for the services to remove the command from + * @param name the name of the command to delete from the service + * @return returns MOD_ERR_OK on success + */ +int Module::DelCommand(BotInfo *bi, Command *c) +{ + if (!bi || !c) + return MOD_ERR_PARAMS; + + if (!bi->Commands.erase(c->name)) + return MOD_ERR_NOEXIST; + + return MOD_ERR_OK; +} + +/** + * Find a message in the message table + * @param name The name of the message were looking for + * @return NULL if we cant find it, or a pointer to the Message if we can + **/ +std::vector<Message *> FindMessage(const std::string &name) +{ + std::vector<Message *> messages; + + std::multimap<std::string, Message *>::iterator it = MessageMap.find(name); + + if (it == MessageMap.end()) + return messages; + + std::multimap<std::string, Message *>::iterator upper = MessageMap.upper_bound(name); + + for (; it != upper; ++it) + messages.push_back(it->second); + + return messages; +} + +/******************************************************************************* + * Module Callback Functions + *******************************************************************************/ + + /* Check the current version of anope against a given version number + * Specifiying -1 for minor,patch or build + * @param major The major version of anope, the first part of the verison number + * @param minor The minor version of anope, the second part of the version number + * @param patch The patch version of anope, the third part of the version number + * @param build The build revision of anope from SVN + * @return True if the version newer than the version specified. + **/ +bool moduleMinVersion(int major, int minor, int patch, int build) +{ + bool ret = false; + if (VERSION_MAJOR > major) { /* Def. new */ + ret = true; + } else if (VERSION_MAJOR == major) { /* Might be newer */ + if (minor == -1) { + return true; + } /* They dont care about minor */ + if (VERSION_MINOR > minor) { /* Def. newer */ + ret = true; + } else if (VERSION_MINOR == minor) { /* Might be newer */ + if (patch == -1) { + return true; + } /* They dont care about patch */ + if (VERSION_PATCH > patch) { + ret = true; + } else if (VERSION_PATCH == patch) { +#if 0 +// XXX + if (build == -1) { + return true; + } /* They dont care about build */ + if (VERSION_BUILD >= build) { + ret = true; + } +#endif + } + } + } + return ret; +} + +void Module::NoticeLang(const char *source, User * u, int number, ...) +{ + va_list va; + char buffer[4096], outbuf[4096]; + char *fmt = NULL; + int mlang = Config.NSDefLanguage; + char *s, *t, *buf; + + /* Find the users lang, and use it if we can */ + if (u && u->Account()) { + mlang = u->Account()->language; + } + + /* If the users lang isnt supported, drop back to English */ + if (this->lang[mlang].argc == 0) + { + mlang = LANG_EN_US; + } + + /* If the requested lang string exists for the language */ + if (this->lang[mlang].argc > number) { + fmt = this->lang[mlang].argv[number]; + + buf = sstrdup(fmt); + va_start(va, number); + vsnprintf(buffer, 4095, buf, va); + va_end(va); + s = buffer; + while (*s) { + t = s; + s += strcspn(s, "\n"); + if (*s) + *s++ = '\0'; + strscpy(outbuf, t, sizeof(outbuf)); + u->SendMessage(source, "%s", outbuf); + } + delete [] buf; + } else { + Alog() << this->name << ": INVALID language string call, language: [" << mlang << "], String [" << number << "]"; + } +} + +const char *Module::GetLangString(User * u, int number) +{ + int mlang = Config.NSDefLanguage; + + /* Find the users lang, and use it if we can */ + if (u && u->Account()) + mlang = u->Account()->language; + + /* If the users lang isnt supported, drop back to English */ + if (this->lang[mlang].argc == 0) + mlang = LANG_EN_US; + + /* If the requested lang string exists for the language */ + if (this->lang[mlang].argc > number) { + return this->lang[mlang].argv[number]; + /* Return an empty string otherwise, because we might be used without + * the return value being checked. If we would return NULL, bad things + * would happen! + */ + } else { + Alog() << this->name << ": INVALID language string call, language: [" << mlang << "], String [" << number << "]"; + return ""; + } +} + +void Module::DeleteLanguage(int langNumber) +{ + if (this->lang[langNumber].argc) + { + for (int idx = 0; idx > this->lang[langNumber].argc; idx++) + delete [] this->lang[langNumber].argv[idx]; + delete [] this->lang[langNumber].argv; + this->lang[langNumber].argc = 0; + } +} + +void ModuleRunTimeDirCleanUp() +{ +#ifndef _WIN32 + DIR *dirp; + struct dirent *dp; +#else + BOOL fFinished; + HANDLE hList; + TCHAR szDir[MAX_PATH + 1]; + WIN32_FIND_DATA FileData; + char buffer[_MAX_PATH]; +#endif + char dirbuf[BUFSIZE]; + char filebuf[BUFSIZE]; + + snprintf(dirbuf, BUFSIZE, "%s/modules/runtime", services_dir.c_str()); + + Alog(LOG_DEBUG) << "Cleaning out Module run time directory (" << dirbuf << ") - this may take a moment please wait"; + + +#ifndef _WIN32 + if ((dirp = opendir(dirbuf)) == NULL) + { + Alog(LOG_DEBUG) << "cannot open directory (" << dirbuf << ")"; + return; + } + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_ino == 0) { + continue; + } + if (!stricmp(dp->d_name, ".") || !stricmp(dp->d_name, "..")) { + continue; + } + snprintf(filebuf, BUFSIZE, "%s/%s", dirbuf, dp->d_name); + unlink(filebuf); + } + closedir(dirp); +#else + /* Get the current working directory: */ + if (_getcwd(buffer, _MAX_PATH) == NULL) + { + Alog(LOG_DEBUG) << "Unable to set Current working directory"; + } + snprintf(szDir, sizeof(szDir), "%s\\%s\\*", buffer, dirbuf); + + hList = FindFirstFile(szDir, &FileData); + if (hList != INVALID_HANDLE_VALUE) { + fFinished = FALSE; + while (!fFinished) { + if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + snprintf(filebuf, BUFSIZE, "%s/%s", dirbuf, FileData.cFileName); + DeleteFile(filebuf); + } + if (!FindNextFile(hList, &FileData)) { + if (GetLastError() == ERROR_NO_MORE_FILES) { + fFinished = TRUE; + } + } + } + } else { + Alog(LOG_DEBUG) << "Invalid File Handle. GetLastError() reports "<< static_cast<int>(GetLastError()); + } + FindClose(hList); +#endif + Alog(LOG_DEBUG) << "Module run time directory has been cleaned out"; +} + +/* EOF */ |