diff options
Diffstat (limited to 'src')
69 files changed, 3590 insertions, 6213 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b390d164b..007e3605a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,72 +2,37 @@ file(GLOB SRC_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") if(WIN32) - append_to_list(SRC_SRCS win32/dir/dir.cpp) - append_to_list(SRC_SRCS win32/socket.cpp) - append_to_list(SRC_SRCS win32/windows.cpp) - append_to_list(SRC_SRCS win32/dl/dl.cpp) - append_to_list(SRC_SRCS win32/pipe/pipe.cpp) - append_to_list(SRC_SRCS win32/pthread/pthread.cpp) - append_to_list(SRC_SRCS win32/sigaction/sigaction.cpp) -endif(WIN32) + list(APPEND SRC_SRCS win32/dir/dir.cpp) + list(APPEND SRC_SRCS win32/socket.cpp) + list(APPEND SRC_SRCS win32/windows.cpp) + list(APPEND SRC_SRCS win32/dl/dl.cpp) + list(APPEND SRC_SRCS win32/pipe/pipe.cpp) + list(APPEND SRC_SRCS win32/sigaction/sigaction.cpp) +endif() if(HAVE_EPOLL) - append_to_list(SRC_SRCS socketengines/socketengine_epoll.cpp) -else(HAVE_EPOLL) - if(HAVE_KQUEUE) - append_to_list(SRC_SRCS socketengines/socketengine_kqueue.cpp) - else(HAVE_KQUEUE) - if(HAVE_POLL) - append_to_list(SRC_SRCS socketengines/socketengine_poll.cpp) - else(HAVE_POLL) - append_to_list(SRC_SRCS socketengines/socketengine_select.cpp) - endif(HAVE_POLL) - endif(HAVE_KQUEUE) -endif(HAVE_EPOLL) + list(APPEND SRC_SRCS socketengines/socketengine_epoll.cpp) +elseif(HAVE_KQUEUE) + list(APPEND SRC_SRCS socketengines/socketengine_kqueue.cpp) +elseif(HAVE_POLL) + list(APPEND SRC_SRCS socketengines/socketengine_poll.cpp) +else() + list(APPEND SRC_SRCS socketengines/socketengine_select.cpp) +endif() -sort_list(SRC_SRCS) +list(SORT SRC_SRCS) # Set all the files to use C++ as well as set their compile flags (use the module-specific compile flags, though) set_source_files_properties(${SRC_SRCS} PROPERTIES LANGUAGE CXX COMPILE_FLAGS "${CXXFLAGS}") -# Create an empty list to store extra include directories -set(EXTRA_INCLUDES) -# Iterate through all the source files -foreach(SRC ${SRC_SRCS}) - # Temporary variable for the current source's include directories - set(TEMP_INCLUDES) - # Calculate the header file dependencies for the given source file - calculate_depends(${SRC} TEMP_INCLUDES) - # If there were some extra include directories, add them to the list - if(TEMP_INCLUDES) - append_to_list(EXTRA_INCLUDES ${TEMP_INCLUDES}) - endif(TEMP_INCLUDES) -endforeach(SRC) -# If there were extra include directories, remove the duplicates and add the directories to the include path -if(EXTRA_INCLUDES) - remove_list_duplicates(EXTRA_INCLUDES) - include_directories(${EXTRA_INCLUDES}) -endif(EXTRA_INCLUDES) - # Under Windows, we also include a resource file to the build if(WIN32) # Make sure that the resource file is seen as an RC file to be compiled with a resource compiler, not a C++ compiler set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/win32/win32.rc LANGUAGE RC) # Add the resource file to the list of sources - append_to_list(SRC_SRCS ${CMAKE_CURRENT_BINARY_DIR}/win32/win32.rc) - # For MinGW, we have to change the compile flags - if(MINGW) - set(RC_CFLAGS "-DMINGW -Ocoff -I${Anope_SOURCE_DIR}/include") - # If any sort of debugging is being enabled, add a _DEBUG define to the flags for the resource compiler - if(CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO") - set(RC_CFLAGS "${RC_CFLAGS} -D_DEBUG") - endif(CMAKE_BUILD_TYPE STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO") - set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/win32/win32.rc COMPILE_FLAGS "${RC_CFLAGS}") - # For anything else, assumingly Visual Studio at this point, use a different set of compile flags - else(MINGW) - set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/win32/win32.rc COMPILE_FLAGS "/i\"${Anope_SOURCE_DIR}/include\"") - endif(MINGW) -endif(WIN32) + list(APPEND SRC_SRCS ${CMAKE_CURRENT_BINARY_DIR}/win32/win32.rc) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/win32/win32.rc COMPILE_FLAGS "/i\"${Anope_SOURCE_DIR}/include\"") +endif() # If compiling with Visual Studio, create a static library out of win32/win32_memory.cpp to be included with everything else, needed to override its override of new/delete operators if(MSVC) @@ -75,26 +40,26 @@ if(MSVC) add_library(win32_memory STATIC win32/win32_memory.cpp) set(WIN32_MEMORY win32_memory) set(EXTRA_LDFLAGS "/OPT:NOREF") # https://sourceware.org/bugzilla/show_bug.cgi?id=12633 -else(MSVC) +else() set(WIN32_MEMORY) -endif(MSVC) +endif() # Generate the Anope executable and set it's linker flags, also set it to export it's symbols even though it's not a module add_executable(${PROGRAM_NAME} ${SRC_SRCS}) set_target_properties(${PROGRAM_NAME} PROPERTIES LINKER_LANGUAGE CXX LINK_FLAGS "${LDFLAGS} ${EXTRA_LDFLAGS}" ENABLE_EXPORTS ON INSTALL_RPATH_USE_LINK_PATH ON BUILD_WITH_INSTALL_RPATH ON) # On Windows, also link Anope to the wsock32 and Ws2_32 library, as well as set the version if(WIN32) - target_link_libraries(${PROGRAM_NAME} wsock32 Ws2_32 ${LINK_LIBS} ${GETTEXT_LIBRARIES} ${WIN32_MEMORY}) + target_link_libraries(${PROGRAM_NAME} wsock32 Ws2_32 ${LINK_LIBS} ${GETTEXT_LIBRARIES} ${Boost_LIBRARIES} ${WIN32_MEMORY}) set_target_properties(${PROGRAM_NAME} PROPERTIES VERSION "${VERSION_DOTTED}") -else(WIN32) - target_link_libraries(${PROGRAM_NAME} ${LINK_LIBS} ${GETTEXT_LIBRARIES}) -endif(WIN32) +else() + target_link_libraries(${PROGRAM_NAME} ${LINK_LIBS} ${GETTEXT_LIBRARIES} ${Boost_LIBRARIES}) +endif() # Building the Anope executable requires the version.h header to be generated add_dependencies(${PROGRAM_NAME} headers) # Also require the language files if we have gettext if(GETTEXT_FOUND) add_dependencies(${PROGRAM_NAME} language) -endif(GETTEXT_FOUND) +endif() # Get the filename of the Anope executable as it is in on this system get_target_property(SERVICES_BINARY ${PROGRAM_NAME} LOCATION) @@ -108,7 +73,7 @@ configure_file(${Anope_SOURCE_DIR}/include/sysconf.h.cmake ${Anope_BINARY_DIR}/i # Go into the following directories and run their CMakeLists.txt as well if(NOT DISABLE_TOOLS) add_subdirectory(tools) -endif(NOT DISABLE_TOOLS) +endif() # Set Anope to be installed to the bin directory install(TARGETS ${PROGRAM_NAME} diff --git a/src/access.cpp b/src/access.cpp deleted file mode 100644 index 007e6d281..000000000 --- a/src/access.cpp +++ /dev/null @@ -1,476 +0,0 @@ -/* - * - * (C) 2003-2016 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 "service.h" -#include "access.h" -#include "regchannel.h" -#include "users.h" -#include "account.h" -#include "protocol.h" - -static struct -{ - Anope::string name; - Anope::string desc; -} descriptions[] = { - {"ACCESS_CHANGE", _("Allowed to modify the access list")}, - {"ACCESS_LIST", _("Allowed to view the access list")}, - {"AKICK", _("Allowed to use the AKICK command")}, - {"ASSIGN", _("Allowed to assign/unassign a bot")}, - {"AUTOHALFOP", _("Automatic halfop upon join")}, - {"AUTOOP", _("Automatic channel operator status upon join")}, - {"AUTOOWNER", _("Automatic owner upon join")}, - {"AUTOPROTECT", _("Automatic protect upon join")}, - {"AUTOVOICE", _("Automatic voice on join")}, - {"BADWORDS", _("Allowed to modify channel badwords list")}, - {"BAN", _("Allowed to ban users")}, - {"FANTASIA", _("Allowed to use fantasy commands")}, - {"FOUNDER", _("Allowed to issue commands restricted to channel founders")}, - {"GETKEY", _("Allowed to use GETKEY command")}, - {"GREET", _("Greet message displayed on join")}, - {"HALFOP", _("Allowed to (de)halfop users")}, - {"HALFOPME", _("Allowed to (de)halfop him/herself")}, - {"INFO", _("Allowed to get full INFO output")}, - {"INVITE", _("Allowed to use the INVITE command")}, - {"KICK", _("Allowed to use the KICK command")}, - {"MEMO", _("Allowed to read channel memos")}, - {"MODE", _("Allowed to use the MODE command")}, - {"NOKICK", _("Prevents users being kicked by Services")}, - {"OP", _("Allowed to (de)op users")}, - {"OPME", _("Allowed to (de)op him/herself")}, - {"OWNER", _("Allowed to (de)owner users")}, - {"OWNERME", _("Allowed to (de)owner him/herself")}, - {"PROTECT", _("Allowed to (de)protect users")}, - {"PROTECTME", _("Allowed to (de)protect him/herself")}, - {"SAY", _("Allowed to use SAY and ACT commands")}, - {"SET", _("Allowed to set channel settings")}, - {"SIGNKICK", _("No signed kick when SIGNKICK LEVEL is used")}, - {"TOPIC", _("Allowed to change channel topics")}, - {"UNBAN", _("Allowed to unban users")}, - {"VOICE", _("Allowed to (de)voice users")}, - {"VOICEME", _("Allowed to (de)voice him/herself")} -}; - -Privilege::Privilege(const Anope::string &n, const Anope::string &d, int r) : name(n), desc(d), rank(r) -{ - if (this->desc.empty()) - for (unsigned j = 0; j < sizeof(descriptions) / sizeof(*descriptions); ++j) - if (descriptions[j].name.equals_ci(name)) - this->desc = descriptions[j].desc; -} - -bool Privilege::operator==(const Privilege &other) const -{ - return this->name.equals_ci(other.name); -} - -std::vector<Privilege> PrivilegeManager::Privileges; - -void PrivilegeManager::AddPrivilege(Privilege p) -{ - unsigned i; - for (i = 0; i < Privileges.size(); ++i) - { - Privilege &priv = Privileges[i]; - - if (priv.rank > p.rank) - break; - } - - Privileges.insert(Privileges.begin() + i, p); -} - -void PrivilegeManager::RemovePrivilege(Privilege &p) -{ - std::vector<Privilege>::iterator it = std::find(Privileges.begin(), Privileges.end(), p); - if (it != Privileges.end()) - Privileges.erase(it); - - for (registered_channel_map::const_iterator cit = RegisteredChannelList->begin(), cit_end = RegisteredChannelList->end(); cit != cit_end; ++cit) - { - cit->second->QueueUpdate(); - cit->second->RemoveLevel(p.name); - } -} - -Privilege *PrivilegeManager::FindPrivilege(const Anope::string &name) -{ - for (unsigned i = Privileges.size(); i > 0; --i) - if (Privileges[i - 1].name.equals_ci(name)) - return &Privileges[i - 1]; - return NULL; -} - -std::vector<Privilege> &PrivilegeManager::GetPrivileges() -{ - return Privileges; -} - -void PrivilegeManager::ClearPrivileges() -{ - Privileges.clear(); -} - -AccessProvider::AccessProvider(Module *o, const Anope::string &n) : Service(o, "AccessProvider", n) -{ - Providers.push_back(this); -} - -AccessProvider::~AccessProvider() -{ - std::list<AccessProvider *>::iterator it = std::find(Providers.begin(), Providers.end(), this); - if (it != Providers.end()) - Providers.erase(it); -} - -std::list<AccessProvider *> AccessProvider::Providers; - -const std::list<AccessProvider *>& AccessProvider::GetProviders() -{ - return Providers; -} - -ChanAccess::ChanAccess(AccessProvider *p) : Serializable("ChanAccess"), provider(p) -{ -} - -ChanAccess::~ChanAccess() -{ - if (this->ci) - { - std::vector<ChanAccess *>::iterator it = std::find(this->ci->access->begin(), this->ci->access->end(), this); - if (it != this->ci->access->end()) - this->ci->access->erase(it); - - if (*nc != NULL) - nc->RemoveChannelReference(this->ci); - else - { - ChannelInfo *c = ChannelInfo::Find(this->mask); - if (c) - c->RemoveChannelReference(this->ci->name); - } - } -} - -void ChanAccess::SetMask(const Anope::string &m, ChannelInfo *c) -{ - if (*nc != NULL) - nc->RemoveChannelReference(this->ci); - else if (!this->mask.empty()) - { - ChannelInfo *targc = ChannelInfo::Find(this->mask); - if (targc) - targc->RemoveChannelReference(this->ci->name); - } - - ci = c; - mask.clear(); - nc = NULL; - - const NickAlias *na = NickAlias::Find(m); - if (na != NULL) - { - nc = na->nc; - nc->AddChannelReference(ci); - } - else - { - mask = m; - - ChannelInfo *targci = ChannelInfo::Find(mask); - if (targci != NULL) - targci->AddChannelReference(ci->name); - } -} - -const Anope::string &ChanAccess::Mask() const -{ - if (nc) - return nc->display; - else - return mask; -} - -NickCore *ChanAccess::GetAccount() const -{ - return nc; -} - -void ChanAccess::Serialize(Serialize::Data &data) const -{ - data["provider"] << this->provider->name; - data["ci"] << this->ci->name; - data["mask"] << this->Mask(); - data["creator"] << this->creator; - data.SetType("last_seen", Serialize::Data::DT_INT); data["last_seen"] << this->last_seen; - data.SetType("created", Serialize::Data::DT_INT); data["created"] << this->created; - data["data"] << this->AccessSerialize(); -} - -Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string provider, chan; - - data["provider"] >> provider; - data["ci"] >> chan; - - ServiceReference<AccessProvider> aprovider("AccessProvider", provider); - ChannelInfo *ci = ChannelInfo::Find(chan); - if (!aprovider || !ci) - return NULL; - - ChanAccess *access; - if (obj) - access = anope_dynamic_static_cast<ChanAccess *>(obj); - else - access = aprovider->Create(); - access->ci = ci; - Anope::string m; - data["mask"] >> m; - access->SetMask(m, ci); - data["creator"] >> access->creator; - data["last_seen"] >> access->last_seen; - data["created"] >> access->created; - - Anope::string adata; - data["data"] >> adata; - access->AccessUnserialize(adata); - - if (!obj) - ci->AddAccess(access); - return access; -} - -bool ChanAccess::Matches(const User *u, const NickCore *acc, ChannelInfo* &next) const -{ - next = NULL; - - if (this->nc) - return this->nc == acc; - - if (u) - { - bool is_mask = this->mask.find_first_of("!@?*") != Anope::string::npos; - if (is_mask && Anope::Match(u->nick, this->mask)) - return true; - else if (Anope::Match(u->GetDisplayedMask(), this->mask)) - return true; - } - - if (acc) - { - for (unsigned i = 0; i < acc->aliases->size(); ++i) - { - const NickAlias *na = acc->aliases->at(i); - if (Anope::Match(na->nick, this->mask)) - return true; - } - } - - if (IRCD->IsChannelValid(this->mask)) - { - next = ChannelInfo::Find(this->mask); - } - - return false; -} - -bool ChanAccess::operator>(const ChanAccess &other) const -{ - const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges(); - for (unsigned i = privs.size(); i > 0; --i) - { - bool this_p = this->HasPriv(privs[i - 1].name), - other_p = other.HasPriv(privs[i - 1].name); - - if (!this_p && !other_p) - continue; - - return this_p && !other_p; - } - - return false; -} - -bool ChanAccess::operator<(const ChanAccess &other) const -{ - const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges(); - for (unsigned i = privs.size(); i > 0; --i) - { - bool this_p = this->HasPriv(privs[i - 1].name), - other_p = other.HasPriv(privs[i - 1].name); - - if (!this_p && !other_p) - continue; - - return !this_p && other_p; - } - - return false; -} - -bool ChanAccess::operator>=(const ChanAccess &other) const -{ - return !(*this < other); -} - -bool ChanAccess::operator<=(const ChanAccess &other) const -{ - return !(*this > other); -} - -AccessGroup::AccessGroup() -{ - this->ci = NULL; - this->nc = NULL; - this->super_admin = this->founder = false; -} - -static bool HasPriv(const ChanAccess::Path &path, const Anope::string &name) -{ - if (path.empty()) - return false; - - for (unsigned int i = 0; i < path.size(); ++i) - { - ChanAccess *access = path[i]; - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name)); - - if (MOD_RESULT != EVENT_ALLOW && !access->HasPriv(name)) - return false; - } - - return true; -} - -bool AccessGroup::HasPriv(const Anope::string &name) const -{ - if (this->super_admin) - return true; - else if (!ci || ci->GetLevel(name) == ACCESS_INVALID) - return false; - - /* Privileges prefixed with auto are understood to be given - * automatically. Sometimes founders want to not automatically - * obtain privileges, so we will let them */ - bool auto_mode = !name.find("AUTO"); - - /* Only grant founder privilege if this isn't an auto mode or if they don't match any entries in this group */ - if ((!auto_mode || paths.empty()) && this->founder) - return true; - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnGroupCheckPriv, MOD_RESULT, (this, name)); - if (MOD_RESULT != EVENT_CONTINUE) - return MOD_RESULT == EVENT_ALLOW; - - for (unsigned int i = paths.size(); i > 0; --i) - { - const ChanAccess::Path &path = paths[i - 1]; - - if (::HasPriv(path, name)) - return true; - } - - return false; -} - -static ChanAccess *HighestInPath(const ChanAccess::Path &path) -{ - ChanAccess *highest = NULL; - - for (unsigned int i = 0; i < path.size(); ++i) - if (highest == NULL || *path[i] > *highest) - highest = path[i]; - - return highest; -} - -const ChanAccess *AccessGroup::Highest() const -{ - ChanAccess *highest = NULL; - - for (unsigned int i = 0; i < paths.size(); ++i) - { - ChanAccess *hip = HighestInPath(paths[i]); - - if (highest == NULL || *hip > *highest) - highest = hip; - } - - return highest; -} - -bool AccessGroup::operator>(const AccessGroup &other) const -{ - if (other.super_admin) - return false; - else if (this->super_admin) - return true; - else if (other.founder) - return false; - else if (this->founder) - return true; - - const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges(); - for (unsigned i = privs.size(); i > 0; --i) - { - bool this_p = this->HasPriv(privs[i - 1].name), - other_p = other.HasPriv(privs[i - 1].name); - - if (!this_p && !other_p) - continue; - - return this_p && !other_p; - } - - return false; -} - -bool AccessGroup::operator<(const AccessGroup &other) const -{ - if (this->super_admin) - return false; - else if (other.super_admin) - return true; - else if (this->founder) - return false; - else if (other.founder) - return true; - - const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges(); - for (unsigned i = privs.size(); i > 0; --i) - { - bool this_p = this->HasPriv(privs[i - 1].name), - other_p = other.HasPriv(privs[i - 1].name); - - if (!this_p && !other_p) - continue; - - return !this_p && other_p; - } - - return false; -} - -bool AccessGroup::operator>=(const AccessGroup &other) const -{ - return !(*this < other); -} - -bool AccessGroup::operator<=(const AccessGroup &other) const -{ - return !(*this > other); -} - diff --git a/src/accessgroup.cpp b/src/accessgroup.cpp new file mode 100644 index 000000000..a143bede1 --- /dev/null +++ b/src/accessgroup.cpp @@ -0,0 +1,125 @@ +/*
+ * Anope IRC Services
+ *
+ * Copyright (C) 2011-2016 Anope Team <team@anope.org>
+ *
+ * This file is part of Anope. Anope is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see see <http://www.gnu.org/licenses/>.
+ */
+
+#include "modules/chanserv.h"
+#include "accessgroup.h"
+
+using namespace ChanServ;
+
+bool AccessGroup::HasPriv(const Anope::string &priv)
+{
+ if (this->super_admin)
+ return true;
+ else if (!ci || ci->GetLevel(priv) == ACCESS_INVALID)
+ return false;
+
+ /* Privileges prefixed with auto are understood to be given
+ * automatically. Sometimes founders want to not automatically
+ * obtain privileges, so we will let them */
+ bool auto_mode = !priv.find("AUTO");
+
+ /* Only grant founder privilege if this isn't an auto mode or if they don't match any entries in this group */
+ if ((!auto_mode || this->empty()) && this->founder)
+ return true;
+
+ EventReturn MOD_RESULT = EventManager::Get()->Dispatch(&::Event::GroupCheckPriv::OnGroupCheckPriv, this, priv);
+ if (MOD_RESULT != EVENT_CONTINUE)
+ return MOD_RESULT == EVENT_ALLOW;
+
+ for (unsigned i = this->size(); i > 0; --i)
+ {
+ ChanAccess *access = this->at(i - 1);
+
+ if (access->HasPriv(priv))
+ return true;
+ }
+
+ return false;
+}
+
+ChanAccess *AccessGroup::Highest() const
+{
+ ChanAccess *highest = NULL;
+ for (unsigned i = 0; i < this->size(); ++i)
+ if (highest == NULL || *this->at(i) > *highest)
+ highest = this->at(i);
+ return highest;
+}
+
+bool AccessGroup::operator>(AccessGroup &other)
+{
+ if (other.super_admin)
+ return false;
+ else if (this->super_admin)
+ return true;
+ else if (other.founder)
+ return false;
+ else if (this->founder)
+ return true;
+
+ const std::vector<Privilege> &privs = service->GetPrivileges();
+ for (unsigned i = privs.size(); i > 0; --i)
+ {
+ bool this_p = this->HasPriv(privs[i - 1].name),
+ other_p = other.HasPriv(privs[i - 1].name);
+
+ if (!this_p && !other_p)
+ continue;
+
+ return this_p && !other_p;
+ }
+
+ return false;
+}
+
+bool AccessGroup::operator<(AccessGroup &other)
+{
+ if (this->super_admin)
+ return false;
+ else if (other.super_admin)
+ return true;
+ else if (this->founder)
+ return false;
+ else if (other.founder)
+ return true;
+
+ const std::vector<Privilege> &privs = service->GetPrivileges();
+ for (unsigned i = privs.size(); i > 0; --i)
+ {
+ bool this_p = this->HasPriv(privs[i - 1].name),
+ other_p = other.HasPriv(privs[i - 1].name);
+
+ if (!this_p && !other_p)
+ continue;
+
+ return !this_p && other_p;
+ }
+
+ return false;
+}
+
+bool AccessGroup::operator>=(AccessGroup &other)
+{
+ return !(*this < other);
+}
+
+bool AccessGroup::operator<=(AccessGroup &other)
+{
+ return !(*this > other);
+}
diff --git a/src/account.cpp b/src/account.cpp deleted file mode 100644 index f23f81242..000000000 --- a/src/account.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * (C) 2003-2016 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 "services.h" -#include "account.h" -#include "modules.h" -#include "users.h" -#include "protocol.h" -#include "regchannel.h" - -std::set<IdentifyRequest *> IdentifyRequest::Requests; - -IdentifyRequest::IdentifyRequest(Module *o, const Anope::string &acc, const Anope::string &pass) : owner(o), account(acc), password(pass), dispatched(false), success(false) -{ - Requests.insert(this); -} - -IdentifyRequest::~IdentifyRequest() -{ - Requests.erase(this); -} - -void IdentifyRequest::Hold(Module *m) -{ - holds.insert(m); -} - -void IdentifyRequest::Release(Module *m) -{ - holds.erase(m); - if (holds.empty() && dispatched) - { - if (!success) - this->OnFail(); - delete this; - } -} - -void IdentifyRequest::Success(Module *m) -{ - if (!success) - { - this->OnSuccess(); - success = true; - } -} - -void IdentifyRequest::Dispatch() -{ - if (holds.empty()) - { - if (!success) - this->OnFail(); - delete this; - } - else - dispatched = true; -} - -void IdentifyRequest::ModuleUnload(Module *m) -{ - for (std::set<IdentifyRequest *>::iterator it = Requests.begin(), it_end = Requests.end(); it != it_end;) - { - IdentifyRequest *ir = *it; - ++it; - - ir->holds.erase(m); - if (ir->holds.empty() && ir->dispatched) - { - if (!ir->success) - ir->OnFail(); - delete ir; - continue; - } - - if (ir->owner == m) - { - if (!ir->success) - ir->OnFail(); - delete ir; - } - } -} diff --git a/src/base.cpp b/src/base.cpp index 5e4ecc9e3..c35a654b4 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -1,17 +1,47 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2010-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "anope.h" #include "service.h" +#include "base.h" + +std::set<ReferenceBase *> *ReferenceBase::references = NULL; + +ReferenceBase::ReferenceBase() +{ + if (references == NULL) + references = new std::set<ReferenceBase *>(); + references->insert(this); +} -std::map<Anope::string, std::map<Anope::string, Service *> > Service::Services; -std::map<Anope::string, std::map<Anope::string, Anope::string> > Service::Aliases; +ReferenceBase::~ReferenceBase() +{ + references->erase(this); +} + +void ReferenceBase::ResetAll() +{ + if (references) + for (ReferenceBase *b : *references) + b->Reset(); +} Base::Base() : references(NULL) { diff --git a/src/base64.cpp b/src/base64.cpp index 3096d9c3f..5c2d721ad 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -1,12 +1,20 @@ -/* base64 routines. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2004-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" diff --git a/src/bots.cpp b/src/bots.cpp index 7654bb247..7aaefccc1 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -1,9 +1,21 @@ /* + * Anope IRC Services * - * (C) 2008-2011 Robin Burchell <w00t@inspircd.org> - * (C) 2008-2016 Anope Team <team@anope.org> + * Copyright (C) 2008-2011 Robin Burchell <w00t@inspircd.org> + * Copyright (C) 2008-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -12,25 +24,22 @@ #include "servers.h" #include "protocol.h" #include "xline.h" -#include "regchannel.h" #include "channels.h" #include "config.h" #include "language.h" #include "serialize.h" +#include "event.h" +#include "modules/chanserv.h" -Serialize::Checker<botinfo_map> BotListByNick("BotInfo"), BotListByUID("BotInfo"); - -BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const Anope::string &nhost, const Anope::string &nreal, const Anope::string &bmodes) : User(nnick, nuser, nhost, "", "", Me, nreal, Anope::CurTime, "", IRCD ? IRCD->UID_Retrieve() : "", NULL), Serializable("BotInfo"), channels("ChannelInfo"), botmodes(bmodes) +ServiceBot::ServiceBot(const Anope::string &nnick, const Anope::string &nuser, const Anope::string &nhost, const Anope::string &nreal, const Anope::string &bmodes) + : LocalUser(nnick, nuser, nhost, "", "", Me, nreal, Anope::CurTime, "", IRCD ? IRCD->UID_Retrieve() : "", NULL) + , botmodes(bmodes) + , logger(this) { - this->lastmsg = this->created = Anope::CurTime; - this->introduced = false; - this->oper_only = this->conf = false; + this->type = UserType::BOT; + this->lastmsg = Anope::CurTime; - (*BotListByNick)[this->nick] = this; - if (!this->uid.empty()) - (*BotListByUID)[this->uid] = this; - - FOREACH_MOD(OnCreateBot, (this)); + EventManager::Get()->Dispatch(&Event::CreateBot::OnCreateBot, this); // If we're synchronised with the uplink already, send the bot. if (Me && Me->IsSynced()) @@ -39,191 +48,146 @@ BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const A if (!tmodes.empty()) this->SetModesInternal(this, tmodes.c_str()); - XLine x(this->nick, "Reserved for services"); - IRCD->SendSQLine(NULL, &x); - IRCD->SendClientIntroduction(this); + //XXX + //XLine x(this->nick, "Reserved for services"); + //IRCD->SendSQLine(NULL, &x); + IRCD->Send<messages::NickIntroduction>(this); this->introduced = true; } } -BotInfo::~BotInfo() +ServiceBot::~ServiceBot() { - UnsetExtensibles(); + if (bi != nullptr) + { + bi->bot = nullptr; + bi->Delete(); + } - FOREACH_MOD(OnDelBot, (this)); + EventManager::Get()->Dispatch(&Event::DelBot::OnDelBot, this); // If we're synchronised with the uplink already, send the bot. if (Me && Me->IsSynced()) { IRCD->SendQuit(this, ""); - FOREACH_MOD(OnUserQuit, (this, "")); + EventManager::Get()->Dispatch(&Event::UserQuit::OnUserQuit, this, ""); this->introduced = false; - XLine x(this->nick); - IRCD->SendSQLineDel(&x); - } - - for (std::set<ChannelInfo *>::iterator it = this->channels->begin(), it_end = this->channels->end(); it != it_end; ++it) - { - ChannelInfo *ci = *it; - this->UnAssign(NULL, ci); + // XXX ? + //XLine x(this->nick); + //IRCD->SendSQLineDel(&x); } - - BotListByNick->erase(this->nick); - if (!this->uid.empty()) - BotListByUID->erase(this->uid); } -void BotInfo::Serialize(Serialize::Data &data) const -{ - data["nick"] << this->nick; - data["user"] << this->ident; - data["host"] << this->host; - data["realname"] << this->realname; - data["created"] << this->created; - data["oper_only"] << this->oper_only; - - Extensible::ExtensibleSerialize(this, this, data); -} -Serializable* BotInfo::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string nick, user, host, realname, flags; - - data["nick"] >> nick; - data["user"] >> user; - data["host"] >> host; - data["realname"] >> realname; - - BotInfo *bi; - if (obj) - bi = anope_dynamic_static_cast<BotInfo *>(obj); - else if (!(bi = BotInfo::Find(nick, true))) - bi = new BotInfo(nick, user, host, realname); - - data["created"] >> bi->created; - data["oper_only"] >> bi->oper_only; - - Extensible::ExtensibleUnserialize(bi, bi, data); - - return bi; -} - -void BotInfo::GenerateUID() +void ServiceBot::GenerateUID() { if (this->introduced) throw CoreException("Changing bot UID when it is introduced?"); if (!this->uid.empty()) - { - BotListByUID->erase(this->uid); UserListByUID.erase(this->uid); - } - this->uid = IRCD->UID_Retrieve(); - (*BotListByUID)[this->uid] = this; UserListByUID[this->uid] = this; } -void BotInfo::OnKill() +void ServiceBot::OnKill() { this->introduced = false; this->GenerateUID(); - IRCD->SendClientIntroduction(this); + IRCD->Send<messages::NickIntroduction>(this); this->introduced = true; for (User::ChanUserList::const_iterator cit = this->chans.begin(), cit_end = this->chans.end(); cit != cit_end; ++cit) - IRCD->SendJoin(this, cit->second->chan, &cit->second->status); + IRCD->Send<messages::Join>(this, cit->second->chan, &cit->second->status); } -void BotInfo::SetNewNick(const Anope::string &newnick) +void ServiceBot::SetNewNick(const Anope::string &newnick) { UserListByNick.erase(this->nick); - BotListByNick->erase(this->nick); + if (bi != nullptr) + bi->SetNick(newnick); this->nick = newnick; UserListByNick[this->nick] = this; - (*BotListByNick)[this->nick] = this; } -const std::set<ChannelInfo *> &BotInfo::GetChannels() const +std::vector<ChanServ::Channel *> ServiceBot::GetChannels() const { - return this->channels; + return bi != nullptr ? bi->GetRefs<ChanServ::Channel *>() : std::vector<ChanServ::Channel *>(); } -void BotInfo::Assign(User *u, ChannelInfo *ci) +void ServiceBot::Assign(User *u, ChanServ::Channel *ci) { EventReturn MOD_RESULT; - FOREACH_RESULT(OnPreBotAssign, MOD_RESULT, (u, ci, this)); + MOD_RESULT = EventManager::Get()->Dispatch(&Event::PreBotAssign::OnPreBotAssign, u, ci, this); if (MOD_RESULT == EVENT_STOP) return; - if (ci->bi) - ci->bi->UnAssign(u, ci); - - ci->bi = this; - this->channels->insert(ci); + if (ci->GetBot()) + ci->GetBot()->UnAssign(u, ci); - FOREACH_MOD(OnBotAssign, (u, ci, this)); + ci->SetBot(this); + + EventManager::Get()->Dispatch(&Event::BotAssign::OnBotAssign, u, ci, this); } -void BotInfo::UnAssign(User *u, ChannelInfo *ci) +void ServiceBot::UnAssign(User *u, ChanServ::Channel *ci) { EventReturn MOD_RESULT; - FOREACH_RESULT(OnBotUnAssign, MOD_RESULT, (u, ci)); + MOD_RESULT = EventManager::Get()->Dispatch(&Event::BotUnAssign::OnBotUnAssign, u, ci); if (MOD_RESULT == EVENT_STOP) return; - if (ci->c && ci->c->FindUser(ci->bi)) + if (ci->c && ci->c->FindUser(ci->GetBot())) { if (u) - ci->bi->Part(ci->c, "UNASSIGN from " + u->nick); + ci->GetBot()->Part(ci->c, "UNASSIGN from " + u->nick); else - ci->bi->Part(ci->c); + ci->GetBot()->Part(ci->c); } - ci->bi = NULL; - this->channels->erase(ci); + ci->SetBot(nullptr); } -unsigned BotInfo::GetChannelCount() const +unsigned ServiceBot::GetChannelCount() const { - return this->channels->size(); + return GetChannels().size(); } -void BotInfo::Join(Channel *c, ChannelStatus *status) +void ServiceBot::Join(Channel *c, ChannelStatus *status) { if (c->FindUser(this) != NULL) return; c->JoinUser(this, status); if (IRCD) - IRCD->SendJoin(this, c, status); + IRCD->Send<messages::Join>(this, c, status); - FOREACH_MOD(OnJoinChannel, (this, c)); + EventManager::Get()->Dispatch(&Event::JoinChannel::OnJoinChannel, this, c); } -void BotInfo::Join(const Anope::string &chname, ChannelStatus *status) +void ServiceBot::Join(const Anope::string &chname, ChannelStatus *status) { bool c; return this->Join(Channel::FindOrCreate(chname, c), status); } -void BotInfo::Part(Channel *c, const Anope::string &reason) +void ServiceBot::Part(Channel *c, const Anope::string &reason) { if (c->FindUser(this) == NULL) return; - FOREACH_MOD(OnPrePartChannel, (this, c)); + EventManager::Get()->Dispatch(&Event::PrePartChannel::OnPrePartChannel, this, c); - IRCD->SendPart(this, c, "%s", !reason.empty() ? reason.c_str() : ""); + IRCD->SendPart(this, c, reason); c->DeleteUser(this); - FOREACH_MOD(OnPartChannel, (this, c, c->name, reason)); + EventManager::Get()->Dispatch(&Event::PartChannel::OnPartChannel, this, c, c->name, reason); } -void BotInfo::OnMessage(User *u, const Anope::string &message) +void ServiceBot::OnMessage(User *u, const Anope::string &message) { if (this->commands.empty()) return; @@ -232,16 +196,16 @@ void BotInfo::OnMessage(User *u, const Anope::string &message) Command::Run(source, message); } -CommandInfo& BotInfo::SetCommand(const Anope::string &cname, const Anope::string &sname, const Anope::string &permission) +CommandInfo& ServiceBot::SetCommand(const Anope::string &cname, const Anope::string &sname, const Anope::string &permission) { - CommandInfo ci; + CommandInfo &ci = this->commands[cname]; ci.name = sname; + ci.cname = cname; ci.permission = permission; - this->commands[cname] = ci; - return this->commands[cname]; + return ci; } -CommandInfo *BotInfo::GetCommand(const Anope::string &cname) +CommandInfo *ServiceBot::GetCommand(const Anope::string &cname) { CommandInfo::map::iterator it = this->commands.find(cname); if (it != this->commands.end()) @@ -249,30 +213,96 @@ CommandInfo *BotInfo::GetCommand(const Anope::string &cname) return NULL; } -BotInfo* BotInfo::Find(const Anope::string &nick, bool nick_only) +CommandInfo *ServiceBot::FindCommand(const Anope::string &service) { - if (!nick_only && IRCD != NULL && IRCD->RequiresID) + for (auto& it : commands) { - botinfo_map::iterator it = BotListByUID->find(nick); - if (it != BotListByUID->end()) - { - BotInfo *bi = it->second; - bi->QueueUpdate(); - return bi; - } - - if (IRCD->AmbiguousID) - return NULL; + CommandInfo &ci = it.second; + + if (ci.name == service) + return &ci; } - botinfo_map::iterator it = BotListByNick->find(nick); - if (it != BotListByNick->end()) + return nullptr; +} + +ServiceBot* ServiceBot::Find(const Anope::string &nick, bool nick_only) +{ + User *u = User::Find(nick, nick_only); + if (u && u->type == UserType::BOT) + return anope_dynamic_static_cast<ServiceBot *>(u); + return nullptr; +} + +void BotInfo::Delete() +{ + if (bot) { - BotInfo *bi = it->second; - bi->QueueUpdate(); - return bi; + ServiceBot *b = bot; + bot = nullptr; + delete b; } - return NULL; + return Serialize::Object::Delete(); +} + +void BotInfo::SetCreated(const time_t &t) +{ + Set(&BotInfoType::created, t); +} + +time_t BotInfo::GetCreated() +{ + return Get(&BotInfoType::created); +} + +void BotInfo::SetOperOnly(const bool &b) +{ + Set(&BotInfoType::operonly, b); +} + +bool BotInfo::GetOperOnly() +{ + return Get(&BotInfoType::operonly); +} + +void BotInfo::SetNick(const Anope::string &n) +{ + Set(&BotInfoType::nick, n); +} + +Anope::string BotInfo::GetNick() +{ + return Get(&BotInfoType::nick); +} + +void BotInfo::SetUser(const Anope::string &u) +{ + Set(&BotInfoType::user, u); +} + +Anope::string BotInfo::GetUser() +{ + return Get(&BotInfoType::user); +} + +void BotInfo::SetHost(const Anope::string &h) +{ + Set(&BotInfoType::host, h); +} + +Anope::string BotInfo::GetHost() +{ + return Get(&BotInfoType::host); +} + +void BotInfo::SetRealName(const Anope::string &r) +{ + Set(&BotInfoType::realname, r); +} + +Anope::string BotInfo::GetRealName() +{ + return Get(&BotInfoType::realname); } diff --git a/src/channels.cpp b/src/channels.cpp index 3d824f0d8..bf5b22183 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -1,65 +1,63 @@ -/* Channel-handling routines. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "channels.h" -#include "regchannel.h" #include "logger.h" #include "modules.h" #include "users.h" -#include "bots.h" #include "servers.h" #include "protocol.h" #include "users.h" #include "config.h" -#include "access.h" #include "sockets.h" #include "language.h" #include "uplink.h" +#include "event.h" +#include "modules/chanserv.h" channel_map ChannelList; std::vector<Channel *> Channel::deleting; Channel::Channel(const Anope::string &nname, time_t ts) + : logger(this) { if (nname.empty()) throw CoreException("A channel without a name ?"); this->name = nname; - this->creation_time = ts; - this->syncing = this->botchannel = false; - this->server_modetime = this->chanserv_modetime = 0; - this->server_modecount = this->chanserv_modecount = this->bouncy_modes = this->topic_ts = this->topic_time = 0; - - this->ci = ChannelInfo::Find(this->name); - if (this->ci) - this->ci->c = this; if (Me && Me->IsSynced()) - Log(NULL, this, "create"); + logger.Category("create").Log("Channel {0} was created", this->GetName()); - FOREACH_MOD(OnChannelCreate, (this)); + EventManager::Get()->Dispatch(&Event::ChannelCreate::OnChannelCreate, this); } Channel::~Channel() { - UnsetExtensibles(); - - FOREACH_MOD(OnChannelDelete, (this)); + EventManager::Get()->Dispatch(&Event::ChannelDelete::OnChannelDelete, this); ModeManager::StackerDel(this); if (Me && Me->IsSynced()) - Log(NULL, this, "destroy"); + logger.Category("destroy").Log("Channel {0} was destroyed", this->GetName()); if (this->ci) this->ci->c = NULL; @@ -67,6 +65,11 @@ Channel::~Channel() ChannelList.erase(this->name); } +const Anope::string &Channel::GetName() const +{ + return name; +} + void Channel::Reset() { this->modes.clear(); @@ -90,7 +93,7 @@ void Channel::Reset() for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it) this->SetCorrectModes(it->second->user, true); - + // If the channel is syncing now, do not force a sync due to Reset(), as we are probably iterating over users in Message::SJoin // A sync will come soon if (!syncing) @@ -100,7 +103,7 @@ void Channel::Reset() void Channel::Sync() { syncing = false; - FOREACH_MOD(OnChannelSync, (this)); + EventManager::Get()->Dispatch(&Event::ChannelSync::OnChannelSync, this); CheckModes(); } @@ -112,13 +115,13 @@ void Channel::CheckModes() /* Check for mode bouncing */ if (this->chanserv_modetime == Anope::CurTime && this->server_modetime == Anope::CurTime && this->server_modecount >= 3 && this->chanserv_modecount >= 3) { - Log() << "Warning: unable to set modes on channel " << this->name << ". Are your servers' U:lines configured correctly?"; + Anope::Logger.Log("Warning: unable to set modes on channel {0}. Are your servers' U:lines configured correctly?", this->GetName()); this->bouncy_modes = 1; return; } Reference<Channel> ref = this; - FOREACH_MOD(OnCheckModes, (ref)); + EventManager::Get()->Dispatch(&Event::CheckModes::OnCheckModes, ref); } bool Channel::CheckDelete() @@ -128,13 +131,13 @@ bool Channel::CheckDelete() */ if (this->syncing) return false; - + /* Permanent channels never get deleted */ if (this->HasMode("PERM")) return false; EventReturn MOD_RESULT; - FOREACH_RESULT(OnCheckDelete, MOD_RESULT, (this)); + MOD_RESULT = EventManager::Get()->Dispatch(&Event::CheckDelete::OnCheckDelete, this); return MOD_RESULT != EVENT_STOP && this->users.empty(); } @@ -142,7 +145,7 @@ bool Channel::CheckDelete() ChanUserContainer* Channel::JoinUser(User *user, const ChannelStatus *status) { if (user->server && user->server->IsSynced()) - Log(user, this, "join"); + logger.Category("join").Log(_("{0} joined {1}"), user->GetMask(), this->GetName()); ChanUserContainer *cuc = new ChanUserContainer(user, this); user->chans[this] = cuc; @@ -156,16 +159,16 @@ ChanUserContainer* Channel::JoinUser(User *user, const ChannelStatus *status) void Channel::DeleteUser(User *user) { if (user->server && user->server->IsSynced() && !user->Quitting()) - Log(user, this, "leave"); + logger.Category("leave").Log(_("{0} left {1}"), user->GetMask(), this->GetName()); - FOREACH_MOD(OnLeaveChannel, (user, this)); + EventManager::Get()->Dispatch(&Event::LeaveChannel::OnLeaveChannel, user, this); ChanUserContainer *cu = user->FindChannel(this); if (!this->users.erase(user)) - Log(LOG_DEBUG) << "Channel::DeleteUser() tried to delete non-existent user " << user->nick << " from channel " << this->name; + logger.Debug("Channel::DeleteUser() tried to delete non-existent user {0} from channel {1}", user->GetMask(), this->GetName()); if (!user->chans.erase(this)) - Log(LOG_DEBUG) << "Channel::DeleteUser() tried to delete non-existent channel " << this->name << " from " << user->nick << "'s channel list"; + logger.Debug("Channel::DeleteUser() tried to delete non-existent channel {0} from channel list of user {1}", this->GetName(), user->GetMask()); delete cu; QueueForDeletion(); @@ -257,7 +260,7 @@ std::vector<Anope::string> Channel::GetModeList(const Anope::string &mname) return r; } -void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Anope::string &oparam, bool enforce_mlock) +void Channel::SetModeInternal(const MessageSource &setter, ChannelMode *ocm, const Anope::string &oparam, bool enforce_mlock) { if (!ocm) return; @@ -272,7 +275,7 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Ano { if (param.empty()) { - Log() << "Channel::SetModeInternal() mode " << cm->mchar << " with no parameter for channel " << this->name; + Anope::Logger.Log("Channel::SetModeInternal() mode {} with no parameter for channel {}", cm->mchar, this->GetName()); return; } @@ -280,18 +283,18 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Ano if (!u) { - Log() << "MODE " << this->name << " +" << cm->mchar << " for non-existent user " << param; + Anope::Logger.Debug("Mode +{0} for non-existent user {1} on channel {2}", cm->mchar, param, this->GetName()); return; } - Log(LOG_DEBUG) << "Setting +" << cm->mchar << " on " << this->name << " for " << u->nick; + Anope::Logger.Debug("Setting +{0} on {1} for {2}", cm->mchar, this->GetName(), u->GetMask()); /* Set the status on the user */ ChanUserContainer *cc = u->FindChannel(this); if (cc) cc->status.AddMode(cm->mchar); - FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, param)); + MOD_RESULT = EventManager::Get()->Dispatch(&Event::ChannelModeSet::OnChannelModeSet, this, setter, cm, param); /* Enforce secureops, etc */ if (enforce_mlock && MOD_RESULT != EVENT_STOP) @@ -308,17 +311,11 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Ano if (param.empty() && cm->type != MODE_REGULAR) { - Log() << "Channel::SetModeInternal() mode " << cm->mchar << " for " << this->name << " with no paramater, but is a param mode"; + Anope::Logger.Log("Channel::SetModeInternal() mode {0} for {1} with no paramater, but is a param mode", cm->mchar, this->name); return; } - if (cm->type == MODE_LIST) - { - ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm); - cml->OnAdd(this, param); - } - - FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, param)); + MOD_RESULT = EventManager::Get()->Dispatch(&Event::ChannelModeSet::OnChannelModeSet, this, setter, cm, param); /* Check if we should enforce mlock */ if (!enforce_mlock || MOD_RESULT == EVENT_STOP) @@ -327,7 +324,7 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Ano this->CheckModes(); } -void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *ocm, const Anope::string &oparam, bool enforce_mlock) +void Channel::RemoveModeInternal(const MessageSource &setter, ChannelMode *ocm, const Anope::string &oparam, bool enforce_mlock) { if (!ocm) return; @@ -342,27 +339,26 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *ocm, const { if (param.empty()) { - Log() << "Channel::RemoveModeInternal() mode " << cm->mchar << " with no parameter for channel " << this->name; + Anope::Logger.Log("Channel::RemoveModeInternal() mode {0} with no parameter for channel {1}", cm->mchar, this->GetName()); return; } - BotInfo *bi = BotInfo::Find(param); - User *u = bi ? bi : User::Find(param); + User *u = User::Find(param); if (!u) { - Log() << "Channel::RemoveModeInternal() MODE " << this->name << "-" << cm->mchar << " for non-existent user " << param; + Anope::Logger.Debug("Mode -{0} for non-existent user {1} on channel {2}", cm->mchar, param, this->GetName()); return; } - Log(LOG_DEBUG) << "Setting -" << cm->mchar << " on " << this->name << " for " << u->nick; + Anope::Logger.Debug("Setting -{0} on {1} for {2}", cm->mchar, this->GetName(), u->GetMask()); /* Remove the status on the user */ ChanUserContainer *cc = u->FindChannel(this); if (cc) cc->status.DelMode(cm->mchar); - FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm, param)); + MOD_RESULT = EventManager::Get()->Dispatch(&Event::ChannelModeUnset::OnChannelModeUnset, this, setter, cm, param); if (enforce_mlock && MOD_RESULT != EVENT_STOP) this->SetCorrectModes(u, false); @@ -381,14 +377,8 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *ocm, const } else this->modes.erase(cm->name); - - if (cm->type == MODE_LIST) - { - ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm); - cml->OnDel(this, param); - } - FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm, param)); + MOD_RESULT = EventManager::Get()->Dispatch(&Event::ChannelModeUnset::OnChannelModeUnset, this, setter, cm, param); if (cm->name == "PERM") { @@ -406,7 +396,7 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *ocm, const this->CheckModes(); } -void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, bool enforce_mlock) +void Channel::SetMode(User *bi, ChannelMode *cm, const Anope::string ¶m, bool enforce_mlock) { Anope::string wparam = param; if (!cm) @@ -455,16 +445,15 @@ void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, ChannelMode *wcm = cm->Wrap(wparam); ModeManager::StackerAdd(bi, this, wcm, true, wparam); - MessageSource ms(bi); - SetModeInternal(ms, wcm, wparam, enforce_mlock); + SetModeInternal(bi, wcm, wparam, enforce_mlock); } -void Channel::SetMode(BotInfo *bi, const Anope::string &mname, const Anope::string ¶m, bool enforce_mlock) +void Channel::SetMode(User *bi, const Anope::string &mname, const Anope::string ¶m, bool enforce_mlock) { SetMode(bi, ModeManager::FindChannelModeByName(mname), param, enforce_mlock); } -void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, bool enforce_mlock) +void Channel::RemoveMode(User *bi, ChannelMode *cm, const Anope::string ¶m, bool enforce_mlock) { if (!cm) return; @@ -509,11 +498,10 @@ void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶ ChannelMode *wcm = cm->Wrap(wparam); ModeManager::StackerAdd(bi, this, wcm, false, wparam); - MessageSource ms(bi); - RemoveModeInternal(ms, wcm, wparam, enforce_mlock); + RemoveModeInternal(bi, wcm, wparam, enforce_mlock); } -void Channel::RemoveMode(BotInfo *bi, const Anope::string &mname, const Anope::string ¶m, bool enforce_mlock) +void Channel::RemoveMode(User *bi, const Anope::string &mname, const Anope::string ¶m, bool enforce_mlock) { RemoveMode(bi, ModeManager::FindChannelModeByName(mname), param, enforce_mlock); } @@ -533,7 +521,7 @@ bool Channel::GetParam(const Anope::string &mname, Anope::string &target) const return false; } -void Channel::SetModes(BotInfo *bi, bool enforce_mlock, const char *cmodes, ...) +void Channel::SetModes(User *bi, bool enforce_mlock, const char *cmodes, ...) { char buf[BUFSIZE] = ""; va_list args; @@ -606,12 +594,12 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode, ; else if (ts > this->creation_time) { - Log(LOG_DEBUG) << "Dropping mode " << mode << " on " << this->name << ", " << ts << " > " << this->creation_time; + Anope::Logger.Debug("Dropping mode {0} on {1}, TS {2] > {3}", mode, this->GetName(), ts, this->creation_time); return; } else if (ts < this->creation_time) { - Log(LOG_DEBUG) << "Changing TS of " << this->name << " from " << this->creation_time << " to " << ts; + Anope::Logger.Debug("Changing TS of {0} from {1} to {2}", this->GetName(), this->creation_time, ts); this->creation_time = ts; this->Reset(); } @@ -649,7 +637,7 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode, cm = ModeManager::FindChannelModeByChar(m[i]); if (!cm) { - Log(LOG_DEBUG) << "Channel::SetModeInternal: Unknown mode char " << m[i]; + Anope::Logger.Debug("Channel::SetModeInternal: Unknown mode char {0}", m[i]); continue; } modestring += cm->mchar; @@ -692,7 +680,9 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode, this->RemoveModeInternal(source, cm, token, enforce_mlock); } else - Log() << "warning: Channel::SetModesInternal() received more modes requiring params than params, modes: " << mode; + { + Anope::Logger.Log("warning: Channel::SetModesInternal() received more modes requiring params than params, modes: {0}", mode); + } } if (!this_reference) @@ -710,10 +700,10 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode, } if (setter) - Log(setter, this, "mode") << modestring << paramstring; + logger.Category("mode").Log("{0} {1}", modestring, paramstring); else - Log(LOG_DEBUG) << source.GetName() << " is setting " << this->name << " to " << modestring << paramstring; - + logger.Debug("{0} is setting {1] to {2}{3}", source.GetName(), this->GetName(), modestring, paramstring); + if (enforce_mlock) this->CheckModes(); } @@ -734,58 +724,52 @@ bool Channel::MatchesList(User *u, const Anope::string &mode) return false; } -void Channel::KickInternal(const MessageSource &source, const Anope::string &nick, const Anope::string &reason) +bool Channel::KickInternal(const MessageSource &source, const Anope::string &nick, const Anope::string &reason) { User *sender = source.GetUser(); User *target = User::Find(nick); + if (!target) { - Log(LOG_DEBUG) << "Channel::KickInternal got a nonexistent user " << nick << " on " << this->name << ": " << reason; - return; + Anope::Logger.Debug("Channel::KickInternal got a nonexistent user {0} on {1}: {2}", nick, this->GetName(), reason); + return false; } if (sender) - Log(sender, this, "kick") << "kicked " << target->nick << " (" << reason << ")"; + logger.User(sender).Category("kick").Log(_("{0} kicked {1} from {2} ({3})"), sender->GetMask(), target->GetMask(), this->GetName(), reason); else - Log(target, this, "kick") << "was kicked by " << source.GetName() << " (" << reason << ")"; + logger.Category("kick").Log(_("{0} kicked {1} from {2} ({3})"), source.GetName(), target->GetMask(), this->GetName(), reason); Anope::string chname = this->name; ChanUserContainer *cu = target->FindChannel(this); if (cu == NULL) { - Log(LOG_DEBUG) << "Channel::KickInternal got kick for user " << target->nick << " from " << source.GetSource() << " who isn't on channel " << this->name; - return; + Anope::Logger.Debug("Kick for user {0} who is not in channel {1}", target->GetMask(), this->GetName()); + return false; } ChannelStatus status = cu->status; - FOREACH_MOD(OnPreUserKicked, (source, cu, reason)); + EventReturn MOD_RESULT = EventManager::Get()->Dispatch(&Event::PreUserKicked::OnPreUserKicked, source, cu, reason); + if ((sender && sender->server == Me) || source.GetServer() == Me) + if (MOD_RESULT == EVENT_STOP) + return false; + this->DeleteUser(target); - FOREACH_MOD(OnUserKicked, (source, target, this->name, status, reason)); + EventManager::Get()->Dispatch(&Event::UserKicked::OnUserKicked, source, target, this->name, status, reason); + return true; } -bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...) +bool Channel::Kick(User *source, User *u, const Anope::string &reason) { - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, reason); - vsnprintf(buf, BUFSIZE - 1, reason, args); - va_end(args); - /* Do not kick protected clients or Ulines */ if (u->IsProtected()) return false; - - if (bi == NULL) - bi = this->ci->WhoSends(); - EventReturn MOD_RESULT; - FOREACH_RESULT(OnBotKick, MOD_RESULT, (bi, this, u, buf)); - if (MOD_RESULT == EVENT_STOP) + if (!this->KickInternal(source, u->nick, reason)) return false; - IRCD->SendKick(bi, this, u, "%s", buf); - this->KickInternal(bi, u->nick, buf); + IRCD->SendKick(source, this, u, reason); return true; } @@ -796,9 +780,9 @@ void Channel::ChangeTopicInternal(User *u, const Anope::string &user, const Anop this->topic_ts = ts; this->topic_time = Anope::CurTime; - Log(LOG_DEBUG) << "Topic of " << this->name << " changed by " << this->topic_setter << " to " << newtopic; + Anope::Logger.Debug("Topic of {0} changed by {1} to {2}", this->GetName(), this->topic_setter, newtopic); - FOREACH_MOD(OnTopicUpdated, (u, this, user, this->topic)); + EventManager::Get()->Dispatch(&Event::TopicUpdated::OnTopicUpdated, u, this, user, this->topic); } void Channel::ChangeTopic(const Anope::string &user, const Anope::string &newtopic, time_t ts) @@ -807,30 +791,30 @@ void Channel::ChangeTopic(const Anope::string &user, const Anope::string &newtop this->topic_setter = user; this->topic_ts = ts; - IRCD->SendTopic(this->ci->WhoSends(), this); + IRCD->Send<messages::Topic>(this->ci ? this->ci->WhoSends() : Config->GetClient("ChanServ"), this, newtopic, ts, user); /* Now that the topic is set update the time set. This is *after* we set it so the protocol modules are able to tell the old last set time */ this->topic_time = Anope::CurTime; - FOREACH_MOD(OnTopicUpdated, (NULL, this, user, this->topic)); + EventManager::Get()->Dispatch(&Event::TopicUpdated::OnTopicUpdated, nullptr, this, user, this->topic); } void Channel::SetCorrectModes(User *user, bool give_modes) { if (user == NULL) return; - + if (!this->ci) return; - Log(LOG_DEBUG) << "Setting correct user modes for " << user->nick << " on " << this->name << " (" << (give_modes ? "" : "not ") << "giving modes)"; + Anope::Logger.Debug("Setting correct user modes for {0} on {1} ({2}giving modes)", user->nick, this->name, give_modes ? "" : "not "); - AccessGroup u_access = ci->AccessFor(user); + ChanServ::AccessGroup u_access = ci->AccessFor(user); /* Initially only take modes if the channel is being created by a non netmerge */ bool take_modes = this->syncing && user->server->IsSynced(); - FOREACH_MOD(OnSetCorrectModes, (user, this, u_access, give_modes, take_modes)); + EventManager::Get()->Dispatch(&Event::SetCorrectModes::OnSetCorrectModes, user, this, u_access, give_modes, take_modes); /* Never take modes from ulines */ if (user->server->IsULined()) @@ -857,7 +841,7 @@ void Channel::SetCorrectModes(User *user, bool give_modes) } } /* modes that have no privileges assigned shouldn't be removed (like operprefix, ojoin) */ - else if (take_modes && !has_priv && ci->GetLevel(cm->name + "ME") != ACCESS_INVALID && !u_access.HasPriv(cm->name + "ME")) + else if (take_modes && !has_priv && ci->GetLevel(cm->name + "ME") != ChanServ::ACCESS_INVALID && !u_access.HasPriv(cm->name + "ME")) { /* Only remove modes if they are > voice */ if (cm->name == "VOICE") @@ -901,20 +885,19 @@ bool Channel::CheckKick(User *user) Anope::string mask, reason; - EventReturn MOD_RESULT; - FOREACH_RESULT(OnCheckKick, MOD_RESULT, (user, this, mask, reason)); + EventReturn MOD_RESULT = EventManager::Get()->Dispatch(&Event::CheckKick::OnCheckKick, user, this, mask, reason); if (MOD_RESULT != EVENT_STOP) return false; - + if (mask.empty()) mask = this->ci->GetIdealBan(user); if (reason.empty()) - reason = Language::Translate(user->Account(), CHAN_NOT_ALLOWED_TO_JOIN); + reason = Language::Translate(user->Account(), _("You are not permitted to be on this channel.")); - Log(LOG_DEBUG) << "Autokicking " << user->nick << " (" << mask << ") from " << this->name; + Anope::Logger.Debug("Autokicking {0} ({1}) from {2}", user->nick, mask, this->name); this->SetMode(NULL, "BAN", mask); - this->Kick(NULL, user, "%s", reason.c_str()); + this->Kick(NULL, user, reason); return true; } diff --git a/src/command.cpp b/src/command.cpp index 35a99eb80..02decd1b7 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -1,9 +1,21 @@ /* + * Anope IRC Services * - * (C) 2008-2011 Robin Burchell <w00t@inspircd.org> - * (C) 2008-2016 Anope Team <team@anope.org> + * Copyright (C) 2008-2011 Robin Burchell <w00t@inspircd.org> + * Copyright (C) 2008-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -11,14 +23,20 @@ #include "users.h" #include "language.h" #include "config.h" -#include "bots.h" #include "opertype.h" -#include "access.h" -#include "regchannel.h" #include "channels.h" - -CommandSource::CommandSource(const Anope::string &n, User *user, NickCore *core, CommandReply *r, BotInfo *bi) : nick(n), u(user), nc(core), reply(r), - c(NULL), service(bi) +#include "event.h" +#include "bots.h" +#include "protocol.h" +#include "modules/botserv.h" +#include "modules/chanserv.h" + +CommandSource::CommandSource(const Anope::string &n, User *user, NickServ::Account *core, CommandReply *r, ServiceBot *bi) + : nick(n) + , u(user) + , nc(core) + , reply(r) + , service(bi) { } @@ -32,25 +50,63 @@ User *CommandSource::GetUser() return this->u; } -NickCore *CommandSource::GetAccount() +NickServ::Account *CommandSource::GetAccount() { return this->nc; } -AccessGroup CommandSource::AccessFor(ChannelInfo *ci) +Anope::string CommandSource::GetSource() +{ + if (u) + if (nc) + return this->u->GetMask() + " (" + this->nc->GetDisplay() + ")"; + else + return this->u->GetMask(); + else if (nc) + return nc->GetDisplay(); + else + return this->nick; +} + +const Anope::string &CommandSource::GetCommand() const +{ + return this->command.cname; +} + +void CommandSource::SetCommand(const Anope::string &command) +{ + this->command.cname = command; +} + +const Anope::string &CommandSource::GetPermission() const +{ + return this->command.permission; +} + +const CommandInfo &CommandSource::GetCommandInfo() const +{ + return this->command; +} + +void CommandSource::SetCommandInfo(const CommandInfo &ci) +{ + this->command = ci; +} + +ChanServ::AccessGroup CommandSource::AccessFor(ChanServ::Channel *ci) { if (this->u) return ci->AccessFor(this->u); else if (this->nc) return ci->AccessFor(this->nc); else - return AccessGroup(); + return ChanServ::AccessGroup(); } -bool CommandSource::IsFounder(ChannelInfo *ci) +bool CommandSource::IsFounder(ChanServ::Channel *ci) { if (this->u) - return ::IsFounder(this->u, ci); + return ci->IsFounder(this->u); else if (this->nc) return *this->nc == ci->GetFounder(); return false; @@ -60,8 +116,10 @@ bool CommandSource::HasCommand(const Anope::string &cmd) { if (this->u) return this->u->HasCommand(cmd); - else if (this->nc && this->nc->o) - return this->nc->o->ot->HasCommand(cmd); + + if (this->nc && this->nc->GetOper()) + return this->nc->GetOper()->HasCommand(cmd); + return false; } @@ -69,8 +127,10 @@ bool CommandSource::HasPriv(const Anope::string &cmd) { if (this->u) return this->u->HasPriv(cmd); - else if (this->nc && this->nc->o) - return this->nc->o->ot->HasPriv(cmd); + + if (this->nc && this->nc->GetOper()) + return this->nc->GetOper()->HasPriv(cmd); + return false; } @@ -79,7 +139,7 @@ bool CommandSource::IsServicesOper() if (this->u) return this->u->IsServicesOper(); else if (this->nc) - return this->nc->IsServicesOper(); + return this->nc->GetOper() != nullptr; return false; } @@ -88,23 +148,31 @@ bool CommandSource::IsOper() if (this->u) return this->u->HasMode("OPER"); else if (this->nc) - return this->nc->IsServicesOper(); + return this->nc->GetOper() != nullptr; return false; } -void CommandSource::Reply(const char *message, ...) +bool CommandSource::HasOverridePriv(const Anope::string &priv) { - va_list args; - char buf[4096]; // Messages can be really big. + if (!HasPriv(priv)) + return false; - const char *translated_message = Language::Translate(this->nc, message); + override = true; + return true; +} - va_start(args, message); - vsnprintf(buf, sizeof(buf), translated_message, args); +bool CommandSource::HasOverrideCommand(const Anope::string &priv) +{ + if (!HasCommand(priv)) + return false; - this->Reply(Anope::string(buf)); + override = true; + return true; +} - va_end(args); +bool CommandSource::IsOverride() const +{ + return override; } void CommandSource::Reply(const Anope::string &message) @@ -114,15 +182,14 @@ void CommandSource::Reply(const Anope::string &message) sepstream sep(translated_message, '\n', true); Anope::string tok; while (sep.GetToken(tok)) - this->reply->SendMessage(this->service, tok); + this->reply->SendMessage(*this->service, tok); } -Command::Command(Module *o, const Anope::string &sname, size_t minparams, size_t maxparams) : Service(o, "Command", sname), max_params(maxparams), min_params(minparams), module(o) -{ - allow_unregistered = require_user = false; -} - -Command::~Command() +Command::Command(Module *o, const Anope::string &sname, size_t minparams, size_t maxparams) : Service(o, NAME, sname) + , max_params(maxparams) + , min_params(minparams) + , module(o) + , logger(this) { } @@ -146,13 +213,13 @@ void Command::SendSyntax(CommandSource &source) Anope::string s = Language::Translate(source.GetAccount(), _("Syntax")); if (!this->syntax.empty()) { - source.Reply("%s: \002%s %s\002", s.c_str(), source.command.c_str(), Language::Translate(source.GetAccount(), this->syntax[0].c_str())); + source.Reply("{0}: \002{1} {2}\002", s, source.GetCommand(), Language::Translate(source.GetAccount(), this->syntax[0].c_str())); Anope::string spaces(s.length(), ' '); for (unsigned i = 1, j = this->syntax.size(); i < j; ++i) - source.Reply("%s \002%s %s\002", spaces.c_str(), source.command.c_str(), Language::Translate(source.GetAccount(), this->syntax[i].c_str())); + source.Reply("{0} \002{1} {2}\002", spaces, source.GetCommand(), Language::Translate(source.GetAccount(), this->syntax[i].c_str())); } else - source.Reply("%s: \002%s\002", s.c_str(), source.command.c_str()); + source.Reply("{0}: \002{1}\002", s, source.GetCommand()); } bool Command::AllowUnregistered() const @@ -182,7 +249,7 @@ const Anope::string Command::GetDesc(CommandSource &) const void Command::OnServHelp(CommandSource &source) { - source.Reply(" %-14s %s", source.command.c_str(), Language::Translate(source.nc, this->GetDesc(source).c_str())); + source.Reply(Anope::printf(" %-14s %s", source.GetCommand().c_str(), Language::Translate(source.nc, this->GetDesc(source).c_str()))); } bool Command::OnHelp(CommandSource &source, const Anope::string &subcommand) { return false; } @@ -192,7 +259,7 @@ void Command::OnSyntaxError(CommandSource &source, const Anope::string &subcomma this->SendSyntax(source); bool has_help = source.service->commands.find("HELP") != source.service->commands.end(); if (has_help) - source.Reply(MORE_INFO, Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), source.command.c_str()); + source.Reply(_("\002{0}{1} HELP {2}\002 for more information."), Config->StrictPrivmsg, source.service->nick, source.GetCommand()); } void Command::Run(CommandSource &source, const Anope::string &message) @@ -217,21 +284,21 @@ void Command::Run(CommandSource &source, const Anope::string &message) if (it == source.service->commands.end()) { if (has_help) - source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->StrictPrivmsg.c_str(), source.service->nick.c_str()); + source.Reply(_("Unknown command \002{0}\002. \"{1}{2} HELP\" for help."), message, Config->StrictPrivmsg, source.service->nick); else - source.Reply(_("Unknown command \002%s\002."), message.c_str()); + source.Reply(_("Unknown command \002{0}\002."), message); return; } const CommandInfo &info = it->second; - ServiceReference<Command> c("Command", info.name); + ServiceReference<Command> c(info.name); if (!c) { if (has_help) - source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->StrictPrivmsg.c_str(), source.service->nick.c_str()); + source.Reply(_("Unknown command \002{0}\002. \"{1}{2} HELP\" for help."), message, Config->StrictPrivmsg, source.service->nick); else - source.Reply(_("Unknown command \002%s\002."), message.c_str()); - Log(source.service) << "Command " << it->first << " exists on me, but its service " << info.name << " was not found!"; + source.Reply(_("Unknown command \002{0}\002."), message); + source.service->logger.Log("Command {0} exists on me, but its service {1} was not found!", it->first, info.name); return; } @@ -255,17 +322,15 @@ void Command::Run(CommandSource &source, const Anope::string &cmdname, const Com // Command requires registered users only if (!this->AllowUnregistered() && !source.nc) { - source.Reply(NICK_IDENTIFY_REQUIRED); + source.Reply(_("Password authentication required for that command.")); if (source.GetUser()) - Log(LOG_NORMAL, "access_denied_unreg", source.service) << "Access denied for unregistered user " << source.GetUser()->GetMask() << " with command " << cmdname; + Anope::Logger.User(source.service).Category("access_denied_unreg").Log(_("Access denied for unregistered user {0} with command {1}"), source.GetUser()->GetMask(), cmdname); return; } - source.command = cmdname; - source.permission = info.permission; + source.SetCommandInfo(info); - EventReturn MOD_RESULT; - FOREACH_RESULT(OnPreCommand, MOD_RESULT, (source, this, params)); + EventReturn MOD_RESULT = EventManager::Get()->Dispatch(&Event::PreCommand::OnPreCommand, source, this, params); if (MOD_RESULT == EVENT_STOP) return; @@ -278,23 +343,30 @@ void Command::Run(CommandSource &source, const Anope::string &cmdname, const Com // If the command requires a permission, and they aren't registered or don't have the required perm, DENIED if (!info.permission.empty() && !source.HasCommand(info.permission)) { - source.Reply(ACCESS_DENIED); + if (!source.IsOper()) + source.Reply(_("Access denied. You are not a Services Operator.")); + else + source.Reply(_("Access denied. You do not have access to command \002{0}\002."), info.permission); if (source.GetUser()) - Log(LOG_NORMAL, "access_denied", source.service) << "Access denied for user " << source.GetUser()->GetMask() << " with command " << cmdname; + Anope::Logger.User(source.service).Category("access_denied").Log(_("Access denied for user {0} with command {1}"), source.GetUser()->GetMask(), cmdname); return; } this->Execute(source, params); - FOREACH_MOD(OnPostCommand, (source, this, params)); + EventManager::Get()->Dispatch(&Event::PostCommand::OnPostCommand, source, this, params); } -bool Command::FindCommandFromService(const Anope::string &command_service, BotInfo* &bot, Anope::string &name) +bool Command::FindCommandFromService(const Anope::string &command_service, ServiceBot* &bot, Anope::string &name) { bot = NULL; - for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) + for (std::pair<Anope::string, User *> p : UserListByNick) { - BotInfo *bi = it->second; + User *u = p.second; + if (u->type != UserType::BOT) + continue; + + ServiceBot *bi = anope_dynamic_static_cast<ServiceBot *>(u); for (CommandInfo::map::const_iterator cit = bi->commands.begin(), cit_end = bi->commands.end(); cit != cit_end; ++cit) { @@ -309,7 +381,7 @@ bool Command::FindCommandFromService(const Anope::string &command_service, BotIn return true; } } - + return false; } diff --git a/src/config.cpp b/src/config.cpp index e821ac099..c2306b29d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,25 +1,37 @@ -/* Configuration file handling. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "config.h" -#include "bots.h" -#include "access.h" #include "opertype.h" #include "channels.h" #include "hashcomp.h" +#include "event.h" +#include "bots.h" +#include "modules.h" +#include "servers.h" +#include "protocol.h" +#include "modules/nickserv.h" using namespace Configuration; -File ServicesConf("services.conf", false); // Services configuration file name +File ServicesConf("anope.conf", false); // Services configuration file name Conf *Config = NULL; Block::Block(const Anope::string &n) : name(n), linenum(-1) @@ -33,47 +45,37 @@ const Anope::string &Block::GetName() const int Block::CountBlock(const Anope::string &bname) { - if (!this) - return 0; - return blocks.count(bname); } +Block* Block::GetBlock(const Anope::string &bname) +{ + auto it = blocks.find(bname); + + if (it != blocks.end()) + return &it->second; + + blocks.emplace(bname, bname); + return GetBlock(bname); +} + Block* Block::GetBlock(const Anope::string &bname, int num) { - if (!this) - return NULL; - std::pair<block_map::iterator, block_map::iterator> it = blocks.equal_range(bname); for (int i = 0; it.first != it.second; ++it.first, ++i) if (i == num) return &it.first->second; - return NULL; -} - -bool Block::Set(const Anope::string &tag, const Anope::string &value) -{ - if (!this) - return false; - - items[tag] = value; - return true; + return nullptr; } const Block::item_map* Block::GetItems() const { - if (this) - return &items; - else - return NULL; + return &items; } -template<> const Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const +template<> Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const { - if (!this) - return def; - Anope::map<Anope::string>::const_iterator it = items.find(tag); if (it != items.end()) return it->second; @@ -83,15 +85,41 @@ template<> const Anope::string Block::Get(const Anope::string &tag, const Anope: template<> time_t Block::Get(const Anope::string &tag, const Anope::string &def) const { - return Anope::DoTime(Get<const Anope::string>(tag, def)); + return Anope::DoTime(Get<Anope::string>(tag, def)); } template<> bool Block::Get(const Anope::string &tag, const Anope::string &def) const { - const Anope::string &str = Get<const Anope::string>(tag, def); + const Anope::string &str = Get<Anope::string>(tag, def); return !str.empty() && !str.equals_ci("no") && !str.equals_ci("off") && !str.equals_ci("false") && !str.equals_ci("0"); } +template<> unsigned int Block::Get(const Anope::string &tag, const Anope::string &def) const +{ + const Anope::string &str = Get<Anope::string>(tag, def); + std::size_t pos = str.length(); + unsigned long l; + + try + { + l = std::stoul(str.str(), &pos, 0); + } + catch (...) + { + return 0; + } + + if (pos != str.length()) + return 0; + + return l; +} + +template<> void Block::Set(const Anope::string &tag, const Anope::string &value) +{ + items[tag] = value; +} + static void ValidateNotEmpty(const Anope::string &block, const Anope::string &name, const Anope::string &value) { if (value.empty()) @@ -121,14 +149,17 @@ Conf::Conf() : Block("") { Block *include = this->GetBlock("include", i); - const Anope::string &type = include->Get<const Anope::string>("type"), - &file = include->Get<const Anope::string>("name"); + const Anope::string &type = include->Get<Anope::string>("type"), + &file = include->Get<Anope::string>("name"); + + ValidateNotEmpty("include", "name", file); File f(file, type == "executable"); this->LoadConf(f); } - FOREACH_MOD(OnReload, (this)); + for (Module *m : ModuleManager::Modules) + m->OnReload(this); /* Check for modified values that aren't allowed to be modified */ if (Config) @@ -147,20 +178,21 @@ Conf::Conf() : Block("") {"networkinfo", "userlen"}, {"networkinfo", "hostlen"}, {"networkinfo", "chanlen"}, + {"options", "casemap"}, }; for (unsigned i = 0; i < sizeof(noreload) / sizeof(noreload[0]); ++i) - if (this->GetBlock(noreload[i].block)->Get<const Anope::string>(noreload[i].name) != Config->GetBlock(noreload[i].block)->Get<const Anope::string>(noreload[i].name)) + if (this->GetBlock(noreload[i].block)->Get<Anope::string>(noreload[i].name) != Config->GetBlock(noreload[i].block)->Get<Anope::string>(noreload[i].name)) throw ConfigException("<" + noreload[i].block + ":" + noreload[i].name + "> can not be modified once set"); } Block *serverinfo = this->GetBlock("serverinfo"), *options = this->GetBlock("options"), *mail = this->GetBlock("mail"), *networkinfo = this->GetBlock("networkinfo"); - ValidateNotEmpty("serverinfo", "name", serverinfo->Get<const Anope::string>("name")); - ValidateNotEmpty("serverinfo", "description", serverinfo->Get<const Anope::string>("description")); - ValidateNotEmpty("serverinfo", "pid", serverinfo->Get<const Anope::string>("pid")); - ValidateNotEmpty("serverinfo", "motd", serverinfo->Get<const Anope::string>("motd")); + ValidateNotEmpty("serverinfo", "name", serverinfo->Get<Anope::string>("name")); + ValidateNotEmpty("serverinfo", "description", serverinfo->Get<Anope::string>("description")); + ValidateNotEmpty("serverinfo", "pid", serverinfo->Get<Anope::string>("pid")); + ValidateNotEmpty("serverinfo", "motd", serverinfo->Get<Anope::string>("motd")); ValidateNotZero("options", "readtimeout", options->Get<time_t>("readtimeout")); ValidateNotZero("options", "warningtimeout", options->Get<time_t>("warningtimeout")); @@ -170,13 +202,13 @@ Conf::Conf() : Block("") ValidateNotZero("networkinfo", "hostlen", networkinfo->Get<unsigned>("hostlen")); ValidateNotZero("networkinfo", "chanlen", networkinfo->Get<unsigned>("chanlen")); - spacesepstream(options->Get<const Anope::string>("ulineservers")).GetTokens(this->Ulines); + spacesepstream(options->Get<Anope::string>("ulineservers")).GetTokens(this->Ulines); if (mail->Get<bool>("usemail")) { Anope::string check[] = { "sendmailpath", "sendfrom", "registration_subject", "registration_message", "emailchange_subject", "emailchange_message", "memo_subject", "memo_message" }; for (unsigned i = 0; i < sizeof(check) / sizeof(Anope::string); ++i) - ValidateNotEmpty("mail", check[i], mail->Get<const Anope::string>(check[i])); + ValidateNotEmpty("mail", check[i], mail->Get<Anope::string>(check[i])); } this->ReadTimeout = options->Get<time_t>("readtimeout"); @@ -185,21 +217,42 @@ Conf::Conf() : Block("") this->StrictPrivmsg = !UseStrictPrivmsg ? "/msg " : "/"; { std::vector<Anope::string> defaults; - spacesepstream(this->GetModule("nickserv")->Get<const Anope::string>("defaults")).GetTokens(defaults); + spacesepstream(this->GetModule("nickserv/main")->Get<Anope::string>("defaults")).GetTokens(defaults); this->DefPrivmsg = std::find(defaults.begin(), defaults.end(), "msg") != defaults.end(); } - this->DefLanguage = options->Get<const Anope::string>("defaultlanguage"); + this->DefLanguage = options->Get<Anope::string>("defaultlanguage"); this->TimeoutCheck = options->Get<time_t>("timeoutcheck"); this->NickChars = networkinfo->Get<Anope::string>("nick_chars"); + Anope::string locale = options->Get<Anope::string>("locale"); + Anope::string casemap = options->Get<Anope::string>("casemap"); + + if (locale.empty() == casemap.empty()) + throw ConfigException("One of options:locale and options:casemap must be set"); + + if (locale.empty()) + { + // load locale conf + File f(casemap + ".conf", false); + this->LoadConf(f); + } + else + { +#if Boost_FOUND + this->locale = new std::locale(Anope::locale::generate(locale.str())); +#else + throw ConfigException("Boost.Locale is not enabled, cannot use locale " + locale); +#endif + } + for (int i = 0; i < this->CountBlock("uplink"); ++i) { Block *uplink = this->GetBlock("uplink", i); - const Anope::string &host = uplink->Get<const Anope::string>("host"); + const Anope::string &host = uplink->Get<Anope::string>("host"); bool ipv6 = uplink->Get<bool>("ipv6"); int port = uplink->Get<int>("port"); - const Anope::string &password = uplink->Get<const Anope::string>("password"); + const Anope::string &password = uplink->Get<Anope::string>("password"); ValidateNotEmpty("uplink", "host", host); ValidateNotZero("uplink", "port", port); @@ -212,7 +265,7 @@ Conf::Conf() : Block("") { Block *module = this->GetBlock("module", i); - const Anope::string &modname = module->Get<const Anope::string>("name"); + const Anope::string &modname = module->Get<Anope::string>("name"); ValidateNotEmpty("module", "name", modname); @@ -223,11 +276,11 @@ Conf::Conf() : Block("") { Block *opertype = this->GetBlock("opertype", i); - const Anope::string &oname = opertype->Get<const Anope::string>("name"), - &modes = opertype->Get<const Anope::string>("modes"), - &inherits = opertype->Get<const Anope::string>("inherits"), - &commands = opertype->Get<const Anope::string>("commands"), - &privs = opertype->Get<const Anope::string>("privs"); + const Anope::string &oname = opertype->Get<Anope::string>("name"), + &modes = opertype->Get<Anope::string>("modes"), + &inherits = opertype->Get<Anope::string>("inherits"), + &commands = opertype->Get<Anope::string>("commands"), + &privs = opertype->Get<Anope::string>("privs"); ValidateNotEmpty("opertype", "name", oname); @@ -254,7 +307,7 @@ Conf::Conf() : Block("") if (ot2->GetName().equals_ci(str)) { - Log() << "Inheriting commands and privs from " << ot2->GetName() << " to " << ot->GetName(); + Anope::Logger.Log(_("Inheriting commands and privs from {0} to {1}"), ot2->GetName(), ot->GetName()); ot->Inherits(ot2); break; } @@ -264,125 +317,7 @@ Conf::Conf() : Block("") this->MyOperTypes.push_back(ot); } - for (int i = 0; i < this->CountBlock("oper"); ++i) - { - Block *oper = this->GetBlock("oper", i); - - const Anope::string &nname = oper->Get<const Anope::string>("name"), - &type = oper->Get<const Anope::string>("type"), - &password = oper->Get<const Anope::string>("password"), - &certfp = oper->Get<const Anope::string>("certfp"), - &host = oper->Get<const Anope::string>("host"), - &vhost = oper->Get<const Anope::string>("vhost"); - bool require_oper = oper->Get<bool>("require_oper"); - - ValidateNotEmpty("oper", "name", nname); - ValidateNotEmpty("oper", "type", type); - - OperType *ot = NULL; - for (unsigned j = 0; j < this->MyOperTypes.size(); ++j) - if (this->MyOperTypes[j]->GetName() == type) - ot = this->MyOperTypes[j]; - if (ot == NULL) - throw ConfigException("Oper block for " + nname + " has invalid oper type " + type); - - Oper *o = new Oper(nname, ot); - o->require_oper = require_oper; - o->password = password; - o->certfp = certfp; - spacesepstream(host).GetTokens(o->hosts); - o->vhost = vhost; - - this->Opers.push_back(o); - } - - for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) - it->second->conf = false; - for (int i = 0; i < this->CountBlock("service"); ++i) - { - Block *service = this->GetBlock("service", i); - - const Anope::string &nick = service->Get<const Anope::string>("nick"), - &user = service->Get<const Anope::string>("user"), - &host = service->Get<const Anope::string>("host"), - &gecos = service->Get<const Anope::string>("gecos"), - &modes = service->Get<const Anope::string>("modes"), - &channels = service->Get<const Anope::string>("channels"); - - ValidateNotEmpty("service", "nick", nick); - ValidateNotEmpty("service", "user", user); - ValidateNotEmpty("service", "host", host); - ValidateNotEmpty("service", "gecos", gecos); - ValidateNoSpaces("service", "channels", channels); - - BotInfo *bi = BotInfo::Find(nick, true); - if (!bi) - bi = new BotInfo(nick, user, host, gecos, modes); - bi->conf = true; - - std::vector<Anope::string> oldchannels = bi->botchannels; - bi->botchannels.clear(); - commasepstream sep(channels); - for (Anope::string token; sep.GetToken(token);) - { - bi->botchannels.push_back(token); - size_t ch = token.find('#'); - Anope::string chname, want_modes; - if (ch == Anope::string::npos) - chname = token; - else - { - want_modes = token.substr(0, ch); - chname = token.substr(ch); - } - bi->Join(chname); - Channel *c = Channel::Find(chname); - if (!c) - continue; // Can't happen - - c->botchannel = true; - - /* Remove all existing modes */ - ChanUserContainer *cu = c->FindUser(bi); - if (cu != NULL) - for (size_t j = 0; j < cu->status.Modes().length(); ++j) - c->RemoveMode(bi, ModeManager::FindChannelModeByChar(cu->status.Modes()[j]), bi->GetUID()); - /* Set the new modes */ - for (unsigned j = 0; j < want_modes.length(); ++j) - { - ChannelMode *cm = ModeManager::FindChannelModeByChar(want_modes[j]); - if (cm == NULL) - cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_modes[j])); - if (cm && cm->type == MODE_STATUS) - c->SetMode(bi, cm, bi->GetUID()); - } - } - for (unsigned k = 0; k < oldchannels.size(); ++k) - { - size_t ch = oldchannels[k].find('#'); - Anope::string chname = oldchannels[k].substr(ch != Anope::string::npos ? ch : 0); - - bool found = false; - for (unsigned j = 0; j < bi->botchannels.size(); ++j) - { - ch = bi->botchannels[j].find('#'); - Anope::string ochname = bi->botchannels[j].substr(ch != Anope::string::npos ? ch : 0); - - if (chname.equals_ci(ochname)) - found = true; - } - - if (found) - continue; - - Channel *c = Channel::Find(chname); - if (c) - { - c->botchannel = false; - bi->Part(c); - } - } - } + this->LoadBots(); for (int i = 0; i < this->CountBlock("log"); ++i) { @@ -394,38 +329,45 @@ Conf::Conf() : Block("") LogInfo l(logage, rawio, debug); - l.bot = BotInfo::Find(log->Get<const Anope::string>("bot", "Global"), true); - spacesepstream(log->Get<const Anope::string>("target")).GetTokens(l.targets); - spacesepstream(log->Get<const Anope::string>("source")).GetTokens(l.sources); - spacesepstream(log->Get<const Anope::string>("admin")).GetTokens(l.admin); - spacesepstream(log->Get<const Anope::string>("override")).GetTokens(l.override); - spacesepstream(log->Get<const Anope::string>("commands")).GetTokens(l.commands); - spacesepstream(log->Get<const Anope::string>("servers")).GetTokens(l.servers); - spacesepstream(log->Get<const Anope::string>("channels")).GetTokens(l.channels); - spacesepstream(log->Get<const Anope::string>("users")).GetTokens(l.users); - spacesepstream(log->Get<const Anope::string>("other")).GetTokens(l.normal); + l.bot = ServiceBot::Find(log->Get<Anope::string>("bot", "Global"), true); + spacesepstream(log->Get<Anope::string>("target")).GetTokens(l.targets); + spacesepstream(log->Get<Anope::string>("source")).GetTokens(l.sources); + spacesepstream(log->Get<Anope::string>("admin")).GetTokens(l.admin); + spacesepstream(log->Get<Anope::string>("override")).GetTokens(l.override); + spacesepstream(log->Get<Anope::string>("commands")).GetTokens(l.commands); + spacesepstream(log->Get<Anope::string>("servers")).GetTokens(l.servers); + spacesepstream(log->Get<Anope::string>("channels")).GetTokens(l.channels); + spacesepstream(log->Get<Anope::string>("users")).GetTokens(l.users); + spacesepstream(log->Get<Anope::string>("other")).GetTokens(l.normal); this->LogInfos.push_back(l); } - for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) - it->second->commands.clear(); + for (std::pair<Anope::string, User *> p : UserListByNick) + { + User *u = p.second; + if (u->type != UserType::BOT) + continue; + + ServiceBot *bi = anope_dynamic_static_cast<ServiceBot *>(u); + bi->commands.clear(); + } for (int i = 0; i < this->CountBlock("command"); ++i) { Block *command = this->GetBlock("command", i); - const Anope::string &service = command->Get<const Anope::string>("service"), - &nname = command->Get<const Anope::string>("name"), - &cmd = command->Get<const Anope::string>("command"), - &permission = command->Get<const Anope::string>("permission"), - &group = command->Get<const Anope::string>("group"); + const Anope::string &service = command->Get<Anope::string>("service"), + &nname = command->Get<Anope::string>("name"), + &cmd = command->Get<Anope::string>("command"), + &permission = command->Get<Anope::string>("permission"), + &group = command->Get<Anope::string>("group"); bool hide = command->Get<bool>("hide"); ValidateNotEmpty("command", "service", service); ValidateNotEmpty("command", "name", nname); ValidateNotEmpty("command", "command", cmd); - BotInfo *bi = this->GetClient(service); + ServiceBot *bi = this->GetClient(service); if (!bi) continue; @@ -434,26 +376,14 @@ Conf::Conf() : Block("") ci.hide = hide; } - PrivilegeManager::ClearPrivileges(); - for (int i = 0; i < this->CountBlock("privilege"); ++i) - { - Block *privilege = this->GetBlock("privilege", i); - - const Anope::string &nname = privilege->Get<const Anope::string>("name"), - &desc = privilege->Get<const Anope::string>("desc"); - int rank = privilege->Get<int>("rank"); - - PrivilegeManager::AddPrivilege(Privilege(nname, desc, rank)); - } - for (int i = 0; i < this->CountBlock("fantasy"); ++i) { Block *fantasy = this->GetBlock("fantasy", i); - const Anope::string &nname = fantasy->Get<const Anope::string>("name"), - &service = fantasy->Get<const Anope::string>("command"), - &permission = fantasy->Get<const Anope::string>("permission"), - &group = fantasy->Get<const Anope::string>("group"); + const Anope::string &nname = fantasy->Get<Anope::string>("name"), + &service = fantasy->Get<Anope::string>("command"), + &permission = fantasy->Get<Anope::string>("permission"), + &group = fantasy->Get<Anope::string>("group"); bool hide = fantasy->Get<bool>("hide"), prepend_channel = fantasy->Get<bool>("prepend_channel", "yes"); @@ -462,6 +392,7 @@ Conf::Conf() : Block("") CommandInfo &c = this->Fantasy[nname]; c.name = service; + c.cname = nname; c.permission = permission; c.group = group; c.hide = hide; @@ -472,8 +403,8 @@ Conf::Conf() : Block("") { Block *command_group = this->GetBlock("command_group", i); - const Anope::string &nname = command_group->Get<const Anope::string>("name"), - &description = command_group->Get<const Anope::string>("description"); + const Anope::string &nname = command_group->Get<Anope::string>("name"), + &description = command_group->Get<Anope::string>("description"); CommandGroup gr; gr.name = nname; @@ -482,64 +413,152 @@ Conf::Conf() : Block("") this->CommandGroups.push_back(gr); } - /* Below here can't throw */ + for (int i = 0; i < this->CountBlock("usermode"); ++i) + { + Block *usermode = this->GetBlock("usermode", i); - if (Config) - /* Clear existing conf opers */ - for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it) - { - NickCore *nc = it->second; - if (nc->o && std::find(Config->Opers.begin(), Config->Opers.end(), nc->o) != Config->Opers.end()) - nc->o = NULL; - } - /* Apply new opers */ - for (unsigned i = 0; i < this->Opers.size(); ++i) + Anope::string nname = usermode->Get<Anope::string>("name"), + character = usermode->Get<Anope::string>("character"); + bool oper_only = usermode->Get<bool>("oper_only"), + setable = usermode->Get<bool>("setable"), + param = usermode->Get<bool>("param"); + + ValidateNotEmpty("usermode", "name", nname); + + if (character.length() != 1) + throw ConfigException("Usermode character length must be 1"); + + Usermode um; + um.name = nname; + um.character = character[0]; + um.param = param; + um.oper_only = oper_only; + um.setable = setable; + + this->Usermodes.push_back(um); + } + + for (int i = 0; i < this->CountBlock("channelmode"); ++i) + { + Block *channelmode = this->GetBlock("channelmode", i); + + Anope::string nname = channelmode->Get<Anope::string>("name"), + character = channelmode->Get<Anope::string>("character"), + status = channelmode->Get<Anope::string>("status"), + param_regex = channelmode->Get<Anope::string>("param_regex"); + bool oper_only = channelmode->Get<bool>("oper_only"), + setable = channelmode->Get<bool>("setable"), + list = channelmode->Get<bool>("list"), + param = channelmode->Get<bool>("param"), + param_unset = channelmode->Get<bool>("param_unset", "yes"); + int level = channelmode->Get<int>("level"); + + ValidateNotEmpty("usermode", "name", nname); + + if (character.length() != 1) + throw ConfigException("Channelmode character length must be 1"); + + if (status.length() > 1) + throw ConfigException("Channelmode status must be at most one character"); + + if (list || !param_regex.empty() || !status.empty()) + param = true; + + Channelmode cm; + cm.name = nname; + cm.character = character[0]; + cm.status = !status.empty() ? status[0] : 0; + cm.param_regex = param_regex; + cm.oper_only = oper_only; + cm.setable = setable; + cm.list = list; + cm.param = param; + cm.param_unset = param_unset; + cm.level = level; + + this->Channelmodes.push_back(cm); + } + + for (int i = 0; i < this->CountBlock("casemap"); ++i) { - Oper *o = this->Opers[i]; + Block *casemap = this->GetBlock("casemap", i); - NickAlias *na = NickAlias::Find(o->name); - if (!na) - continue; + unsigned char upper = casemap->Get<unsigned int>("upper"), + lower = casemap->Get<unsigned int>("lower"); - if (!na->nc || na->nc->o) + if (!upper) { - // If the account is already an oper it might mean two oper blocks for the same nick, or - // something else has configured them as an oper (like a module) - continue; + Anope::string s = casemap->Get<Anope::string>("upper"); + if (s.length() == 1) + upper = s[0]; } - na->nc->o = o; - Log() << "Tied oper " << na->nc->display << " to type " << o->ot->GetName(); - } + if (!lower) + { + Anope::string s = casemap->Get<Anope::string>("lower"); + if (s.length() == 1) + lower = s[0]; + } - if (options->Get<const Anope::string>("casemap", "ascii") == "ascii") - Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype<char>()); - else if (options->Get<const Anope::string>("casemap") == "rfc1459") - Anope::casemap = std::locale(std::locale(), new Anope::rfc1459_ctype<char>()); - else - { - try + if (upper && lower) { - Anope::casemap = std::locale(options->Get<const Anope::string>("casemap").c_str()); + CaseMapUpper[lower] = CaseMapUpper[upper] = upper; + CaseMapLower[lower] = CaseMapLower[upper] = lower; } - catch (const std::runtime_error &) + } + + /* Below here can't throw */ + + /* Clear existing conf opers */ + if (Config) + { + for (int i = 0; i < Config->CountBlock("oper"); ++i) { - Log() << "Unknown casemap " << options->Get<const Anope::string>("casemap") << " - casemap not changed"; + Block *oper = Config->GetBlock("oper", i); + + const Anope::string &nname = oper->Get<Anope::string>("name"); + + Oper *o = Oper::Find(nname); + if (o != nullptr) + { + o->Delete(); + } } } - Anope::CaseMapRebuild(); /* Check the user keys */ if (!options->Get<unsigned>("seed")) - Log() << "Configuration option options:seed should be set. It's for YOUR safety! Remember that!"; + Anope::Logger.Log(_("Configuration option options:seed should be set. It's for YOUR safety! Remember that!")); + + /* check regexengine */ + const Anope::string ®ex_engine = options->Get<Anope::string>("regexengine"); + if (regex_engine == "ecmascript") + regex_flags = std::regex::ECMAScript; + else if (regex_engine == "basic") + regex_flags = std::regex::basic; + else if (regex_engine == "extended") + regex_flags = std::regex::extended; + else if (regex_engine == "awk") + regex_flags = std::regex::awk; + else if (regex_engine == "grep") + regex_flags = std::regex::grep; + else if (regex_engine == "egrep") + regex_flags = std::regex::egrep; + else + regex_flags = static_cast<std::basic_regex<char>::flag_type>(0); + /* always enable icase and optimize */ + if (regex_flags) + regex_flags |= std::regex::icase | std::regex::optimize; + + this->LineWrap = options->Get<unsigned>("linewrap", "200"); } Conf::~Conf() { for (unsigned i = 0; i < MyOperTypes.size(); ++i) delete MyOperTypes[i]; - for (unsigned i = 0; i < Opers.size(); ++i) - delete Opers[i]; + + delete locale; } void Conf::Post(Conf *old) @@ -552,35 +571,188 @@ void Conf::Post(Conf *old) if (std::find(old->ModulesAutoLoad.begin(), old->ModulesAutoLoad.end(), this->ModulesAutoLoad[i]) == old->ModulesAutoLoad.end()) ModuleManager::LoadModule(this->ModulesAutoLoad[i], NULL); - /* Apply opertype changes, as non-conf opers still point to the old oper types */ - for (unsigned i = Oper::opers.size(); i > 0; --i) + LoadOpers(); + ApplyBots(); + + ModeManager::Apply(old); + + for (BotInfo *bi : Serialize::GetObjects<BotInfo *>()) { - Oper *o = Oper::opers[i - 1]; + if (!bi->conf) + { + bi->Delete(); + continue; + } - /* Oper's type is in the old config, so update it */ - if (std::find(old->MyOperTypes.begin(), old->MyOperTypes.end(), o->ot) != old->MyOperTypes.end()) + for (int i = 0; i < bi->conf->CountBlock("channel"); ++i) { - OperType *ot = o->ot; - o->ot = NULL; + Block *channel = bi->conf->GetBlock("channel", i); - for (unsigned j = 0; j < MyOperTypes.size(); ++j) - if (ot->GetName() == MyOperTypes[j]->GetName()) - o->ot = MyOperTypes[j]; + const Anope::string &chname = channel->Get<Anope::string>("name"), + &modes = channel->Get<Anope::string>("modes"); - if (o->ot == NULL) + bi->bot->Join(chname); + + Channel *c = Channel::Find(chname); + if (!c) + continue; // Can't happen + + c->botchannel = true; + + /* Remove all existing modes */ + ChanUserContainer *cu = c->FindUser(bi->bot); + if (cu != NULL) + for (size_t j = 0; j < cu->status.Modes().length(); ++j) + c->RemoveMode(bi->bot, ModeManager::FindChannelModeByChar(cu->status.Modes()[j]), bi->bot->GetUID()); + /* Set the new modes */ + for (unsigned j = 0; j < modes.length(); ++j) { - /* Oper block has lost type */ - std::vector<Oper *>::iterator it = std::find(old->Opers.begin(), old->Opers.end(), o); - if (it != old->Opers.end()) - old->Opers.erase(it); + ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[j]); + if (cm == NULL) + cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(modes[j])); + if (cm && cm->type == MODE_STATUS) + c->SetMode(bi->bot, cm, bi->bot->GetUID()); + } + } + } +} + +void Conf::LoadBots() +{ + for (BotInfo *bi : Serialize::GetObjects<BotInfo *>()) + bi->conf = nullptr; + for (int i = 0; i < this->CountBlock("service"); ++i) + { + Block *service = this->GetBlock("service", i); - it = std::find(this->Opers.begin(), this->Opers.end(), o); - if (it != this->Opers.end()) - this->Opers.erase(it); + const Anope::string &nick = service->Get<Anope::string>("nick"), + &user = service->Get<Anope::string>("user"), + &host = service->Get<Anope::string>("host"), + &gecos = service->Get<Anope::string>("gecos"), + &modes = service->Get<Anope::string>("modes"), + &channels = service->Get<Anope::string>("channels"); - delete o; + ValidateNotEmpty("service", "nick", nick); + ValidateNotEmpty("service", "user", user); + ValidateNotEmpty("service", "host", host); + ValidateNotEmpty("service", "gecos", gecos); + ValidateNoSpaces("service", "channels", channels); + + if (User *u = User::Find(nick, true)) + { + if (u->type != UserType::BOT) + { + u->Kill(Me, "Nickname required by services"); } } + + ServiceBot *sb = ServiceBot::Find(nick, true); + if (!sb) + sb = new ServiceBot(nick, user, host, gecos, modes); + } +} + +void Conf::ApplyBots() +{ + /* Associate conf bots with db bots */ + for (BotInfo *bi : Serialize::GetObjects<BotInfo *>()) + { + ServiceBot *sb = ServiceBot::Find(bi->GetNick()); + + if (sb == nullptr) + continue; + + bi->bot = sb; + sb->bi = bi; + } + + /* Apply conf to conf bots */ + for (int i = 0; i < this->CountBlock("service"); ++i) + { + Block *service = this->GetBlock("service", i); + + const Anope::string &nick = service->Get<Anope::string>("nick"); + + for (BotInfo *bi : Serialize::GetObjects<BotInfo *>()) + if (bi->GetNick().equals_ci(nick)) + bi->conf = this; + } + + /* Create new bots for new conf bots */ + for (std::pair<Anope::string, User *> p : UserListByNick) + { + User *u = p.second; + if (u->type != UserType::BOT) + continue; + + ServiceBot *sb = anope_dynamic_static_cast<ServiceBot *>(u); + if (sb->bi != nullptr) + continue; + + sb->bi = Serialize::New<BotInfo *>(); + sb->bi->bot = sb; + + sb->bi->conf = this; + + sb->bi->SetNick(sb->nick); + sb->bi->SetUser(sb->GetIdent()); + sb->bi->SetHost(sb->host); + sb->bi->SetRealName(sb->realname); + sb->bi->SetCreated(Anope::CurTime); + } +} + +void Conf::LoadOpers() +{ + for (int i = 0; i < this->CountBlock("oper"); ++i) + { + Block *oper = this->GetBlock("oper", i); + + const Anope::string &nname = oper->Get<Anope::string>("name"), + &type = oper->Get<Anope::string>("type"), + &password = oper->Get<Anope::string>("password"), + &certfp = oper->Get<Anope::string>("certfp"), + &host = oper->Get<Anope::string>("host"), + &vhost = oper->Get<Anope::string>("vhost"); + bool require_oper = oper->Get<bool>("require_oper"); + + ValidateNotEmpty("oper", "name", nname); + ValidateNotEmpty("oper", "type", type); + + OperType *ot = NULL; + for (unsigned j = 0; j < this->MyOperTypes.size(); ++j) + if (this->MyOperTypes[j]->GetName() == type) + ot = this->MyOperTypes[j]; + if (ot == NULL) + { + Anope::Logger.Log(_("Oper block for {0} has invalid oper type {1}"), nname, type); + continue; + } + + Oper *o = Oper::Find(nname); + if (o == nullptr) + o = Serialize::New<Oper *>(); + + o->SetName(nname); + o->SetType(ot); + o->SetRequireOper(require_oper); + o->SetPassword(password); + o->SetCertFP(certfp); + o->SetHost(host); + o->SetVhost(vhost); + + Anope::Logger.Debug(_("Creating oper {0} of type {1}"), nname, ot->GetName()); + } + + /* Apply new opers */ + for (Oper *o : Serialize::GetObjects<Oper *>()) + { + NickServ::Nick *na = NickServ::FindNick(o->GetName()); + if (!na) + continue; + + na->GetAccount()->SetOper(o); + Anope::Logger.Log(_("Tied oper {0} to type {1}"), na->GetAccount()->GetDisplay(), o->GetType()->GetName()); } } @@ -588,7 +760,7 @@ Block *Conf::GetModule(Module *m) { if (!m) return NULL; - + return GetModule(m->name); } @@ -599,30 +771,37 @@ Block *Conf::GetModule(const Anope::string &mname) return it->second; Block* &block = modules[mname]; - + /* Search for the block */ for (std::pair<block_map::iterator, block_map::iterator> iters = blocks.equal_range("module"); iters.first != iters.second; ++iters.first) { Block *b = &iters.first->second; - if (b->Get<const Anope::string>("name") == mname) + if (b->Get<Anope::string>("name") == mname) { block = b; break; } } - return GetModule(mname); + if (block == nullptr) + { + /* not found, create new block */ + auto it2 = blocks.emplace(mname, mname); + block = &it2->second; + } + + return block; } -BotInfo *Conf::GetClient(const Anope::string &cname) +ServiceBot *Conf::GetClient(const Anope::string &cname) { Anope::map<Anope::string>::iterator it = bots.find(cname); if (it != bots.end()) - return BotInfo::Find(!it->second.empty() ? it->second : cname, true); + return ServiceBot::Find(!it->second.empty() ? it->second : cname, true); Block *block = GetModule(cname.lower()); - const Anope::string &client = block->Get<const Anope::string>("client"); + const Anope::string &client = block->Get<Anope::string>("client"); bots[cname] = client; return GetClient(cname); } @@ -635,7 +814,7 @@ Block *Conf::GetCommand(CommandSource &source) { Block *b = &iters.first->second; - if (b->Get<Anope::string>("name") == source.command) + if (b->Get<Anope::string>("name") == source.GetCommand()) return b; } @@ -720,18 +899,18 @@ void Conf::LoadConf(File &file) int linenumber = 0; bool in_word = false, in_quote = false, in_comment = false; - Log(LOG_DEBUG) << "Start to read conf " << file.GetName(); + Anope::Logger.Debug("Start to read conf {0}", file.GetName()); // Start reading characters... while (!file.End()) - { + { Anope::string line = file.Read(); ++linenumber; - + /* If this line is completely empty and we are in a quote, just append a newline */ if (line.empty() && in_quote) wordbuffer += "\n"; - for (unsigned c = 0, len = line.length(); c < len; ++c) + for (unsigned int c = 0, len = line.length(); c < len; ++c) { char ch = line[c]; if (in_quote) @@ -880,17 +1059,17 @@ void Conf::LoadConf(File &file) Block *b = block_stack.top(); if (b) - Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << b->name << "' '" << itemname << "' set to '" << wordbuffer << "'"; + Anope::Logger.Debug("ln {0} EOL: s='{1}' '{2}' set to '{3}'", linenumber, b->name, itemname, wordbuffer); /* Check defines */ for (int i = 0; i < this->CountBlock("define"); ++i) { Block *define = this->GetBlock("define", i); - const Anope::string &dname = define->Get<const Anope::string>("name"); + const Anope::string &dname = define->Get<Anope::string>("name"); if (dname == wordbuffer && define != b) - wordbuffer = define->Get<const Anope::string>("value"); + wordbuffer = define->Get<Anope::string>("value"); } if (b) diff --git a/src/event.cpp b/src/event.cpp new file mode 100644 index 000000000..8f59f9960 --- /dev/null +++ b/src/event.cpp @@ -0,0 +1,35 @@ +/* + * Anope IRC Services + * + * Copyright (C) 2014-2016 Adam <adam@anope.org> + * Copyright (C) 2016 Anope Team <team@anope.org> + * + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. + */ + +#include "services.h" +#include "event.h" + +EventManager *EventManager::eventManager = nullptr; + +void EventManager::Init() +{ + eventManager = new EventManager(); +} + +EventManager *EventManager::Get() +{ + return eventManager; +} + diff --git a/src/extensible.cpp b/src/extensible.cpp index 4079290ff..524d74be3 100644 --- a/src/extensible.cpp +++ b/src/extensible.cpp @@ -1,72 +1,45 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2013-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "extensible.h" -static std::set<ExtensibleBase *> extensible_items; - -ExtensibleBase::ExtensibleBase(Module *m, const Anope::string &n) : Service(m, "Extensible", n) +ExtensibleBase::ExtensibleBase(Module *m, const Anope::string &n) : ExtensibleBase(m, "Extensible", n) { - extensible_items.insert(this); } -ExtensibleBase::~ExtensibleBase() +ExtensibleBase::ExtensibleBase(Module *m, const Anope::string &t, const Anope::string &n) : Service(m, t, n) { - extensible_items.erase(this); } Extensible::~Extensible() { - UnsetExtensibles(); -} - -void Extensible::UnsetExtensibles() -{ while (!extension_items.empty()) (*extension_items.begin())->Unset(this); } -bool Extensible::HasExt(const Anope::string &name) const +bool Extensible::HasExtOK(const Anope::string &name) { ExtensibleRef<void *> ref(name); if (ref) return ref->HasExt(this); - Log(LOG_DEBUG) << "HasExt for nonexistent type " << name << " on " << static_cast<const void *>(this); + Anope::Logger.Debug("HasExt for nonexistent type {0} on {1}", name, static_cast<const void *>(this)); return false; } -void Extensible::ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) -{ - for (std::set<ExtensibleBase *>::iterator it = e->extension_items.begin(); it != e->extension_items.end(); ++it) - { - ExtensibleBase *eb = *it; - eb->ExtensibleSerialize(e, s, data); - } -} - -void Extensible::ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) -{ - for (std::set<ExtensibleBase *>::iterator it = extensible_items.begin(); it != extensible_items.end(); ++it) - { - ExtensibleBase *eb = *it; - eb->ExtensibleUnserialize(e, s, data); - } -} - -template<> -bool* Extensible::Extend(const Anope::string &name, const bool &what) -{ - ExtensibleRef<bool> ref(name); - if (ref) - return ref->Set(this); - - Log(LOG_DEBUG) << "Extend for non-existent type " << name << " on " << static_cast<void *>(this); - return NULL; -} - diff --git a/src/hashcomp.cpp b/src/hashcomp.cpp index 6374639d8..72e729eba 100644 --- a/src/hashcomp.cpp +++ b/src/hashcomp.cpp @@ -1,40 +1,46 @@ /* + * Anope IRC Services * - * (C) 2002-2011 InspIRCd Development Team - * (C) 2008-2016 Anope Team <team@anope.org> + * Copyright (C) 2002-2011 InspIRCd Development Team + * Copyright (C) 2008-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "hashcomp.h" #include "anope.h" +#include "config.h" -/* Case map in use by Anope */ -std::locale Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype<char>()); -/* Cache of the above case map, forced upper */ -static unsigned char case_map_upper[256], case_map_lower[256]; - -/* called whenever Anope::casemap is modified to rebuild the casemap cache */ -void Anope::CaseMapRebuild() -{ - const std::ctype<char> &ct = std::use_facet<std::ctype<char> >(Anope::casemap); - - for (unsigned i = 0; i < sizeof(case_map_upper); ++i) - { - case_map_upper[i] = ct.toupper(i); - case_map_lower[i] = ct.tolower(i); - } -} +#ifdef Boost_FOUND +#include <boost/locale.hpp> +#endif unsigned char Anope::tolower(unsigned char c) { - return case_map_lower[c]; + if (!Config || !Config->CaseMapLower[c]) + return std::tolower(c); + + return Config->CaseMapLower[c]; } unsigned char Anope::toupper(unsigned char c) { - return case_map_upper[c]; + if (!Config || !Config->CaseMapUpper[c]) + return std::toupper(c); + + return Config->CaseMapUpper[c]; } /* @@ -43,10 +49,10 @@ unsigned char Anope::toupper(unsigned char c) * which is a case-insensitive equivalent to std::string. * */ - + bool ci::ci_char_traits::eq(char c1st, char c2nd) { - return case_map_upper[static_cast<unsigned char>(c1st)] == case_map_upper[static_cast<unsigned char>(c2nd)]; + return Anope::toupper(c1st) == Anope::toupper(c2nd); } bool ci::ci_char_traits::ne(char c1st, char c2nd) @@ -56,15 +62,15 @@ bool ci::ci_char_traits::ne(char c1st, char c2nd) bool ci::ci_char_traits::lt(char c1st, char c2nd) { - return case_map_upper[static_cast<unsigned char>(c1st)] < case_map_upper[static_cast<unsigned char>(c2nd)]; + return Anope::toupper(c1st) < Anope::toupper(c2nd); } int ci::ci_char_traits::compare(const char *str1, const char *str2, size_t n) { for (unsigned i = 0; i < n; ++i) { - register unsigned char c1 = case_map_upper[static_cast<unsigned char>(*str1)], - c2 = case_map_upper[static_cast<unsigned char>(*str2)]; + unsigned char c1 = Anope::toupper(*str1), + c2 = Anope::toupper(*str2); if (c1 > c2) return 1; @@ -81,7 +87,7 @@ int ci::ci_char_traits::compare(const char *str1, const char *str2, size_t n) const char *ci::ci_char_traits::find(const char *s1, int n, char c) { - while (n-- > 0 && case_map_upper[static_cast<unsigned char>(*s1)] != case_map_upper[static_cast<unsigned char>(c)]) + while (n-- > 0 && Anope::toupper(*s1) != Anope::toupper(c)) ++s1; return n >= 0 ? s1 : NULL; } @@ -162,3 +168,95 @@ bool sepstream::StreamEnd() return this->pos > this->tokens.length(); } +size_t Anope::hash::operator()(const Anope::string &s) const +{ + return std::hash<std::string>()(s.str()); +} + +bool Anope::compare::operator()(const Anope::string &s1, const Anope::string &s2) const +{ + return s1.equals_cs(s2); +} + +size_t Anope::hash_ci::operator()(const Anope::string &s) const +{ + return std::hash<std::string>()(s.lower().str()); +} + +bool Anope::compare_ci::operator()(const Anope::string &s1, const Anope::string &s2) const +{ + return s1.equals_ci(s2); +} + +size_t Anope::hash_locale::operator()(const Anope::string &s) const +{ +#ifdef Boost_FOUND + if (Config != nullptr && Config->locale != nullptr) + { + return Anope::locale::hash(s.str()); + } +#endif + + return Anope::hash_ci()(s); +} + +bool Anope::compare_locale::operator()(const Anope::string &s1, const Anope::string &s2) const +{ +#ifdef Boost_FOUND + if (Config != nullptr && Config->locale != nullptr) + { + return Anope::locale::compare(s1.str(), s2.str()) == 0; + } +#endif + + return Anope::compare_ci()(s1, s2); +} + +Anope::string Anope::transform(const Anope::string &s) +{ +#ifdef Boost_FOUND + if (Config != nullptr && Config->locale != nullptr) + { + return Anope::locale::transform(s.str()); + } +#endif + + return s.lower(); +} + +#ifdef Boost_FOUND + +std::locale Anope::locale::generate(const std::string &name) +{ + boost::locale::generator gen; + return gen.generate(name); +} + +int Anope::locale::compare(const std::string &s1, const std::string &s2) +{ + std::string c1 = boost::locale::conv::between(s1.data(), s1.data() + s1.length(), + Config->locale->name(), + ""); + + std::string c2 = boost::locale::conv::between(s2.data(), s2.data() + s2.length(), + Config->locale->name(), + ""); + + const boost::locale::collator<char> &ct = std::use_facet<boost::locale::collator<char>>(*Config->locale); + return ct.compare(boost::locale::collator_base::secondary, c1, c2); +} + +long Anope::locale::hash(const std::string &s) +{ + const boost::locale::collator<char> &ct = std::use_facet<boost::locale::collator<char>>(*Config->locale); + return ct.hash(boost::locale::collator_base::secondary, s.data(), s.data() + s.length()); +} + +std::string Anope::locale::transform(const std::string &s) +{ + const boost::locale::collator<char> &ct = std::use_facet<boost::locale::collator<char>>(*Config->locale); + return ct.transform(boost::locale::collator_base::secondary, s); +} + +#endif + diff --git a/src/init.cpp b/src/init.cpp index 7e5722603..2922edaf1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,12 +1,20 @@ -/* Initialization and related routines. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -18,6 +26,8 @@ #include "socketengine.h" #include "servers.h" #include "language.h" +#include "event.h" +#include "modules.h" #ifndef _WIN32 #include <sys/wait.h> @@ -105,7 +115,7 @@ void Anope::Fork() { #ifndef _WIN32 kill(getppid(), SIGUSR2); - + freopen("/dev/null", "r", stdin); freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); @@ -124,8 +134,6 @@ void Anope::HandleSignal() { case SIGHUP: { - Anope::SaveDatabases(); - try { Configuration::Conf *new_config = new Configuration::Conf(); @@ -136,21 +144,20 @@ void Anope::HandleSignal() } catch (const ConfigException &ex) { - Log() << "Error reloading configuration file: " << ex.GetReason(); + Anope::Logger.Log("Error reloading configuration file: {0}", ex.GetReason()); } break; } case SIGTERM: case SIGINT: #ifndef _WIN32 - Log() << "Received " << strsignal(Signal) << " signal (" << Signal << "), exiting."; + Anope::Logger.Log(_("Received {0} signal ({1}), exiting"), strsignal(Signal), Signal); Anope::QuitReason = Anope::string("Services terminating via signal ") + strsignal(Signal) + " (" + stringify(Signal) + ")"; #else - Log() << "Received signal " << Signal << ", exiting."; - Anope::QuitReason = Anope::string("Services terminating via signal ") + stringify(Signal); + Anope::Logger.Log(_("Received signal {0}, exiting"), Signal); + Anope::QuitReason = "Services terminating via signal " + stringify(Signal); #endif Anope::Quitting = true; - Anope::SaveDatabases(); break; } @@ -207,14 +214,14 @@ static void InitSignals() static void remove_pidfile() { - remove(Config->GetBlock("serverinfo")->Get<const Anope::string>("pid").c_str()); + remove(Config->GetBlock("serverinfo")->Get<Anope::string>("pid").c_str()); } /* Create our PID file and write the PID to it. */ static void write_pidfile() { - FILE *pidfile = fopen(Config->GetBlock("serverinfo")->Get<const Anope::string>("pid").c_str(), "w"); + FILE *pidfile = fopen(Config->GetBlock("serverinfo")->Get<Anope::string>("pid").c_str(), "w"); if (pidfile) { #ifdef _WIN32 @@ -226,7 +233,7 @@ static void write_pidfile() atexit(remove_pidfile); } else - throw CoreException("Can not write to PID file " + Config->GetBlock("serverinfo")->Get<const Anope::string>("pid")); + throw CoreException("Can not write to PID file " + Config->GetBlock("serverinfo")->Get<Anope::string>("pid")); } static void setuidgid() @@ -236,21 +243,21 @@ static void setuidgid() uid_t uid = -1; gid_t gid = -1; - if (!options->Get<const Anope::string>("user").empty()) + if (!options->Get<Anope::string>("user").empty()) { errno = 0; - struct passwd *u = getpwnam(options->Get<const Anope::string>("user").c_str()); + struct passwd *u = getpwnam(options->Get<Anope::string>("user").c_str()); if (u == NULL) - Log() << "Unable to setuid to " << options->Get<const Anope::string>("user") << ": " << Anope::LastError(); + Anope::Logger.Log(_("Unable to setuid to {0}: {1}"), options->Get<Anope::string>("user"), Anope::LastError()); else uid = u->pw_uid; } - if (!options->Get<const Anope::string>("group").empty()) + if (!options->Get<Anope::string>("group").empty()) { errno = 0; - struct group *g = getgrnam(options->Get<const Anope::string>("group").c_str()); + struct group *g = getgrnam(options->Get<Anope::string>("group").c_str()); if (g == NULL) - Log() << "Unable to setgid to " << options->Get<const Anope::string>("group") << ": " << Anope::LastError(); + Anope::Logger.Log(_("Unable to setgid to {0}: {1}"), options->Get<Anope::string>("group"), Anope::LastError()); else gid = g->gr_gid; } @@ -270,16 +277,16 @@ static void setuidgid() if (static_cast<int>(gid) != -1) { if (setgid(gid) == -1) - Log() << "Unable to setgid to " << options->Get<const Anope::string>("group") << ": " << Anope::LastError(); + Anope::Logger.Log(_("Unable to setgid to {0}: {1}"), options->Get<Anope::string>("group"), Anope::LastError()); else - Log() << "Successfully set group to " << options->Get<const Anope::string>("group"); + Anope::Logger.Log(_("Successfully set group to {0"), options->Get<Anope::string>("group")); } if (static_cast<int>(uid) != -1) { if (setuid(uid) == -1) - Log() << "Unable to setuid to " << options->Get<const Anope::string>("user") << ": " << Anope::LastError(); + Anope::Logger.Log(_("Unable to setuid to {0}: {1}"), options->Get<Anope::string>("user"), Anope::LastError()); else - Log() << "Successfully set user to " << options->Get<const Anope::string>("user"); + Anope::Logger.Log(_("Successfully set user to {0}"), options->Get<Anope::string>("user")); } #endif } @@ -291,41 +298,39 @@ void Anope::Init(int ac, char **av) umask(DEFUMASK); #endif - Serialize::RegisterTypes(); - /* Parse command line arguments */ ParseCommandLineArguments(ac, av); if (GetCommandLineArgument("version", 'v')) { - Log(LOG_TERMINAL) << "Anope-" << Anope::Version() << " -- " << Anope::VersionBuildString(); - throw CoreException(); + Anope::Logger.Terminal(_("Anope-{0} -- Built: {1} -- Flags: {2}"), Anope::Version(), Anope::VersionBuildTime(), Anope::VersionFlags()); + exit(EXIT_SUCCESS); } if (GetCommandLineArgument("help", 'h')) { - Log(LOG_TERMINAL) << "Anope-" << Anope::Version() << " -- " << Anope::VersionBuildString(); - Log(LOG_TERMINAL) << "Anope IRC Services (http://www.anope.org)"; - Log(LOG_TERMINAL) << "Usage ./" << Anope::ServicesBin << " [options] ..."; - Log(LOG_TERMINAL) << "-c, --config=filename.conf"; - Log(LOG_TERMINAL) << " --confdir=conf file direcory"; - Log(LOG_TERMINAL) << " --dbdir=database directory"; - Log(LOG_TERMINAL) << "-d, --debug[=level]"; - Log(LOG_TERMINAL) << "-h, --help"; - Log(LOG_TERMINAL) << " --localedir=locale directory"; - Log(LOG_TERMINAL) << " --logdir=logs directory"; - Log(LOG_TERMINAL) << " --modulesdir=modules directory"; - Log(LOG_TERMINAL) << "-e, --noexpire"; - Log(LOG_TERMINAL) << "-n, --nofork"; - Log(LOG_TERMINAL) << " --nothird"; - Log(LOG_TERMINAL) << " --protocoldebug"; - Log(LOG_TERMINAL) << "-r, --readonly"; - Log(LOG_TERMINAL) << "-s, --support"; - Log(LOG_TERMINAL) << "-v, --version"; - Log(LOG_TERMINAL) << ""; - Log(LOG_TERMINAL) << "Further support is available from http://www.anope.org"; - Log(LOG_TERMINAL) << "Or visit us on IRC at irc.anope.org #anope"; - throw CoreException(); + Anope::Logger.Terminal(_("Anope-{0}"), Anope::Version()); + Anope::Logger.Terminal(_("Anope IRC Services (https://anope.org)")); + Anope::Logger.Terminal(_("Usage ./{0} [options] ..."), Anope::ServicesBin); + Anope::Logger.Terminal(_("-c, --config=filename.conf")); + Anope::Logger.Terminal(_(" --confdir=conf file direcory")); + Anope::Logger.Terminal(_(" --dbdir=database directory")); + Anope::Logger.Terminal(_("-d, --debug[=level]")); + Anope::Logger.Terminal(_("-h, --help")); + Anope::Logger.Terminal(_(" --localedir=locale directory")); + Anope::Logger.Terminal(_(" --logdir=logs directory")); + Anope::Logger.Terminal(_(" --modulesdir=modules directory")); + Anope::Logger.Terminal(_("-e, --noexpire")); + Anope::Logger.Terminal(_("-n, --nofork")); + Anope::Logger.Terminal(_(" --nothird")); + Anope::Logger.Terminal(_(" --protocoldebug")); + Anope::Logger.Terminal(_("-r, --readonly")); + Anope::Logger.Terminal(_("-s, --support")); + Anope::Logger.Terminal(_("-v, --version")); + Anope::Logger.Terminal(""); + Anope::Logger.Terminal(_("Further support is available from https://anope.org")); + Anope::Logger.Terminal(_("Or visit us on IRC at irc.anope.org #anope")); + exit(EXIT_SUCCESS); } if (GetCommandLineArgument("nofork", 'n')) @@ -412,7 +417,7 @@ void Anope::Init(int ac, char **av) throw CoreException("Unable to chdir to " + Anope::ServicesDir + ": " + Anope::LastError()); } - Log(LOG_TERMINAL) << "Anope " << Anope::Version() << ", " << Anope::VersionBuildString(); + Anope::Logger.Terminal("Anope-{0} -- Built: {1} -- Flags: {2}", Anope::Version(), Anope::VersionBuildTime(), Anope::VersionFlags()); #ifdef _WIN32 if (!SupportedWindowsVersion()) @@ -423,7 +428,7 @@ void Anope::Init(int ac, char **av) { /* If we are configured to setuid later, don't issue a warning */ Configuration::Block *options = Config->GetBlock("options"); - if (options->Get<const Anope::string>("user").empty()) + if (options->Get<Anope::string>("user").empty()) { std::cerr << "WARNING: You are currently running Anope as the root superuser. Anope does not" << std::endl; std::cerr << " require root privileges to run, and it is discouraged that you run Anope" << std::endl; @@ -434,9 +439,9 @@ void Anope::Init(int ac, char **av) #endif #ifdef _WIN32 - Log(LOG_TERMINAL) << "Using configuration file " << Anope::ConfigDir << "\\" << ServicesConf.GetName(); + Anope::Logger.Terminal("Using configuration file {0}\\{1}", Anope::ConfigDir, ServicesConf.GetName()); #else - Log(LOG_TERMINAL) << "Using configuration file " << Anope::ConfigDir << "/" << ServicesConf.GetName(); + Anope::Logger.Terminal("Using configuration file {0}/{1}", Anope::ConfigDir, ServicesConf.GetName()); /* Fork to background */ if (!Anope::NoFork) @@ -466,7 +471,7 @@ void Anope::Init(int ac, char **av) } else if (i == -1) { - Log() << "Error, unable to fork: " << Anope::LastError(); + Anope::Logger.Terminal("Error, unable to fork: {0}", Anope::LastError()); Anope::NoFork = true; } @@ -480,6 +485,13 @@ void Anope::Init(int ac, char **av) /* Initialize the socket engine. Note that some engines can not survive a fork(), so this must be here. */ SocketEngine::Init(); + ServiceManager::Init(); + EventManager::Init(); + + new BotInfoType(); + new XLineType(nullptr); + new OperBlockType(); + /* Read configuration file; exit if there are problems. */ try { @@ -487,25 +499,35 @@ void Anope::Init(int ac, char **av) } catch (const ConfigException &ex) { - Log(LOG_TERMINAL) << ex.GetReason(); - Log(LOG_TERMINAL) << "*** Support resources: Read through the services.conf self-contained"; - Log(LOG_TERMINAL) << "*** documentation. Read the documentation files found in the 'docs'"; - Log(LOG_TERMINAL) << "*** folder. Visit our portal located at http://www.anope.org/. Join"; - Log(LOG_TERMINAL) << "*** our support channel on /server irc.anope.org channel #anope."; + Anope::Logger.Terminal(ex.GetReason()); + Anope::Logger.Terminal("*** Support resources: Read through the anope.conf self-contained"); + Anope::Logger.Terminal("*** documentation. Read the documentation files found in the 'docs'"); + Anope::Logger.Terminal("*** folder. Visit our portal located at https://anope.org/. Join"); + Anope::Logger.Terminal("*** our support channel on irc.anope.org #anope."); throw CoreException("Configuration file failed to validate"); } /* Create me */ Configuration::Block *block = Config->GetBlock("serverinfo"); - Me = new Server(NULL, block->Get<const Anope::string>("name"), 0, block->Get<const Anope::string>("description"), block->Get<const Anope::string>("id")); - for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) + Me = new Server(NULL, block->Get<Anope::string>("name"), 0, block->Get<Anope::string>("description"), block->Get<Anope::string>("id")); + for (std::pair<Anope::string, User *> p : UserListByNick) { - it->second->server = Me; + User *u = p.second; + if (u->type != UserType::BOT) + continue; + + ServiceBot *bi = anope_dynamic_static_cast<ServiceBot *>(u); + bi->server = Me; ++Me->users; } /* Announce ourselves to the logfile. */ - Log() << "Anope " << Anope::Version() << " starting up" << (Anope::Debug || Anope::ReadOnly ? " (options:" : "") << (Anope::Debug ? " debug" : "") << (Anope::ReadOnly ? " readonly" : "") << (Anope::Debug || Anope::ReadOnly ? ")" : ""); + if (Anope::Debug || Anope::ReadOnly) + Anope::Logger.Log("Anope {0} starting up ({1})", + Anope::Version(), + Anope::Format("options:{0}{1}", Anope::Debug ? " debug" : "", Anope::ReadOnly ? " readonly" : "")); + else + Anope::Logger.Log("Anope {0} starting up", Anope::Version()); InitSignals(); @@ -516,10 +538,15 @@ void Anope::Init(int ac, char **av) block = Config->GetBlock("options"); srand(block->Get<unsigned>("seed") ^ time(NULL)); + ModeManager::Apply(nullptr); + /* load modules */ - Log() << "Loading modules..."; + Anope::Logger.Log("Loading modules..."); for (int i = 0; i < Config->CountBlock("module"); ++i) - ModuleManager::LoadModule(Config->GetBlock("module", i)->Get<const Anope::string>("name"), NULL); + ModuleManager::LoadModule(Config->GetBlock("module", i)->Get<Anope::string>("name"), NULL); + + Config->LoadOpers(); + Config->ApplyBots(); #ifndef _WIN32 /* We won't background later, so we should setuid now */ @@ -534,7 +561,7 @@ void Anope::Init(int ac, char **av) /* Write our PID to the PID file. */ write_pidfile(); - Log() << "Using IRCd protocol " << protocol->name; + Anope::Logger.Log("Using IRCd protocol {0}", protocol->GetName()); /* Auto assign sid if applicable */ if (IRCD->RequiresID) @@ -542,20 +569,23 @@ void Anope::Init(int ac, char **av) Anope::string sid = IRCD->SID_Retrieve(); if (Me->GetSID() == Me->GetName()) Me->SetSID(sid); - for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) - it->second->GenerateUID(); + for (std::pair<Anope::string, User *> p : UserListByNick) + { + User *u = p.second; + if (u->type != UserType::BOT) + continue; + + ServiceBot *bi = anope_dynamic_static_cast<ServiceBot *>(u); + bi->GenerateUID(); + } } /* Load up databases */ - Log() << "Loading databases..."; - EventReturn MOD_RESULT; - FOREACH_RESULT(OnLoadDatabase, MOD_RESULT, ()); - static_cast<void>(MOD_RESULT); - Log() << "Databases loaded"; + Anope::Logger.Log("Loading databases..."); + EventManager::Get()->Dispatch(&Event::LoadDatabase::OnLoadDatabase);; + Anope::Logger.Log("Databases loaded"); for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it) it->second->Sync(); - - Serialize::CheckTypes(); } diff --git a/src/language.cpp b/src/language.cpp index 0a19729b1..238449aaa 100644 --- a/src/language.cpp +++ b/src/language.cpp @@ -1,12 +1,20 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -14,6 +22,7 @@ #include "commands.h" #include "config.h" #include "language.h" +#include "modules/nickserv.h" #if GETTEXT_FOUND # include <libintl.h> @@ -25,33 +34,33 @@ std::vector<Anope::string> Language::Domains; void Language::InitLanguages() { #if GETTEXT_FOUND - Log(LOG_DEBUG) << "Initializing Languages..."; + Anope::Logger.Debug("Initializing Languages..."); Languages.clear(); if (!bindtextdomain("anope", Anope::LocaleDir.c_str())) - Log() << "Error calling bindtextdomain, " << Anope::LastError(); + Anope::Logger.Log("Error calling bindtextdomain, {0}", Anope::LastError()); else - Log(LOG_DEBUG) << "Successfully bound anope to " << Anope::LocaleDir; + Anope::Logger.Debug("Successfully bound anope to {0}", Anope::LocaleDir); setlocale(LC_ALL, ""); - spacesepstream sep(Config->GetBlock("options")->Get<const Anope::string>("languages")); + spacesepstream sep(Config->GetBlock("options")->Get<Anope::string>("languages")); Anope::string language; while (sep.GetToken(language)) { const Anope::string &lang_name = Translate(language.c_str(), _("English")); if (lang_name == "English") { - Log() << "Unable to use language " << language; + Anope::Logger.Log("Unable to use language {0}", language); continue; } - Log(LOG_DEBUG) << "Found language " << language; + Anope::Logger.Debug("Found language {0}", language); Languages.push_back(language); } #else - Log() << "Unable to initialize languages, gettext is not installed"; + Anope::Logger.Log("Unable to initialize languages, gettext is not installed"); #endif } @@ -60,6 +69,11 @@ const char *Language::Translate(const char *string) return Translate("", string); } +const char *Language::Translate(const Anope::string &string) +{ + return Translate("", string.c_str()); +} + const char *Language::Translate(User *u, const char *string) { if (u && u->Account()) @@ -68,9 +82,19 @@ const char *Language::Translate(User *u, const char *string) return Translate("", string); } -const char *Language::Translate(const NickCore *nc, const char *string) +const char *Language::Translate(User *u, const Anope::string &string) +{ + return Translate(u, string.c_str()); +} + +const char *Language::Translate(NickServ::Account *nc, const char *string) { - return Translate(nc ? nc->language.c_str() : "", string); + return Translate(nc ? nc->GetLanguage().c_str() : "", string); +} + +const char *Language::Translate(NickServ::Account *nc, const Anope::string &string) +{ + return Translate(nc, string.c_str()); } #if GETTEXT_FOUND @@ -85,7 +109,12 @@ const char *Language::Translate(const char *lang, const char *string) return ""; if (!lang || !*lang) + { + if (Config == nullptr) + return string; + lang = Config->DefLanguage.c_str(); + } #ifdef __USE_GNU_GETTEXT ++_nl_msg_cat_cntr; diff --git a/src/logger.cpp b/src/logger.cpp index c681e42fa..ae5709052 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -1,12 +1,20 @@ -/* Logging routines. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2010-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -20,6 +28,10 @@ #include "servers.h" #include "uplink.h" #include "protocol.h" +#include "event.h" +#include "anope.h" +#include "modules/nickserv.h" +#include "modules/chanserv.h" #ifndef _WIN32 #include <sys/time.h> @@ -46,7 +58,9 @@ static Anope::string GetTimeStamp() strftime(s, sizeof(tbuf) - (s - tbuf) - 1, " %Y]", &tm); } else + { strftime(tbuf, sizeof(tbuf) - 1, "[%b %d %H:%M:%S %Y]", &tm); + } return tbuf; } @@ -74,153 +88,7 @@ const Anope::string &LogFile::GetName() const return this->filename; } -Log::Log(LogType t, const Anope::string &cat, BotInfo *b) : bi(b), u(NULL), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(NULL), m(NULL), type(t), category(cat) -{ -} - -Log::Log(LogType t, CommandSource &src, Command *_c, ChannelInfo *_ci) : u(src.GetUser()), nc(src.nc), c(_c), source(&src), chan(NULL), ci(_ci), s(NULL), m(NULL), type(t) -{ - if (!c) - throw CoreException("Invalid pointers passed to Log::Log"); - - if (type != LOG_COMMAND && type != LOG_OVERRIDE && type != LOG_ADMIN) - throw CoreException("This constructor does not support this log type"); - - size_t sl = c->name.find('/'); - this->bi = NULL; - if (sl != Anope::string::npos) - this->bi = BotInfo::Find(c->name.substr(0, sl), true); - this->category = c->name; -} - -Log::Log(User *_u, Channel *ch, const Anope::string &cat) : bi(NULL), u(_u), nc(NULL), c(NULL), source(NULL), chan(ch), ci(chan ? *chan->ci : NULL), s(NULL), m(NULL), type(LOG_CHANNEL), category(cat) -{ - if (!chan) - throw CoreException("Invalid pointers passed to Log::Log"); -} - -Log::Log(User *_u, const Anope::string &cat, BotInfo *_bi) : bi(_bi), u(_u), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(NULL), m(NULL), type(LOG_USER), category(cat) -{ - if (!u) - throw CoreException("Invalid pointers passed to Log::Log"); -} - -Log::Log(Server *serv, const Anope::string &cat, BotInfo *_bi) : bi(_bi), u(NULL), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(serv), m(NULL), type(LOG_SERVER), category(cat) -{ - if (!s) - throw CoreException("Invalid pointer passed to Log::Log"); -} - -Log::Log(BotInfo *b, const Anope::string &cat) : bi(b), u(NULL), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(NULL), m(NULL), type(LOG_NORMAL), category(cat) -{ -} - -Log::Log(Module *mod, const Anope::string &cat, BotInfo *_bi) : bi(_bi), u(NULL), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(NULL), m(mod), type(LOG_MODULE), category(cat) -{ -} - -Log::~Log() -{ - if (Anope::NoFork && Anope::Debug && this->type >= LOG_NORMAL && this->type <= LOG_DEBUG + Anope::Debug - 1) - std::cout << GetTimeStamp() << " Debug: " << this->BuildPrefix() << this->buf.str() << std::endl; - else if (Anope::NoFork && this->type <= LOG_TERMINAL) - std::cout << GetTimeStamp() << " " << this->BuildPrefix() << this->buf.str() << std::endl; - else if (this->type == LOG_TERMINAL) - std::cout << this->BuildPrefix() << this->buf.str() << std::endl; - - FOREACH_MOD(OnLog, (this)); - - if (Config) - for (unsigned i = 0; i < Config->LogInfos.size(); ++i) - if (Config->LogInfos[i].HasType(this->type, this->category)) - Config->LogInfos[i].ProcessMessage(this); -} - -Anope::string Log::FormatSource() const -{ - if (u) - if (nc) - return this->u->GetMask() + " (" + this->nc->display + ")"; - else - return this->u->GetMask(); - else if (nc) - return nc->display; - return ""; -} - -Anope::string Log::FormatCommand() const -{ - Anope::string buffer = FormatSource() + " used " + (source != NULL && !source->command.empty() ? source->command : this->c->name) + " "; - if (this->ci) - buffer += "on " + this->ci->name + " "; - - return buffer; -} - -Anope::string Log::BuildPrefix() const -{ - Anope::string buffer; - - switch (this->type) - { - case LOG_ADMIN: - { - if (!this->c) - break; - buffer += "ADMIN: " + FormatCommand(); - break; - } - case LOG_OVERRIDE: - { - if (!this->c) - break; - buffer += "OVERRIDE: " + FormatCommand(); - break; - } - case LOG_COMMAND: - { - if (!this->c) - break; - buffer += "COMMAND: " + FormatCommand(); - break; - } - case LOG_CHANNEL: - { - if (!this->chan) - break; - buffer += "CHANNEL: "; - Anope::string src = FormatSource(); - if (!src.empty()) - buffer += src + " "; - buffer += this->category + " " + this->chan->name + " "; - break; - } - case LOG_USER: - { - if (this->u) - buffer += "USERS: " + FormatSource() + " "; - break; - } - case LOG_SERVER: - { - if (this->s) - buffer += "SERVER: " + this->s->GetName() + " (" + this->s->GetDescription() + ") "; - break; - } - case LOG_MODULE: - { - if (this->m) - buffer += this->m->name.upper() + ": "; - break; - } - default: - break; - } - - return buffer; -} - -LogInfo::LogInfo(int la, bool rio, bool ldebug) : bot(NULL), last_day(0), log_age(la), raw_io(rio), debug(ldebug) +LogInfo::LogInfo(int la, bool rio, bool ldebug) : log_age(la), raw_io(rio), debug(ldebug) { } @@ -231,41 +99,46 @@ LogInfo::~LogInfo() this->logfiles.clear(); } -bool LogInfo::HasType(LogType ltype, const Anope::string &type) const +bool LogInfo::HasType(LogType ltype, LogLevel level, const Anope::string &type) const { + switch (level) + { + case LogLevel::TERMINAL: + return true; + case LogLevel::RAWIO: + return (Anope::Debug || this->debug) ? true : this->raw_io; + case LogLevel::DEBUG: + return Anope::Debug ? true : this->debug; + case LogLevel::DEBUG_2: + case LogLevel::DEBUG_3: + return false; + case LogLevel::NORMAL: + break; + } + const std::vector<Anope::string> *list = NULL; switch (ltype) { - case LOG_ADMIN: + case LogType::ADMIN: list = &this->admin; break; - case LOG_OVERRIDE: + case LogType::OVERRIDE: list = &this->override; break; - case LOG_COMMAND: + case LogType::COMMAND: list = &this->commands; break; - case LOG_SERVER: + case LogType::SERVER: list = &this->servers; break; - case LOG_CHANNEL: + case LogType::CHANNEL: list = &this->channels; break; - case LOG_USER: + case LogType::USER: list = &this->users; break; - case LOG_TERMINAL: - return true; - case LOG_RAWIO: - return (Anope::Debug || this->debug) ? true : this->raw_io; - case LOG_DEBUG: - return Anope::Debug ? true : this->debug; - case LOG_DEBUG_2: - case LOG_DEBUG_3: - case LOG_DEBUG_4: - break; - case LOG_MODULE: - case LOG_NORMAL: + case LogType::MODULE: + case LogType::NORMAL: default: list = &this->normal; break; @@ -274,7 +147,7 @@ bool LogInfo::HasType(LogType ltype, const Anope::string &type) const if (list == NULL) return false; - for (unsigned i = 0; i < list->size(); ++i) + for (unsigned int i = 0; i < list->size(); ++i) { Anope::string cat = list->at(i); bool inverse = false; @@ -302,13 +175,13 @@ void LogInfo::OpenLogFiles() { const Anope::string &target = this->targets[i]; - if (target.empty() || target[0] == '#' || target == "globops" || target.find(":") != Anope::string::npos) + if (target.empty() || target[0] == '#' || target == "opers" || target.find(":") != Anope::string::npos) continue; LogFile *lf = new LogFile(CreateLogName(target)); if (!lf->stream.is_open()) { - Log() << "Unable to open logfile " << lf->GetName(); + Anope::Logger.Log("Unable to open logfile {0}", lf->GetName()); delete lf; } else @@ -316,7 +189,7 @@ void LogInfo::OpenLogFiles() } } -void LogInfo::ProcessMessage(const Log *l) +void LogInfo::ProcessMessage(const Logger *l, const Anope::string &message) { if (!this->sources.empty()) { @@ -325,26 +198,29 @@ void LogInfo::ProcessMessage(const Log *l) { const Anope::string &src = this->sources[i]; - if (l->bi && src == l->bi->nick) + if (l->GetBot() && src == l->GetBot()->nick) log = true; - else if (l->u && src == l->u->nick) + else if (l->GetUser() && src == l->GetUser()->nick) log = true; - else if (l->nc && src == l->nc->display) + else if (l->GetAccount() && src == l->GetAccount()->GetDisplay()) log = true; - else if (l->ci && src == l->ci->name) + else if (l->GetCi() && src == l->GetCi()->GetName()) log = true; - else if (l->m && src == l->m->name) + else if (l->GetModule() && src == l->GetModule()->name) log = true; - else if (l->s && src == l->s->GetName()) + else if (l->GetServer() && src == l->GetServer()->GetName()) log = true; } if (!log) return; } - const Anope::string &buffer = l->BuildPrefix() + l->buf.str(); + const Anope::string &buffer = l->BuildPrefix() + message; - FOREACH_MOD(OnLogMessage, (this, l, buffer)); + if (l->GetLevel() <= LogLevel::NORMAL) + { + EventManager::Get()->Dispatch(&Event::LogMessage::OnLogMessage, this, l, buffer); + } for (unsigned i = 0; i < this->targets.size(); ++i) { @@ -352,30 +228,30 @@ void LogInfo::ProcessMessage(const Log *l) if (!target.empty() && target[0] == '#') { - if (UplinkSock && l->type <= LOG_NORMAL && Me && Me->IsSynced()) + if (UplinkSock && l->type == LogType::NORMAL && Me && Me->IsSynced()) { Channel *c = Channel::Find(target); if (!c) continue; - BotInfo *bi = l->bi; + User *bi = l->GetBot(); if (!bi) bi = this->bot; - if (!bi) + if (!bi && c->ci) bi = c->ci->WhoSends(); if (bi) - IRCD->SendPrivmsg(bi, c->name, "%s", buffer.c_str()); + IRCD->SendPrivmsg(bi, c->name, buffer); } } - else if (target == "globops") + else if (target == "opers") { - if (UplinkSock && l->bi && l->type <= LOG_NORMAL && Me && Me->IsSynced()) + if (UplinkSock && l->GetBot() && l->type == LogType::NORMAL && Me && Me->IsSynced()) { - IRCD->SendGlobops(l->bi, "%s", buffer.c_str()); + IRCD->SendWallops(l->GetBot(), buffer); } } } - + tm *tm = localtime(&Anope::CurTime); if (tm->tm_mday != this->last_day) { @@ -387,14 +263,14 @@ void LogInfo::ProcessMessage(const Log *l) { const Anope::string &target = this->targets[i]; - if (target.empty() || target[0] == '#' || target == "globops" || target.find(":") != Anope::string::npos) + if (target.empty() || target[0] == '#' || target == "opers" || target.find(":") != Anope::string::npos) continue; Anope::string oldlog = CreateLogName(target, Anope::CurTime - 86400 * this->log_age); if (IsFile(oldlog)) { unlink(oldlog.c_str()); - Log(LOG_DEBUG) << "Deleted old logfile " << oldlog; + Anope::Logger.Debug("Deleted old logfile {0}", oldlog); } } } @@ -406,3 +282,221 @@ void LogInfo::ProcessMessage(const Log *l) } } +void Logger::InsertVariables(FormatInfo &fi) +{ + if (user != nullptr) + fi.Add("user"_kw = user->GetMask()); + + if (ci != nullptr) + fi.Add("channel"_kw = ci->GetName()); + else if (channel != nullptr) + fi.Add("channel"_kw = channel->GetName()); + + fi.Add("source"_kw = this->FormatSource()); + + if (source != nullptr && !source->GetCommand().empty()) + fi.Add("command"_kw = source->GetCommand()); + else if (command != nullptr) + fi.Add("command"_kw = command->GetName()); +} + +void Logger::CheckOverride() +{ + if (type == LogType::COMMAND && source != nullptr && source->IsOverride()) + type = LogType::OVERRIDE; +} + +Anope::string Logger::FormatSource() const +{ + if (user) + if (account) + return user->GetMask() + " (" + account->GetDisplay() + ")"; + else + return user->GetMask(); + else if (account) + return account->GetDisplay(); + else if (source) + return source->GetNick(); + return ""; +} + +Anope::string Logger::BuildPrefix() const +{ + switch (this->type) + { + case LogType::ADMIN: + return "ADMIN: "; + case LogType::OVERRIDE: + return "OVERRIDE: "; + case LogType::COMMAND: + return "COMMAND: "; + case LogType::SERVER: + return "SERVER: "; + case LogType::CHANNEL: + return "CHANNEL: "; + case LogType::USER: + return "USER: "; + case LogType::MODULE: + return this->module != nullptr ? (this->module->name.upper() + ": ") : ""; + case LogType::NORMAL: + break; + } + + return ""; +} + +void Logger::LogMessage(const Anope::string &message) +{ + if (Anope::NoFork && Anope::Debug && level >= LogLevel::NORMAL && static_cast<int>(level) <= static_cast<int>(LogLevel::DEBUG) + Anope::Debug - 1) + std::cout << GetTimeStamp() << " Debug: " << this->BuildPrefix() << message << std::endl; + else if (Anope::NoFork && level <= LogLevel::TERMINAL) + std::cout << GetTimeStamp() << " " << this->BuildPrefix() << message << std::endl; + else if (level == LogLevel::TERMINAL) + std::cout << this->BuildPrefix() << message << std::endl; + + if (level <= LogLevel::NORMAL) + { + EventManager *em = EventManager::Get(); + if (em != nullptr) + em->Dispatch(&Event::Log::OnLog, this); + } + + if (Config != nullptr) + for (LogInfo &info : Config->LogInfos) + if (info.HasType(this->type, this->level, this->category)) + info.ProcessMessage(this, message); +} + +LogType Logger::GetType() const +{ + return type; +} + +LogLevel Logger::GetLevel() const +{ + return level; +} + +Module *Logger::GetModule() const +{ + return module; +} + +Command *Logger::GetCommand() const +{ + return command; +} + +ServiceBot *Logger::GetBot() const +{ + return bot; +} + +Server *Logger::GetServer() const +{ + return server; +} + +User *Logger::GetUser() const +{ + return user; +} + +void Logger::SetUser(class User *u) +{ + user = u; +} + +NickServ::Account *Logger::GetAccount() const +{ + return account; +} + +void Logger::SetAccount(NickServ::Account *acc) +{ + account = acc; +} + +Channel *Logger::GetChannel() const +{ + return channel; +} + +void Logger::SetChannel(class Channel *c) +{ + channel = c; +} + +ChanServ::Channel *Logger::GetCi() const +{ + return ci; +} + +void Logger::SetCi(ChanServ::Channel *c) +{ + ci = c; +} + +CommandSource *Logger::GetSource() const +{ + return source; +} + +void Logger::SetSource(CommandSource *s) +{ + source = s; + if (s != nullptr) + { + SetUser(s->GetUser()); + SetAccount(s->GetAccount()); + SetChannel(s->c); + } +} + +Logger Logger::Category(const Anope::string &c) const +{ + Logger l = *this; + l.category = c; + return l; +} + +Logger Logger::User(class User *u) const +{ + Logger l = *this; + l.user = u; + return l; +} + +Logger Logger::Channel(class Channel *c) const +{ + Logger l = *this; + l.channel = c; + return l; +} + +Logger Logger::Channel(ChanServ::Channel *c) const +{ + Logger l = *this; + l.ci = c; + return l; +} + +Logger Logger::Source(CommandSource *s) const +{ + Logger l = *this; + l.source = s; + return l; +} + +Logger Logger::Bot(ServiceBot *bot) const +{ + Logger l = *this; + l.bot = bot; + return l; +} + +Logger Logger::Bot(const Anope::string &bot) const +{ + return Bot(Config ? Config->GetClient(bot) : nullptr); +} + diff --git a/src/mail.cpp b/src/mail.cpp index f909fa5a3..619180520 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1,28 +1,39 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "mail.h" #include "config.h" +#include "bots.h" +#include "protocol.h" +#include "modules/nickserv.h" -Mail::Message::Message(const Anope::string &sf, const Anope::string &mailto, const Anope::string &a, const Anope::string &s, const Anope::string &m) : Thread(), sendmail_path(Config->GetBlock("mail")->Get<const Anope::string>("sendmailpath")), send_from(sf), mail_to(mailto), addr(a), subject(s), message(m), dont_quote_addresses(Config->GetBlock("mail")->Get<bool>("dontquoteaddresses")), success(false) +Mail::Message::Message(const Anope::string &sf, const Anope::string &mailto, const Anope::string &a, const Anope::string &s, const Anope::string &m) : Thread(), sendmail_path(Config->GetBlock("mail")->Get<Anope::string>("sendmailpath")), send_from(sf), mail_to(mailto), addr(a), subject(s), message(m), dont_quote_addresses(Config->GetBlock("mail")->Get<bool>("dontquoteaddresses")), success(false) { } Mail::Message::~Message() { if (success) - Log(LOG_NORMAL, "mail") << "Successfully delivered mail for " << mail_to << " (" << addr << ")"; + Anope::Logger.Category("mail").Log(_("Successfully delivered mail for {0} ({1})"), mail_to, addr); else - Log(LOG_NORMAL, "mail") << "Error delivering mail for " << mail_to << " (" << addr << ")"; + Anope::Logger.Category("mail").Log(_("Error delivering mail for {0} ({1})"), mail_to, addr); } void Mail::Message::Run() @@ -50,37 +61,38 @@ void Mail::Message::Run() SetExitState(); } -bool Mail::Send(User *u, NickCore *nc, BotInfo *service, const Anope::string &subject, const Anope::string &message) +bool Mail::Send(User *u, NickServ::Account *nc, ServiceBot *service, const Anope::string &subject, const Anope::string &message) { if (!nc || !service || subject.empty() || message.empty()) return false; Configuration::Block *b = Config->GetBlock("mail"); - + if (!u) { - if (!b->Get<bool>("usemail") || b->Get<const Anope::string>("sendfrom").empty()) + if (!b->Get<bool>("usemail") || b->Get<Anope::string>("sendfrom").empty()) return false; - else if (nc->email.empty()) + else if (nc->GetEmail().empty()) return false; - nc->lastmail = Anope::CurTime; - Thread *t = new Mail::Message(b->Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message); + nc->SetLastMail(Anope::CurTime); + Thread *t = new Mail::Message(b->Get<Anope::string>("sendfrom"), nc->GetDisplay(), nc->GetEmail(), subject, message); t->Start(); return true; } else { - if (!b->Get<bool>("usemail") || b->Get<const Anope::string>("sendfrom").empty()) + if (!b->Get<bool>("usemail") || b->Get<Anope::string>("sendfrom").empty()) u->SendMessage(service, _("Services have been configured to not send mail.")); else if (Anope::CurTime - u->lastmail < b->Get<time_t>("delay")) u->SendMessage(service, _("Please wait \002%d\002 seconds and retry."), b->Get<time_t>("delay") - (Anope::CurTime - u->lastmail)); - else if (nc->email.empty()) - u->SendMessage(service, _("E-mail for \002%s\002 is invalid."), nc->display.c_str()); + else if (nc->GetEmail().empty()) + u->SendMessage(service, _("E-mail for \002%s\002 is invalid."), nc->GetDisplay().c_str()); else { - u->lastmail = nc->lastmail = Anope::CurTime; - Thread *t = new Mail::Message(b->Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message); + u->lastmail = Anope::CurTime; + nc->SetLastMail(Anope::CurTime); + Thread *t = new Mail::Message(b->Get<Anope::string>("sendfrom"), nc->GetDisplay(), nc->GetEmail(), subject, message); t->Start(); return true; } @@ -89,14 +101,14 @@ bool Mail::Send(User *u, NickCore *nc, BotInfo *service, const Anope::string &su } } -bool Mail::Send(NickCore *nc, const Anope::string &subject, const Anope::string &message) +bool Mail::Send(NickServ::Account *nc, const Anope::string &subject, const Anope::string &message) { Configuration::Block *b = Config->GetBlock("mail"); - if (!b->Get<bool>("usemail") || b->Get<const Anope::string>("sendfrom").empty() || !nc || nc->email.empty() || subject.empty() || message.empty()) + if (!b->Get<bool>("usemail") || b->Get<Anope::string>("sendfrom").empty() || !nc || nc->GetEmail().empty() || subject.empty() || message.empty()) return false; - nc->lastmail = Anope::CurTime; - Thread *t = new Mail::Message(b->Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message); + nc->SetLastMail(Anope::CurTime); + Thread *t = new Mail::Message(b->Get<Anope::string>("sendfrom"), nc->GetDisplay(), nc->GetEmail(), subject, message); t->Start(); return true; diff --git a/src/main.cpp b/src/main.cpp index bbcccee27..b171c9794 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,20 @@ -/* Services -- main source file. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -15,6 +23,8 @@ #include "bots.h" #include "socketengine.h" #include "uplink.h" +#include "event.h" +#include "modules.h" #ifndef _WIN32 #include <limits.h> @@ -33,6 +43,7 @@ sig_atomic_t Anope::Signal = 0; bool Anope::Quitting = false; bool Anope::Restarting = false; Anope::string Anope::QuitReason; +Logger Anope::Logger; static Anope::string BinaryDir; /* Full path to services bin directory */ @@ -41,37 +52,17 @@ time_t Anope::CurTime = time(NULL); int Anope::CurrentUplink = -1; -class UpdateTimer : public Timer -{ - public: - UpdateTimer(time_t timeout) : Timer(timeout, Anope::CurTime, true) { } - - void Tick(time_t) anope_override - { - Anope::SaveDatabases(); - } -}; - class ExpireTimer : public Timer { public: ExpireTimer(time_t timeout) : Timer(timeout, Anope::CurTime, true) { } - void Tick(time_t) anope_override + void Tick(time_t) override { - FOREACH_MOD(OnExpireTick, ()); + EventManager::Get()->Dispatch(&Event::ExpireTick::OnExpireTick); } }; -void Anope::SaveDatabases() -{ - if (Anope::ReadOnly) - return; - - Log(LOG_DEBUG) << "Saving databases"; - FOREACH_MOD(OnSaveDatabase, ()); -} - /** The following comes from InspIRCd to get the full path of the Anope executable */ static Anope::string GetFullProgDir(const Anope::string &argv0) @@ -113,9 +104,6 @@ static Anope::string GetFullProgDir(const Anope::string &argv0) int main(int ac, char **av, char **envp) { - /* String comparisons won't work until we build the case map cache, so do it first */ - Anope::CaseMapRebuild(); - BinaryDir = GetFullProgDir(av[0]); if (BinaryDir[BinaryDir.length() - 1] == '.') BinaryDir = BinaryDir.substr(0, BinaryDir.length() - 2); @@ -141,7 +129,7 @@ int main(int ac, char **av, char **envp) } catch (const CoreException &ex) { - Log() << ex.GetReason(); + Anope::Logger.Log(ex.GetReason()); return -1; } @@ -151,18 +139,17 @@ int main(int ac, char **av, char **envp) } catch (const SocketException &ex) { - Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << "): " << ex.GetReason(); + Anope::Logger.Terminal(_("Unable to connect to uplink #{0} ({1}:{2}): {3}"), Anope::CurrentUplink + 1, Config->Uplinks[Anope::CurrentUplink].host, Config->Uplinks[Anope::CurrentUplink].port, ex.GetReason()); } /* Set up timers */ time_t last_check = Anope::CurTime; - UpdateTimer updateTimer(Config->GetBlock("options")->Get<time_t>("updatetimeout", "5m")); ExpireTimer expireTimer(Config->GetBlock("options")->Get<time_t>("expiretimeout", "30m")); /*** Main loop. ***/ while (!Anope::Quitting) { - Log(LOG_DEBUG_2) << "Top of main loop"; + Anope::Logger.Debug2("Top of main loop"); /* Process timers */ if (Anope::CurTime - last_check >= Config->TimeoutCheck) @@ -180,16 +167,16 @@ int main(int ac, char **av, char **envp) if (Anope::Restarting) { - FOREACH_MOD(OnRestart, ()); + EventManager::Get()->Dispatch(&Event::Restart::OnRestart); } else { - FOREACH_MOD(OnShutdown, ()); + EventManager::Get()->Dispatch(&Event::Shutdown::OnShutdown); } if (Anope::QuitReason.empty()) Anope::QuitReason = "Terminating, reason unknown"; - Log() << Anope::QuitReason; + Anope::Logger.Log(Anope::QuitReason); delete UplinkSock; @@ -210,7 +197,7 @@ int main(int ac, char **av, char **envp) Anope::string sbin = "./" + Anope::ServicesBin; av[0] = const_cast<char *>(sbin.c_str()); execve(Anope::ServicesBin.c_str(), av, envp); - Log() << "Restart failed"; + Anope::Logger.Log("Restart failed"); Anope::ReturnValue = -1; } diff --git a/src/memos.cpp b/src/memos.cpp deleted file mode 100644 index bf8f0eb73..000000000 --- a/src/memos.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* MemoServ functions. - * - * (C) 2003-2016 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 "services.h" -#include "modules.h" -#include "service.h" -#include "memo.h" -#include "users.h" -#include "account.h" -#include "regchannel.h" - -Memo::Memo() : Serializable("Memo") -{ - mi = NULL; - unread = receipt = false; -} - -Memo::~Memo() -{ - if (mi) - { - std::vector<Memo *>::iterator it = std::find(mi->memos->begin(), mi->memos->end(), this); - - if (it != mi->memos->end()) - mi->memos->erase(it); - } -} - -void Memo::Serialize(Serialize::Data &data) const -{ - data["owner"] << this->owner; - data.SetType("time", Serialize::Data::DT_INT); data["time"] << this->time; - data["sender"] << this->sender; - data["text"] << this->text; - data["unread"] << this->unread; - data["receipt"] << this->receipt; -} - -Serializable* Memo::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string owner; - - data["owner"] >> owner; - - bool ischan; - MemoInfo *mi = MemoInfo::GetMemoInfo(owner, ischan); - if (!mi) - return NULL; - - Memo *m; - if (obj) - m = anope_dynamic_static_cast<Memo *>(obj); - else - { - m = new Memo(); - m->mi = mi; - } - - m->owner = owner; - data["time"] >> m->time; - data["sender"] >> m->sender; - data["text"] >> m->text; - data["unread"] >> m->unread; - data["receipt"] >> m->receipt; - - if (obj == NULL) - mi->memos->push_back(m); - return m; -} - -MemoInfo::MemoInfo() : memomax(0), memos("Memo") -{ -} - -Memo *MemoInfo::GetMemo(unsigned index) const -{ - if (index >= this->memos->size()) - return NULL; - Memo *m = (*memos)[index]; - m->QueueUpdate(); - return m; -} - -unsigned MemoInfo::GetIndex(Memo *m) const -{ - for (unsigned i = 0; i < this->memos->size(); ++i) - if (this->GetMemo(i) == m) - return i; - return -1; -} - -void MemoInfo::Del(unsigned index) -{ - if (index >= this->memos->size()) - return; - - Memo *m = this->GetMemo(index); - - std::vector<Memo *>::iterator it = std::find(memos->begin(), memos->end(), m); - if (it != memos->end()) - memos->erase(it); - - delete m; -} - -bool MemoInfo::HasIgnore(User *u) -{ - for (unsigned i = 0; i < this->ignores.size(); ++i) - if (u->nick.equals_ci(this->ignores[i]) || (u->Account() && u->Account()->display.equals_ci(this->ignores[i])) || Anope::Match(u->GetMask(), Anope::string(this->ignores[i]))) - return true; - return false; -} - -MemoInfo *MemoInfo::GetMemoInfo(const Anope::string &target, bool &ischan) -{ - if (!target.empty() && target[0] == '#') - { - ischan = true; - ChannelInfo *ci = ChannelInfo::Find(target); - if (ci != NULL) - return &ci->memos; - } - else - { - ischan = false; - NickAlias *na = NickAlias::Find(target); - if (na != NULL) - return &na->nc->memos; - } - - return NULL; -} - diff --git a/src/messages.cpp b/src/messages.cpp deleted file mode 100644 index ee02cc473..000000000 --- a/src/messages.cpp +++ /dev/null @@ -1,502 +0,0 @@ -/* Common message handlers - * - * (C) 2003-2016 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 "services.h" -#include "modules.h" -#include "users.h" -#include "protocol.h" -#include "config.h" -#include "uplink.h" -#include "opertype.h" -#include "messages.h" -#include "servers.h" -#include "channels.h" - -using namespace Message; - -void Away::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - const Anope::string &msg = !params.empty() ? params[0] : ""; - - FOREACH_MOD(OnUserAway, (source.GetUser(), msg)); - if (!msg.empty()) - Log(source.GetUser(), "away") << "is now away: " << msg; - else - Log(source.GetUser(), "away") << "is no longer away"; -} - -void Capab::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - if (params.size() == 1) - { - spacesepstream sep(params[0]); - Anope::string token; - while (sep.GetToken(token)) - Servers::Capab.insert(token); - } - else - for (unsigned i = 0; i < params.size(); ++i) - Servers::Capab.insert(params[i]); -} - -void Error::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - Log(LOG_TERMINAL) << "ERROR: " << params[0]; - Anope::QuitReason = "Received ERROR from uplink: " + params[0]; - Anope::Quitting = true; -} - -void Invite::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - User *targ = User::Find(params[0]); - Channel *c = Channel::Find(params[1]); - - if (!targ || targ->server != Me || !c || c->FindUser(targ)) - return; - - FOREACH_MOD(OnInvite, (source.GetUser(), c, targ)); -} - -void Join::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - User *user = source.GetUser(); - const Anope::string &channels = params[0]; - - Anope::string channel; - commasepstream sep(channels); - - while (sep.GetToken(channel)) - { - /* Special case for /join 0 */ - if (channel == "0") - { - for (User::ChanUserList::iterator it = user->chans.begin(), it_end = user->chans.end(); it != it_end; ) - { - ChanUserContainer *cc = it->second; - Channel *c = cc->chan; - ++it; - - FOREACH_MOD(OnPrePartChannel, (user, c)); - cc->chan->DeleteUser(user); - FOREACH_MOD(OnPartChannel, (user, c, c->name, "")); - } - continue; - } - - std::list<SJoinUser> users; - users.push_back(std::make_pair(ChannelStatus(), user)); - - Channel *chan = Channel::Find(channel); - SJoin(source, channel, chan ? chan->creation_time : Anope::CurTime, "", users); - } -} - -void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, const Anope::string &modes, const std::list<SJoinUser> &users) -{ - bool created; - Channel *c = Channel::FindOrCreate(chan, created, ts ? ts : Anope::CurTime); - bool keep_their_modes = true; - - if (created) - c->syncing = true; - /* Some IRCds do not include a TS */ - else if (!ts) - ; - /* Our creation time is newer than what the server gave us, so reset the channel to the older time */ - else if (c->creation_time > ts) - { - c->creation_time = ts; - c->Reset(); - } - /* Their TS is newer, don't accept any modes from them */ - else if (ts > c->creation_time) - keep_their_modes = false; - - /* Update the modes for the channel */ - if (keep_their_modes && !modes.empty()) - /* If we are syncing, mlock is checked later in Channel::Sync. It is important to not check it here - * so that Channel::SetCorrectModes can correctly detect the presence of channel mode +r. - */ - c->SetModesInternal(source, modes, ts, !c->syncing); - - for (std::list<SJoinUser>::const_iterator it = users.begin(), it_end = users.end(); it != it_end; ++it) - { - const ChannelStatus &status = it->first; - User *u = it->second; - keep_their_modes = ts <= c->creation_time; // OnJoinChannel can call modules which can modify this channel's ts - - if (c->FindUser(u)) - continue; - - /* Add the user to the channel */ - c->JoinUser(u, keep_their_modes ? &status : NULL); - - /* Check if the user is allowed to join */ - if (c->CheckKick(u)) - continue; - - /* Set whatever modes the user should have, and remove any that - * they aren't allowed to have (secureops etc). - */ - c->SetCorrectModes(u, true); - - FOREACH_MOD(OnJoinChannel, (u, c)); - } - - /* Channel is done syncing */ - if (c->syncing) - { - /* Sync the channel (mode lock, topic, etc) */ - /* the channel is synced when the netmerge is complete */ - Server *src = source.GetServer() ? source.GetServer() : Me; - if (src && src->IsSynced()) - { - c->Sync(); - - if (c->CheckDelete()) - c->QueueForDeletion(); - } - } -} - -void Kick::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - const Anope::string &channel = params[0]; - const Anope::string &users = params[1]; - const Anope::string &reason = params.size() > 2 ? params[2] : ""; - - Channel *c = Channel::Find(channel); - if (!c) - return; - - Anope::string user; - commasepstream sep(users); - - while (sep.GetToken(user)) - c->KickInternal(source, user, reason); -} - -void Kill::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - User *u = User::Find(params[0]); - BotInfo *bi; - - if (!u) - return; - - /* Recover if someone kills us. */ - if (u->server == Me && (bi = dynamic_cast<BotInfo *>(u))) - { - static time_t last_time = 0; - - if (last_time == Anope::CurTime) - { - Anope::QuitReason = "Kill loop detected. Are Services U:Lined?"; - Anope::Quitting = true; - return; - } - last_time = Anope::CurTime; - - bi->OnKill(); - } - else - u->KillInternal(source, params[1]); -} - -void Message::Mode::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - Anope::string buf; - for (unsigned i = 1; i < params.size(); ++i) - buf += " " + params[i]; - - if (IRCD->IsChannelValid(params[0])) - { - Channel *c = Channel::Find(params[0]); - - if (c) - c->SetModesInternal(source, buf.substr(1), 0); - } - else - { - User *u = User::Find(params[0]); - - if (u) - u->SetModesInternal(source, "%s", buf.substr(1).c_str()); - } -} - -/* XXX We should cache the file somewhere not open/read/close it on every request */ -void MOTD::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - Server *s = Server::Find(params[0]); - if (s != Me) - return; - - FILE *f = fopen(Config->GetBlock("serverinfo")->Get<const Anope::string>("motd").c_str(), "r"); - if (f) - { - IRCD->SendNumeric(375, source.GetSource(), ":- %s Message of the Day", s->GetName().c_str()); - char buf[BUFSIZE]; - while (fgets(buf, sizeof(buf), f)) - { - buf[strlen(buf) - 1] = 0; - IRCD->SendNumeric(372, source.GetSource(), ":- %s", buf); - } - fclose(f); - IRCD->SendNumeric(376, source.GetSource(), ":End of /MOTD command."); - } - else - IRCD->SendNumeric(422, source.GetSource(), ":- MOTD file not found! Please contact your IRC administrator."); -} - -void Notice::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - Anope::string message = params[1]; - - User *u = source.GetUser(); - - /* ignore channel notices */ - if (!IRCD->IsChannelValid(params[0])) - { - BotInfo *bi = BotInfo::Find(params[0]); - if (!bi) - return; - FOREACH_MOD(OnBotNotice, (u, bi, message)); - } -} - -void Part::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - User *u = source.GetUser(); - const Anope::string &reason = params.size() > 1 ? params[1] : ""; - - Anope::string channel; - commasepstream sep(params[0]); - - while (sep.GetToken(channel)) - { - Channel *c = Channel::Find(channel); - - if (!c || !u->FindChannel(c)) - continue; - - Log(u, c, "part") << "Reason: " << (!reason.empty() ? reason : "No reason"); - FOREACH_MOD(OnPrePartChannel, (u, c)); - c->DeleteUser(u); - FOREACH_MOD(OnPartChannel, (u, c, c->name, !reason.empty() ? reason : "")); - } -} - -void Ping::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - IRCD->SendPong(params.size() > 1 ? params[1] : Me->GetSID(), params[0]); -} - -void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - const Anope::string &receiver = params[0]; - Anope::string message = params[1]; - - User *u = source.GetUser(); - - if (IRCD->IsChannelValid(receiver)) - { - Channel *c = Channel::Find(receiver); - if (c) - { - FOREACH_MOD(OnPrivmsg, (u, c, message)); - } - } - else - { - /* If a server is specified (nick@server format), make sure it matches - * us, and strip it off. */ - Anope::string botname = receiver; - size_t s = receiver.find('@'); - bool nick_only = false; - if (s != Anope::string::npos) - { - Anope::string servername(receiver.begin() + s + 1, receiver.end()); - botname = botname.substr(0, s); - nick_only = true; - if (!servername.equals_ci(Me->GetName())) - return; - } - else if (!IRCD->RequiresID && Config->UseStrictPrivmsg) - { - BotInfo *bi = BotInfo::Find(receiver); - if (!bi) - return; - Log(LOG_DEBUG) << "Ignored PRIVMSG without @ from " << u->nick; - u->SendMessage(bi, _("\"/msg %s\" is no longer supported. Use \"/msg %s@%s\" or \"/%s\" instead."), bi->nick.c_str(), bi->nick.c_str(), Me->GetName().c_str(), bi->nick.c_str()); - return; - } - - BotInfo *bi = BotInfo::Find(botname, nick_only); - - if (bi) - { - if (message[0] == '\1' && message[message.length() - 1] == '\1') - { - if (message.substr(0, 6).equals_ci("\1PING ")) - { - Anope::string buf = message; - buf.erase(buf.begin()); - buf.erase(buf.end() - 1); - IRCD->SendCTCP(bi, u->nick, "%s", buf.c_str()); - } - else if (message.substr(0, 9).equals_ci("\1VERSION\1")) - { - Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); - IRCD->SendCTCP(bi, u->nick, "VERSION Anope-%s %s :%s - (%s) -- %s", Anope::Version().c_str(), Me->GetName().c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()); - } - return; - } - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnBotPrivmsg, MOD_RESULT, (u, bi, message)); - if (MOD_RESULT == EVENT_STOP) - return; - - bi->OnMessage(u, message); - } - } - - return; -} - -void Quit::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - const Anope::string &reason = params[0]; - User *user = source.GetUser(); - - Log(user, "quit") << "quit (Reason: " << (!reason.empty() ? reason : "no reason") << ")"; - - user->Quit(reason); -} - -void SQuit::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - Server *s = Server::Find(params[0]); - - if (!s) - { - Log(LOG_DEBUG) << "SQUIT for nonexistent server " << params[0]; - return; - } - - if (s == Me) - { - if (Me->GetLinks().empty()) - return; - - s = Me->GetLinks().front(); - } - - s->Delete(s->GetName() + " " + s->GetUplink()->GetName()); -} - -void Stats::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - User *u = source.GetUser(); - - switch (params[0][0]) - { - case 'l': - if (u->HasMode("OPER")) - { - IRCD->SendNumeric(211, source.GetSource(), "Server SendBuf SentBytes SentMsgs RecvBuf RecvBytes RecvMsgs ConnTime"); - IRCD->SendNumeric(211, source.GetSource(), "%s %d %d %d %d %d %d %ld", Config->Uplinks[Anope::CurrentUplink].host.c_str(), UplinkSock->WriteBufferLen(), TotalWritten, -1, UplinkSock->ReadBufferLen(), TotalRead, -1, static_cast<long>(Anope::CurTime - Anope::StartTime)); - } - - IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]); - break; - case 'o': - case 'O': - /* Check whether the user is an operator */ - if (!u->HasMode("OPER") && Config->GetBlock("options")->Get<bool>("hidestatso")) - IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]); - else - { - for (unsigned i = 0; i < Oper::opers.size(); ++i) - { - Oper *o = Oper::opers[i]; - - const NickAlias *na = NickAlias::Find(o->name); - if (na) - IRCD->SendNumeric(243, source.GetSource(), "O * * %s %s 0", o->name.c_str(), o->ot->GetName().replace_all_cs(" ", "_").c_str()); - } - - IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]); - } - - break; - case 'u': - { - long uptime = static_cast<long>(Anope::CurTime - Anope::StartTime); - IRCD->SendNumeric(242, source.GetSource(), ":Services up %d day%s, %02d:%02d:%02d", uptime / 86400, uptime / 86400 == 1 ? "" : "s", (uptime / 3600) % 24, (uptime / 60) % 60, uptime % 60); - IRCD->SendNumeric(250, source.GetSource(), ":Current users: %d (%d ops); maximum %d", UserListByNick.size(), OperCount, MaxUserCount); - IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]); - break; - } /* case 'u' */ - - default: - IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]); - } - - return; -} - -void Time::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - time_t t; - time(&t); - struct tm *tm = localtime(&t); - char buf[64]; - strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y %Z", tm); - IRCD->SendNumeric(391, source.GetSource(), "%s :%s", Me->GetName().c_str(), buf); - return; -} - -void Topic::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - Channel *c = Channel::Find(params[0]); - if (c) - c->ChangeTopicInternal(source.GetUser(), source.GetSource(), params[1], Anope::CurTime); - - return; -} - -void Version::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); - IRCD->SendNumeric(351, source.GetSource(), "Anope-%s %s :%s -(%s) -- %s", Anope::Version().c_str(), Me->GetName().c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()); -} - -void Whois::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) -{ - User *u = User::Find(params[0]); - - if (u && u->server == Me) - { - const BotInfo *bi = BotInfo::Find(u->GetUID()); - IRCD->SendNumeric(311, source.GetSource(), "%s %s %s * :%s", u->nick.c_str(), u->GetIdent().c_str(), u->host.c_str(), u->realname.c_str()); - if (bi) - IRCD->SendNumeric(307, source.GetSource(), "%s :is a registered nick", bi->nick.c_str()); - IRCD->SendNumeric(312, source.GetSource(), "%s %s :%s", u->nick.c_str(), Me->GetName().c_str(), Config->GetBlock("serverinfo")->Get<const Anope::string>("description").c_str()); - if (bi) - IRCD->SendNumeric(317, source.GetSource(), "%s %ld %ld :seconds idle, signon time", bi->nick.c_str(), static_cast<long>(Anope::CurTime - bi->lastmsg), static_cast<long>(bi->signon)); - IRCD->SendNumeric(318, source.GetSource(), "%s :End of /WHOIS list.", u->nick.c_str()); - } - else - IRCD->SendNumeric(401, source.GetSource(), "%s :No such user.", params[0].c_str()); -} - diff --git a/src/misc.cpp b/src/misc.cpp index 0938a033c..939d06498 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -1,12 +1,20 @@ -/* Miscellaneous routines. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -16,8 +24,8 @@ #include "config.h" #include "bots.h" #include "language.h" -#include "regexpr.h" #include "sockets.h" +#include "event.h" #include <errno.h> #include <sys/types.h> @@ -27,11 +35,13 @@ #include <netdb.h> #endif -NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(true), desc(descending) +NumberList::NumberList(const Anope::string &list, bool descending, std::function<void(unsigned int)> nf, std::function<void(void)> ef) : endf(ef) { Anope::string error; commasepstream sep(list); Anope::string token; + bool is_valid = true; + std::set<unsigned> numbers; sep.GetToken(token); if (token.empty()) @@ -55,11 +65,8 @@ NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(tr if (!error.empty()) { - if (!this->InvalidRange(list)) - { - is_valid = false; - return; - } + is_valid = false; + return; } } else @@ -80,47 +87,27 @@ NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(tr if (!error.empty() || !error2.empty()) { - if (!this->InvalidRange(list)) - { - is_valid = false; - return; - } + is_valid = false; + return; } } } while (sep.GetToken(token)); -} - -NumberList::~NumberList() -{ -} -void NumberList::Process() -{ if (!is_valid) return; - if (this->desc) - { - for (std::set<unsigned>::reverse_iterator it = numbers.rbegin(), it_end = numbers.rend(); it != it_end; ++it) - this->HandleNumber(*it); - } + if (descending) + std::for_each(numbers.rbegin(), numbers.rend(), nf); else - { - for (std::set<unsigned>::iterator it = numbers.begin(), it_end = numbers.end(); it != it_end; ++it) - this->HandleNumber(*it); - } -} - -void NumberList::HandleNumber(unsigned) -{ + std::for_each(numbers.begin(), numbers.end(), nf); } -bool NumberList::InvalidRange(const Anope::string &) +NumberList::~NumberList() { - return true; + endf(); } -ListFormatter::ListFormatter(NickCore *acc) : nc(acc) +ListFormatter::ListFormatter(NickServ::Account *acc) : nc(acc) { } @@ -160,14 +147,15 @@ void ListFormatter::Process(std::vector<Anope::string> &buffer) unsigned length = 0; for (std::map<Anope::string, size_t>::iterator it = lenghts.begin(), it_end = lenghts.end(); it != it_end; ++it) { - /* Break lines at 80 chars */ - if (length > 80) + if (length > Config->LineWrap) { breaks.insert(it->first); length = 0; } else + { length += it->second; + } } /* Only put a list header if more than 1 column */ @@ -214,7 +202,7 @@ void ListFormatter::Process(std::vector<Anope::string> &buffer) } } -InfoFormatter::InfoFormatter(NickCore *acc) : nc(acc), longest(0) +InfoFormatter::InfoFormatter(NickServ::Account *acc) : nc(acc), longest(0) { } @@ -311,7 +299,7 @@ time_t Anope::DoTime(const Anope::string &s) return amount; } -Anope::string Anope::Duration(time_t t, const NickCore *nc) +Anope::string Anope::Duration(time_t t, NickServ::Account *nc) { /* We first calculate everything */ time_t years = t / 31536000; @@ -352,7 +340,7 @@ Anope::string Anope::Duration(time_t t, const NickCore *nc) } } -Anope::string Anope::strftime(time_t t, const NickCore *nc, bool short_output) +Anope::string Anope::strftime(time_t t, NickServ::Account *nc, bool short_output) { tm tm = *localtime(&t); char buf[BUFSIZE]; @@ -367,10 +355,10 @@ Anope::string Anope::strftime(time_t t, const NickCore *nc, bool short_output) return Anope::string(buf) + " " + Language::Translate(nc, _("(now)")); } -Anope::string Anope::Expires(time_t expires, const NickCore *nc) +Anope::string Anope::Expires(time_t expires, NickServ::Account *nc) { if (!expires) - return Language::Translate(nc, NO_EXPIRE); + return Language::Translate(nc, _("does not expire")); else if (expires <= Anope::CurTime) return Language::Translate(nc, _("expires momentarily")); else @@ -407,38 +395,29 @@ bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case { size_t s = 0, m = 0, str_len = str.length(), mask_len = mask.length(); - if (use_regex && mask_len >= 2 && mask[0] == '/' && mask[mask.length() - 1] == '/') + if (use_regex && Config->regex_flags && mask_len >= 2 && mask[0] == '/' && mask[mask.length() - 1] == '/') { Anope::string stripped_mask = mask.substr(1, mask_len - 2); // This is often called with the same mask multiple times in a row, so cache it - static Regex *r = NULL; + static Anope::string pattern; + static std::regex r; - if (r == NULL || r->GetExpression() != stripped_mask) + if (pattern != stripped_mask) { - ServiceReference<RegexProvider> provider("Regex", Config->GetBlock("options")->Get<const Anope::string>("regexengine")); - if (provider) + try { - try - { - delete r; - r = NULL; - // This may throw - r = provider->Compile(stripped_mask); - } - catch (const RegexException &ex) - { - Log(LOG_DEBUG) << ex.GetReason(); - } + r.assign(stripped_mask.str(), Config->regex_flags); + pattern = stripped_mask; } - else + catch (const std::regex_error &error) { - delete r; - r = NULL; + Anope::Logger.Debug(error.what()); } } - if (r != NULL && r->Matches(str)) - return true; + if (pattern == stripped_mask) + if (std::regex_search(str.str(), r)) + return true; // Fall through to non regex match } @@ -509,29 +488,10 @@ bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case void Anope::Encrypt(const Anope::string &src, Anope::string &dest) { - EventReturn MOD_RESULT; - FOREACH_RESULT(OnEncrypt, MOD_RESULT, (src, dest)); + EventReturn MOD_RESULT = EventManager::Get()->Dispatch(&Event::Encrypt::OnEncrypt, src, dest); static_cast<void>(MOD_RESULT); } -bool Anope::Decrypt(const Anope::string &src, Anope::string &dest) -{ - size_t pos = src.find(':'); - if (pos == Anope::string::npos) - { - Log() << "Error: Anope::Decrypt() called with invalid password string (" << src << ")"; - return false; - } - Anope::string hashm(src.begin(), src.begin() + pos); - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnDecrypt, MOD_RESULT, (hashm, src, dest)); - if (MOD_RESULT == EVENT_ALLOW) - return true; - - return false; -} - Anope::string Anope::printf(const char *fmt, ...) { va_list args; @@ -619,40 +579,44 @@ const Anope::string Anope::LastError() Anope::string Anope::Version() { #ifdef VERSION_GIT - return stringify(VERSION_MAJOR) + "." + stringify(VERSION_MINOR) + "." + stringify(VERSION_PATCH) + VERSION_EXTRA + " (" + VERSION_GIT + ")"; + return Anope::Format("{0}.{1}.{2}{3}-{4}", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_EXTRA, VERSION_GIT); #else - return stringify(VERSION_MAJOR) + "." + stringify(VERSION_MINOR) + "." + stringify(VERSION_PATCH) + VERSION_EXTRA; + return Anope::Format("{0}.{1}.{2}{3}", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_EXTRA); #endif } Anope::string Anope::VersionShort() { - return stringify(VERSION_MAJOR) + "." + stringify(VERSION_MINOR) + "." + stringify(VERSION_PATCH); + return Anope::Format("{0}.{1}.{2}", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); } -Anope::string Anope::VersionBuildString() +Anope::string Anope::VersionBuildTime() { #ifdef REPRODUCIBLE_BUILD - Anope::string s = "build #" + stringify(BUILD); + return "unknown"; #else - Anope::string s = "build #" + stringify(BUILD) + ", compiled " + Anope::compiled; + return Anope::COMPILED; #endif +} + +Anope::string Anope::VersionFlags() +{ Anope::string flags; #ifdef DEBUG_BUILD - flags += "D"; + flags.append('D'); #endif #ifdef VERSION_GIT - flags += "G"; + flags.append('G'); #endif #ifdef _WIN32 - flags += "W"; + flags.append('W'); #endif - if (!flags.empty()) - s += ", flags " + flags; - - return s; + if (flags.empty()) + flags = "none"; + + return flags; } int Anope::VersionMajor() { return VERSION_MAJOR; } @@ -733,7 +697,7 @@ Anope::string Anope::Resolve(const Anope::string &host, int type) memset(&hints, 0, sizeof(hints)); hints.ai_family = type; - Log(LOG_DEBUG_2) << "Resolver: BlockingQuery: Looking up " << host; + Anope::Logger.Debug2("Resolver: BlockingQuery: Looking up {0}", host); addrinfo *addrresult = NULL; if (getaddrinfo(host.c_str(), NULL, &hints, &addrresult) == 0) @@ -741,7 +705,7 @@ Anope::string Anope::Resolve(const Anope::string &host, int type) sockaddrs addr; memcpy(&addr, addrresult->ai_addr, addrresult->ai_addrlen); result = addr.addr(); - Log(LOG_DEBUG_2) << "Resolver: " << host << " -> " << result; + Anope::Logger.Debug2("Resolver: {0} -> {1}", host, result); freeaddrinfo(addrresult); } @@ -764,3 +728,40 @@ Anope::string Anope::Random(size_t len) return buf; } +const kwarg *FormatInfo::GetKwarg(const Anope::string &name) const +{ + for (const kwarg &kw : parameters) + if (kw.name == name) + return &kw; + return nullptr; +} + +void FormatInfo::Format() +{ + size_t start = 0; + size_t s = format.find('{', start); + + while (s != Anope::string::npos) + { + size_t e = format.find('}', s + 1); + if (e == Anope::string::npos) + break; + + Anope::string key = format.substr(s + 1, e - s - 1); + + // Find replacement for key + const kwarg *arg = GetKwarg(key); + + format.erase(s, e - s + 1); + if (arg != nullptr) + format.insert(s, arg->value); + + start = s + (arg != nullptr ? arg->value.length() : 0); + s = format.find('{', start); + } +} + +const Anope::string &FormatInfo::GetFormat() const +{ + return format; +} diff --git a/src/modes.cpp b/src/modes.cpp index 229945b7d..0223a9c93 100644 --- a/src/modes.cpp +++ b/src/modes.cpp @@ -1,9 +1,21 @@ -/* Mode support +/* + * Anope IRC Services * - * (C) 2008-2011 Adam <Adam@anope.org> - * (C) 2008-2016 Anope Team <team@anope.org> + * Copyright (C) 2008-2011 Adam <Adam@anope.org> + * Copyright (C) 2008-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -13,6 +25,8 @@ #include "protocol.h" #include "channels.h" #include "uplink.h" +#include "event.h" +#include "modules/chanserv.h" struct StackerInfo; @@ -36,9 +50,6 @@ static std::map<Anope::string, UserMode *> UserModesByName; /* Sorted by status */ static std::vector<ChannelModeStatus *> ChannelModesByStatus; -/* Number of generic modes we support */ -unsigned ModeManager::GenericChannelModes = 0, ModeManager::GenericUserModes = 0; - struct StackerInfo { /* Modes to be added */ @@ -46,9 +57,7 @@ struct StackerInfo /* Modes to be deleted */ std::list<std::pair<Mode *, Anope::string> > DelModes; /* Bot this is sent from */ - BotInfo *bi; - - StackerInfo() : bi(NULL) { } + User *bi = nullptr; /** Add a mode to this object * @param mode The mode @@ -124,6 +133,12 @@ Mode::~Mode() bool Mode::CanSet(User *u) const { + if (!setable) + return false; + + if (oper_only) + return u && u->HasMode("OPER"); + return true; } @@ -142,8 +157,7 @@ ChannelMode::ChannelMode(const Anope::string &cm, char mch) : Mode(cm, MC_CHANNE bool ChannelMode::CanSet(User *u) const { - EventReturn MOD_RESULT; - FOREACH_RESULT(OnCanSet, MOD_RESULT, (u, this)); + EventReturn MOD_RESULT = EventManager::Get()->Dispatch(&Event::CanSet::OnCanSet, u, this); return MOD_RESULT != EVENT_STOP; } @@ -186,6 +200,11 @@ ChannelModeParam::ChannelModeParam(const Anope::string &cm, char mch, bool ma) : this->type = MODE_PARAM; } +bool ChannelModeParam::IsValid(Anope::string &value) const +{ + return std::regex_search(value.str(), param_validation); +} + ChannelModeStatus::ChannelModeStatus(const Anope::string &mname, char modeChar, char msymbol, short mlevel) : ChannelMode(mname, modeChar), symbol(msymbol), level(mlevel) { this->type = MODE_STATUS; @@ -231,34 +250,6 @@ ChannelMode *ChannelModeVirtual<T>::Wrap(Anope::string ¶m) template class ChannelModeVirtual<ChannelMode>; template class ChannelModeVirtual<ChannelModeList>; -bool UserModeOperOnly::CanSet(User *u) const -{ - return u && u->HasMode("OPER"); -} - -bool UserModeNoone::CanSet(User *u) const -{ - return false; -} - -bool ChannelModeKey::IsValid(Anope::string &value) const -{ - if (!value.empty() && value.find(':') == Anope::string::npos && value.find(',') == Anope::string::npos) - return true; - - return false; -} - -bool ChannelModeOperOnly::CanSet(User *u) const -{ - return u && u->HasMode("OPER"); -} - -bool ChannelModeNoone::CanSet(User *u) const -{ - return false; -} - void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string ¶m) { bool is_param = mode->type == MODE_PARAM; @@ -313,7 +304,7 @@ void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string ¶m) static class ModePipe : public Pipe { public: - void OnNotify() + void OnNotify() override { ModeManager::ProcessModes(); } @@ -395,15 +386,10 @@ bool ModeManager::AddUserMode(UserMode *um) { if (ModeManager::FindUserModeByChar(um->mchar) != NULL) return false; + if (ModeManager::FindUserModeByName(um->name) != NULL) return false; - if (um->name.empty()) - { - um->name = stringify(++GenericUserModes); - Log() << "ModeManager: Added generic support for user mode " << um->mchar; - } - unsigned want = um->mchar; if (want >= UserModesIdx.size()) UserModesIdx.resize(want + 1); @@ -413,7 +399,7 @@ bool ModeManager::AddUserMode(UserMode *um) UserModes.push_back(um); - FOREACH_MOD(OnUserModeAdd, (um)); + EventManager::Get()->Dispatch(&Event::UserModeAdd::OnUserModeAdd, um); return true; } @@ -425,12 +411,6 @@ bool ModeManager::AddChannelMode(ChannelMode *cm) if (ModeManager::FindChannelModeByName(cm->name) != NULL) return false; - if (cm->name.empty()) - { - cm->name = stringify(++GenericChannelModes); - Log() << "ModeManager: Added generic support for channel mode " << cm->mchar; - } - if (cm->mchar) { unsigned want = cm->mchar; @@ -454,7 +434,7 @@ bool ModeManager::AddChannelMode(ChannelMode *cm) ChannelModes.push_back(cm); - FOREACH_MOD(OnChannelModeAdd, (cm)); + EventManager::Get()->Dispatch(&Event::ChannelModeAdd::OnChannelModeAdd, cm); for (unsigned int i = 0; i < ChannelModes.size(); ++i) ChannelModes[i]->Check(); @@ -570,7 +550,7 @@ char ModeManager::GetStatusChar(char value) ChannelMode *cm = ChannelModesIdx[want]; if (cm == NULL || cm->type != MODE_STATUS || cm->mchar == value) return 0; - + return cm->mchar; } @@ -610,13 +590,13 @@ void ModeManager::RebuildStatusModes() std::sort(ChannelModesByStatus.begin(), ChannelModesByStatus.end(), statuscmp); } -void ModeManager::StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, const Anope::string &Param) +void ModeManager::StackerAdd(User *bi, Channel *c, ChannelMode *cm, bool Set, const Anope::string &Param) { StackerInfo *s = GetInfo(ChannelStackerObjects, c); s->AddMode(cm, Set, Param); if (bi) s->bi = bi; - else + else if (c->ci) s->bi = c->ci->WhoSends(); if (!modePipe) @@ -624,7 +604,7 @@ void ModeManager::StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, modePipe->Notify(); } -void ModeManager::StackerAdd(BotInfo *bi, User *u, UserMode *um, bool Set, const Anope::string &Param) +void ModeManager::StackerAdd(User *bi, User *u, UserMode *um, bool Set, const Anope::string &Param) { StackerInfo *s = GetInfo(UserStackerObjects, u); s->AddMode(um, Set, Param); @@ -647,7 +627,7 @@ void ModeManager::ProcessModes() std::list<Anope::string> ModeStrings = BuildModeStrings(s); for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit) - IRCD->SendMode(s->bi, u, lit->c_str()); + IRCD->SendMode(s->bi, u, *lit); delete it->second; } UserStackerObjects.clear(); @@ -662,7 +642,7 @@ void ModeManager::ProcessModes() std::list<Anope::string> ModeStrings = BuildModeStrings(s); for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit) - IRCD->SendMode(s->bi, c, lit->c_str()); + IRCD->SendMode(s->bi, c, *lit); delete it->second; } ChannelStackerObjects.clear(); @@ -678,7 +658,7 @@ static void StackerDel(std::map<T *, StackerInfo *> &map, T *obj) StackerInfo *si = it->second; std::list<Anope::string> ModeStrings = BuildModeStrings(si); for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit) - IRCD->SendMode(si->bi, obj, lit->c_str()); + IRCD->SendMode(si->bi, obj, *lit); delete si; map.erase(it); @@ -742,7 +722,59 @@ void ModeManager::StackerDel(Mode *m) } } -Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0), family(0) +void ModeManager::Apply(Configuration::Conf *old) +{ +#warning "remove old modes" + + for (Configuration::Channelmode &cm : Config->Channelmodes) + { + ChannelMode *mode; + + if (cm.list) + Anope::Logger.Log("Creating channelmode list {0} ({1})", cm.name, cm.character); + else if (cm.status) + Anope::Logger.Log("Creating channelmode status {0} ({1})", cm.name, cm.character); + else if (cm.param) + Anope::Logger.Log("Creating channelmode param {0} ({1})", cm.name, cm.character); + else + Anope::Logger.Log("Creating channelmode {0} ({1})", cm.name, cm.character); + + if (cm.list) + mode = new ChannelModeList(cm.name, cm.character); + else if (cm.status) + mode = new ChannelModeStatus(cm.name, cm.character, cm.status, cm.level); + else if (cm.param) + mode = new ChannelModeParam(cm.name, cm.character, !cm.param_unset); + else + mode = new ChannelMode(cm.name, cm.character); + + mode->SetSetable(cm.setable); + mode->SetOperOnly(cm.oper_only); + + if (!AddChannelMode(mode)) + delete mode; + } + + for (Configuration::Usermode &um : Config->Usermodes) + { + UserMode *mode; + + Anope::Logger.Log("Creating usermode {0} ({1})", um.name, um.character); + + if (um.param) + mode = new UserModeParam(um.name, um.character); + else + mode = new UserMode(um.name, um.character); + + mode->SetSetable(um.setable); + mode->SetOperOnly(um.oper_only); + + if (!AddUserMode(mode)) + delete mode; + } +} + +Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0) { Anope::string n, u, h; @@ -769,21 +801,21 @@ Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh else this->nick = fh; } - + at = this->host.find('#'); if (at != Anope::string::npos) { this->real = this->host.substr(at + 1); this->host = this->host.substr(0, at); } - + /* If the mask is all *'s it will match anything, so just clear it */ if (this->nick.find_first_not_of("*") == Anope::string::npos) this->nick.clear(); - + if (this->user.find_first_not_of("*") == Anope::string::npos) this->user.clear(); - + if (this->host.find_first_not_of("*") == Anope::string::npos) this->host.clear(); else @@ -803,12 +835,10 @@ Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh { this->cidr_len = convertTo<unsigned short>(cidr_range); - /* If we got here, cidr_len is a valid number. */ - this->host = cidr_ip; this->family = addr.family(); - Log(LOG_DEBUG) << "Ban " << mask << " has cidr " << this->cidr_len; + Anope::Logger.Log("Ban {0} has cidr {1}", mask, this->cidr_len); } } catch (const ConvertException &) { } @@ -831,6 +861,7 @@ const Anope::string Entry::GetNUHMask() const h = host.empty() ? "*" : host, r = real.empty() ? "" : "#" + real, c; + switch (family) { case AF_INET: @@ -842,8 +873,7 @@ const Anope::string Entry::GetNUHMask() const c = "/" + stringify(cidr_len); break; } - - return n + "!" + u + "@" + h + c + r; + return n + "!" + u + "@" + h + r + c; } bool Entry::Matches(User *u, bool full) const @@ -888,10 +918,10 @@ bool Entry::Matches(User *u, bool full) const else if (!this->host.empty() && !Anope::Match(u->GetDisplayedHost(), this->host) && !Anope::Match(u->GetCloakedHost(), this->host) && (!full || (!Anope::Match(u->host, this->host) && !Anope::Match(u->ip.addr(), this->host)))) ret = false; - + if (!this->real.empty() && !Anope::Match(u->realname, this->real)) ret = false; - + return ret; } diff --git a/src/module.cpp b/src/module.cpp index 3e377efec..7269800d5 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -1,21 +1,34 @@ -/* Modular support +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "modules.h" #include "language.h" -#include "account.h" #ifdef GETTEXT_FOUND # include <libintl.h> #endif -Module::Module(const Anope::string &modname, const Anope::string &, ModType modtype) : name(modname), type(modtype) +Module::Module(const Anope::string &modname, const Anope::string &, ModType modtype) + : name(modname) + , type(modtype) + , logger(this) { this->handle = NULL; this->permanent = false; @@ -23,7 +36,9 @@ Module::Module(const Anope::string &modname, const Anope::string &, ModType modt this->SetVersion(Anope::Version()); if (type & VENDOR) + { this->SetAuthor("Anope"); + } else { /* Not vendor implies third */ @@ -33,14 +48,14 @@ Module::Module(const Anope::string &modname, const Anope::string &, ModType modt if (ModuleManager::FindModule(this->name)) throw CoreException("Module already exists!"); - + if (Anope::NoThird && type & THIRD) throw ModuleException("Third party modules may not be loaded"); ModuleManager::Modules.push_back(this); #if GETTEXT_FOUND - for (unsigned i = 0; i < Language::Languages.size(); ++i) + for (unsigned int i = 0; i < Language::Languages.size(); ++i) { /* Remove .UTF-8 or any other suffix */ Anope::string lang; @@ -49,10 +64,12 @@ Module::Module(const Anope::string &modname, const Anope::string &, ModType modt if (Anope::IsFile(Anope::LocaleDir + "/" + lang + "/LC_MESSAGES/" + modname + ".mo")) { if (!bindtextdomain(this->name.c_str(), Anope::LocaleDir.c_str())) - Log() << "Error calling bindtextdomain, " << Anope::LastError(); + { + Anope::Logger.Log("Error calling bindtextdomain, {0}", Anope::LastError()); + } else { - Log() << "Found language file " << lang << " for " << modname; + Anope::Logger.Log("Found language file {0} for {1}", lang, modname); Language::Domains.push_back(modname); } break; @@ -63,11 +80,6 @@ Module::Module(const Anope::string &modname, const Anope::string &, ModType modt Module::~Module() { - UnsetExtensibles(); - - /* Detach all event hooks for this module */ - ModuleManager::DetachAll(this); - IdentifyRequest::ModuleUnload(this); /* Clear any active timers this module has */ TimerManager::DeleteTimersFor(this); @@ -82,6 +94,11 @@ Module::~Module() #endif } +const Anope::string &Module::GetName() const +{ + return this->name; +} + void Module::SetPermanent(bool state) { this->permanent = state; @@ -102,10 +119,6 @@ void Module::SetAuthor(const Anope::string &nauthor) this->author = nauthor; } -void Module::Prioritize() -{ -} - ModuleVersion::ModuleVersion(const ModuleVersionC &ver) { version_major = ver.version_major; diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp index 2cda9e256..d4883eccb 100644 --- a/src/modulemanager.cpp +++ b/src/modulemanager.cpp @@ -1,16 +1,27 @@ -/* Modular support +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "modules.h" #include "users.h" -#include "regchannel.h" #include "config.h" +#include "event.h" #include <sys/types.h> #include <sys/stat.h> @@ -21,22 +32,31 @@ #endif std::list<Module *> ModuleManager::Modules; -std::vector<Module *> ModuleManager::EventHandlers[I_SIZE]; + +void ModuleDef::Depends(const Anope::string &modname) +{ + dependencies.push_back(modname); +} + +const std::vector<Anope::string> &ModuleDef::GetDependencies() +{ + return dependencies; +} #ifdef _WIN32 void ModuleManager::CleanupRuntimeDirectory() { Anope::string dirbuf = Anope::DataDir + "/runtime"; - Log(LOG_DEBUG) << "Cleaning out Module run time directory (" << dirbuf << ") - this may take a moment please wait"; + Anope::Logger.Debug("Cleaning out Module run time directory ({0}) - this may take a moment please wait", dirbuf); DIR *dirp = opendir(dirbuf.c_str()); if (!dirp) { - Log(LOG_DEBUG) << "Cannot open directory (" << dirbuf << ")"; + Anope::Logger.Debug("Cannot open directory ({0})", dirbuf); return; } - + for (dirent *dp; (dp = readdir(dirp));) { if (!dp->d_ino) @@ -62,17 +82,17 @@ void ModuleManager::CleanupRuntimeDirectory() static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &output) { Anope::string input = Anope::ModuleDir + "/modules/" + name + ".so"; - + struct stat s; if (stat(input.c_str(), &s) == -1) return MOD_ERR_NOEXIST; else if (!S_ISREG(s.st_mode)) return MOD_ERR_NOEXIST; - + std::ifstream source(input.c_str(), std::ios_base::in | std::ios_base::binary); if (!source.is_open()) return MOD_ERR_NOEXIST; - + char *tmp_output = strdup(output.c_str()); int target_fd = mkstemp(tmp_output); if (target_fd == -1 || close(target_fd) == -1) @@ -84,8 +104,8 @@ static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &out output = tmp_output; free(tmp_output); - Log(LOG_DEBUG_2) << "Runtime module location: " << output; - + Anope::Logger.Debug2("Runtime module location: {0}", output); + std::ofstream target(output.c_str(), std::ios_base::in | std::ios_base::binary); if (!target.is_open()) { @@ -103,7 +123,7 @@ static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &out target.write(buffer, read_len); want -= read_len; } - + source.close(); target.close(); @@ -111,22 +131,6 @@ static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &out } #endif -/* This code was found online at http://www.linuxjournal.com/article/3687#comment-26593 - * - * This function will take a pointer from either dlsym or GetProcAddress and cast it in - * a way that won't cause C++ warnings/errors to come up. - */ -template <class TYPE> static TYPE function_cast(void *symbol) -{ - union - { - void *symbol; - TYPE function; - } cast; - cast.symbol = symbol; - return cast.function; -} - ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) { if (modname.empty()) @@ -135,24 +139,24 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) if (FindModule(modname)) return MOD_ERR_EXISTS; - Log(LOG_DEBUG) << "Trying to load module: " << modname; + Anope::Logger.Debug("Trying to load module: {0}", modname); #ifdef _WIN32 /* Generate the filename for the temporary copy of the module */ - Anope::string pbuf = Anope::DataDir + "/runtime/" + modname + ".so.XXXXXX"; + Anope::string pbuf = Anope::DataDir + "/runtime/" + modname.replace_all_cs("/", "_") + ".so.XXXXXX"; /* Don't skip return value checking! -GD */ ModuleReturn ret = moduleCopyFile(modname, pbuf); if (ret != MOD_ERR_OK) { if (ret == MOD_ERR_NOEXIST) - Log(LOG_TERMINAL) << "Error while loading " << modname << " (file does not exist)"; + Anope::Logger.Terminal(_("Error while loading {0} (file does not exist)"), modname); else if (ret == MOD_ERR_FILE_IO) - Log(LOG_TERMINAL) << "Error while loading " << modname << " (file IO error, check file permissions and diskspace)"; + Anope::Logger.Terminal(_("Error while loading {0} (file IO error, check file permissions and diskspace)"), modname); return ret; } #else - Anope::string pbuf = Anope::ModuleDir + "/modules/" + modname + ".so"; + Anope::string pbuf = Anope::ModuleDir + "/modules/" + modname.replace_all_cs("/", "_") + ".so"; #endif dlerror(); @@ -161,41 +165,53 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) if (!handle) { if (err && *err) - Log() << err; + Anope::Logger.Log(err); + return MOD_ERR_NOLOAD; + } + + dlerror(); + AnopeModule *module = static_cast<AnopeModule *>(dlsym(handle, "AnopeMod")); + err = dlerror(); + if (!module || module->api_version != ANOPE_MODAPI_VER) + { + Anope::Logger.Log("No module symbols function found, not an Anope module"); + if (err && *err) + Anope::Logger.Log(err); + dlclose(handle); return MOD_ERR_NOLOAD; } try { - ModuleVersion v = GetVersion(handle); + ModuleVersion v = module->version(); if (v.GetMajor() < Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() < Anope::VersionMinor())) { - Log() << "Module " << modname << " is compiled against an older version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionShort(); + Anope::Logger.Log(_("Module {0} is compiled against an older version of Anope {1}.{2}, this is {3}"), modname, v.GetMajor(), v.GetMinor(), Anope::VersionShort()); dlclose(handle); return MOD_ERR_VERSION; } else if (v.GetMajor() > Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() > Anope::VersionMinor())) { - Log() << "Module " << modname << " is compiled against a newer version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionShort(); + Anope::Logger.Log(_("Module {0} is compiled against a newer version of Anope {1}.{2}, this is {3}"), modname, v.GetMajor(), v.GetMinor(), Anope::VersionShort()); dlclose(handle); return MOD_ERR_VERSION; } else if (v.GetPatch() < Anope::VersionPatch()) { - Log() << "Module " << modname << " is compiled against an older version of Anope, " << v.GetMajor() << "." << v.GetMinor() << "." << v.GetPatch() << ", this is " << Anope::VersionShort(); + Anope::Logger.Log(_("Module {0} is compiled against an older version of Anope, {1}.{2}.{3}, this is {4}"), modname, v.GetMajor(), v.GetMinor(), v.GetPatch(), Anope::VersionShort()); dlclose(handle); return MOD_ERR_VERSION; } else if (v.GetPatch() > Anope::VersionPatch()) { - Log() << "Module " << modname << " is compiled against a newer version of Anope, " << v.GetMajor() << "." << v.GetMinor() << "." << v.GetPatch() << ", this is " << Anope::VersionShort(); + Anope::Logger.Log(_("Module {0} is compiled against a newer version of Anope, {1}.{2}.{3}, this is {4}"), modname, v.GetMajor(), v.GetMinor(), v.GetPatch(), Anope::VersionShort()); dlclose(handle); return MOD_ERR_VERSION; } else { - Log(LOG_DEBUG_2) << "Module " << modname << " is compiled against current version of Anope " << Anope::VersionShort(); + Anope::Logger.Debug2("Module {0} is compiled against current version of Anope {1}", Anope::VersionShort()); } } catch (const ModuleException &ex) @@ -205,17 +221,7 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) return MOD_ERR_NOLOAD; } - dlerror(); - Module *(*func)(const Anope::string &, const Anope::string &) = function_cast<Module *(*)(const Anope::string &, const Anope::string &)>(dlsym(handle, "AnopeInit")); - err = dlerror(); - if (!func) - { - Log() << "No init function found, not an Anope module"; - if (err && *err) - Log(LOG_DEBUG) << err; - dlclose(handle); - return MOD_ERR_NOLOAD; - } + ModuleDef *def = module->init(); /* Create module. */ Anope::string nick; @@ -227,23 +233,25 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) ModuleReturn moderr = MOD_ERR_OK; try { - m = func(modname, nick); + m = def->Create(modname, nick); } catch (const ModuleException &ex) { - Log() << "Error while loading " << modname << ": " << ex.GetReason(); + Anope::Logger.Log(_("Error while loading {0}: {1}"), modname, ex.GetReason()); moderr = MOD_ERR_EXCEPTION; } if (moderr != MOD_ERR_OK) { if (dlclose(handle)) - Log() << dlerror(); + Anope::Logger.Log(dlerror()); return moderr; } m->filename = pbuf; m->handle = handle; + m->def = def; + m->module = module; /* Initialize config */ try @@ -252,17 +260,14 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) } catch (const ModuleException &ex) { - Log() << "Module " << modname << " couldn't load:" << ex.GetReason(); + Anope::Logger.Log(_("Module {0} couldn't load: {1}"), modname, ex.GetReason()); moderr = MOD_ERR_EXCEPTION; } catch (const ConfigException &ex) { - Log() << "Module " << modname << " couldn't load due to configuration problems: " << ex.GetReason(); + Anope::Logger.Log(_("Module {0} couldn't load due to configuration problems: {1}"), modname, ex.GetReason()); moderr = MOD_ERR_EXCEPTION; } - catch (const NotImplementedException &ex) - { - } if (moderr != MOD_ERR_OK) { @@ -270,43 +275,19 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) return moderr; } - Log(LOG_DEBUG) << "Module " << modname << " loaded."; - - /* Attach module to all events */ - for (unsigned i = 0; i < I_SIZE; ++i) - EventHandlers[i].push_back(m); - - m->Prioritize(); + Anope::Logger.Log(_("Module {0} loaded"), modname); - FOREACH_MOD(OnModuleLoad, (u, m)); + EventManager::Get()->Dispatch(&Event::ModuleLoad::OnModuleLoad, u, m); return MOD_ERR_OK; } -ModuleVersion ModuleManager::GetVersion(void *handle) -{ - dlerror(); - ModuleVersionC (*func)() = function_cast<ModuleVersionC (*)()>(dlsym(handle, "AnopeVersion"));; - if (!func) - { - Log() << "No version function found, not an Anope module"; - - const char *err = dlerror(); - if (err && *err) - Log(LOG_DEBUG) << err; - - throw ModuleException("No version"); - } - - return func(); -} - ModuleReturn ModuleManager::UnloadModule(Module *m, User *u) { if (!m) return MOD_ERR_PARAMS; - FOREACH_MOD(OnModuleUnload, (u, m)); + EventManager::Get()->Dispatch(&Event::ModuleUnload::OnModuleUnload, u, m); return DeleteModule(m); } @@ -366,144 +347,29 @@ ModuleReturn ModuleManager::DeleteModule(Module *m) if (!m || !m->handle) return MOD_ERR_PARAMS; + Serialize::Unregister(m); + void *handle = m->handle; Anope::string filename = m->filename; - Log(LOG_DEBUG) << "Unloading module " << m->name; + Anope::Logger.Log("Unloading module {0}", m->name); - dlerror(); - void (*destroy_func)(Module *m) = function_cast<void (*)(Module *)>(dlsym(m->handle, "AnopeFini")); - const char *err = dlerror(); - if (!destroy_func || (err && *err)) - { - Log() << "No destroy function found for " << m->name << ", chancing delete..."; - delete m; /* we just have to chance they haven't overwrote the delete operator then... */ - } - else - destroy_func(m); /* Let the module delete it self, just in case */ + ModuleDef *def = m->def; + AnopeModule *module = m->module; + + def->Destroy(m); + module->fini(def); + dlerror(); if (dlclose(handle)) - Log() << dlerror(); + Anope::Logger.Log(dlerror()); #ifdef _WIN32 if (!filename.empty()) unlink(filename.c_str()); #endif - - return MOD_ERR_OK; -} - -void ModuleManager::DetachAll(Module *mod) -{ - for (unsigned i = 0; i < I_SIZE; ++i) - { - std::vector<Module *> &mods = EventHandlers[i]; - std::vector<Module *>::iterator it2 = std::find(mods.begin(), mods.end(), mod); - if (it2 != mods.end()) - mods.erase(it2); - } -} -bool ModuleManager::SetPriority(Module *mod, Priority s) -{ - for (unsigned i = 0; i < I_SIZE; ++i) - SetPriority(mod, static_cast<Implementation>(i), s); - - return true; -} - -bool ModuleManager::SetPriority(Module *mod, Implementation i, Priority s, Module **modules, size_t sz) -{ - /** To change the priority of a module, we first find its position in the vector, - * then we find the position of the other modules in the vector that this module - * wants to be before/after. We pick off either the first or last of these depending - * on which they want, and we make sure our module is *at least* before or after - * the first or last of this subset, depending again on the type of priority. - */ - - /* Locate our module. This is O(n) but it only occurs on module load so we're - * not too bothered about it - */ - size_t source = 0; - bool found = false; - for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x) - if (EventHandlers[i][x] == mod) - { - source = x; - found = true; - break; - } - - /* Eh? this module doesn't exist, probably trying to set priority on an event - * they're not attached to. - */ - if (!found) - return false; - - size_t swap_pos = 0; - bool swap = true; - switch (s) - { - /* Dummy value */ - case PRIORITY_DONTCARE: - swap = false; - break; - /* Module wants to be first, sod everything else */ - case PRIORITY_FIRST: - swap_pos = 0; - break; - /* Module is submissive and wants to be last... awww. */ - case PRIORITY_LAST: - if (EventHandlers[i].empty()) - swap_pos = 0; - else - swap_pos = EventHandlers[i].size() - 1; - break; - /* Place this module after a set of other modules */ - case PRIORITY_AFTER: - /* Find the latest possible position */ - swap_pos = 0; - swap = false; - for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x) - for (size_t n = 0; n < sz; ++n) - if (modules[n] && EventHandlers[i][x] == modules[n] && x >= swap_pos && source <= swap_pos) - { - swap_pos = x; - swap = true; - } - break; - /* Place this module before a set of other modules */ - case PRIORITY_BEFORE: - swap_pos = EventHandlers[i].size() - 1; - swap = false; - for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x) - for (size_t n = 0; n < sz; ++n) - if (modules[n] && EventHandlers[i][x] == modules[n] && x <= swap_pos && source >= swap_pos) - { - swap = true; - swap_pos = x; - } - } - - /* Do we need to swap? */ - if (swap && swap_pos != source) - { - /* Suggestion from Phoenix, "shuffle" the modules to better retain call order */ - int incrmnt = 1; - - if (source > swap_pos) - incrmnt = -1; - - for (unsigned j = source; j != swap_pos; j += incrmnt) - { - if (j + incrmnt > EventHandlers[i].size() - 1 || (!j && incrmnt == -1)) - continue; - - std::swap(EventHandlers[i][j], EventHandlers[i][j + incrmnt]); - } - } - - return true; + return MOD_ERR_OK; } void ModuleManager::UnloadAll() @@ -516,7 +382,7 @@ void ModuleManager::UnloadAll() if ((m->type & j) == m->type) modules.push_back(m->name); } - + for (unsigned i = 0; i < modules.size(); ++i) { Module *m = FindModule(modules[i]); diff --git a/src/nickalias.cpp b/src/nickalias.cpp deleted file mode 100644 index 795298cba..000000000 --- a/src/nickalias.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* - * - * (C) 2003-2016 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 "services.h" -#include "account.h" -#include "modules.h" -#include "opertype.h" -#include "protocol.h" -#include "users.h" -#include "servers.h" -#include "config.h" - -Serialize::Checker<nickalias_map> NickAliasList("NickAlias"); - -NickAlias::NickAlias(const Anope::string &nickname, NickCore* nickcore) : Serializable("NickAlias") -{ - if (nickname.empty()) - throw CoreException("Empty nick passed to NickAlias constructor"); - else if (!nickcore) - throw CoreException("Empty nickcore passed to NickAlias constructor"); - - this->time_registered = this->last_seen = Anope::CurTime; - this->nick = nickname; - this->nc = nickcore; - nickcore->aliases->push_back(this); - - size_t old = NickAliasList->size(); - (*NickAliasList)[this->nick] = this; - if (old == NickAliasList->size()) - Log(LOG_DEBUG) << "Duplicate nick " << nickname << " in nickalias table"; - - if (this->nc->o == NULL) - { - Oper *o = Oper::Find(this->nick); - if (o == NULL) - o = Oper::Find(this->nc->display); - nickcore->o = o; - if (this->nc->o != NULL) - Log() << "Tied oper " << this->nc->display << " to type " << this->nc->o->ot->GetName(); - } -} - -NickAlias::~NickAlias() -{ - UnsetExtensibles(); - - FOREACH_MOD(OnDelNick, (this)); - - /* Accept nicks that have no core, because of database load functions */ - if (this->nc) - { - /* Next: see if our core is still useful. */ - std::vector<NickAlias *>::iterator it = std::find(this->nc->aliases->begin(), this->nc->aliases->end(), this); - if (it != this->nc->aliases->end()) - this->nc->aliases->erase(it); - if (this->nc->aliases->empty()) - { - delete this->nc; - this->nc = NULL; - } - else - { - /* Display updating stuff */ - if (this->nick.equals_ci(this->nc->display)) - this->nc->SetDisplay(this->nc->aliases->front()); - } - } - - /* Remove us from the aliases list */ - NickAliasList->erase(this->nick); -} - -void NickAlias::SetVhost(const Anope::string &ident, const Anope::string &host, const Anope::string &creator, time_t created) -{ - this->vhost_ident = ident; - this->vhost_host = host; - this->vhost_creator = creator; - this->vhost_created = created; -} - -void NickAlias::RemoveVhost() -{ - this->vhost_ident.clear(); - this->vhost_host.clear(); - this->vhost_creator.clear(); - this->vhost_created = 0; -} - -bool NickAlias::HasVhost() const -{ - return !this->vhost_host.empty(); -} - -const Anope::string &NickAlias::GetVhostIdent() const -{ - return this->vhost_ident; -} - -const Anope::string &NickAlias::GetVhostHost() const -{ - return this->vhost_host; -} - -const Anope::string &NickAlias::GetVhostCreator() const -{ - return this->vhost_creator; -} - -time_t NickAlias::GetVhostCreated() const -{ - return this->vhost_created; -} - -NickAlias *NickAlias::Find(const Anope::string &nick) -{ - nickalias_map::const_iterator it = NickAliasList->find(nick); - if (it != NickAliasList->end()) - { - it->second->QueueUpdate(); - return it->second; - } - - return NULL; -} - -void NickAlias::Serialize(Serialize::Data &data) const -{ - data["nick"] << this->nick; - data["last_quit"] << this->last_quit; - data["last_realname"] << this->last_realname; - data["last_usermask"] << this->last_usermask; - data["last_realhost"] << this->last_realhost; - data.SetType("time_registered", Serialize::Data::DT_INT); data["time_registered"] << this->time_registered; - data.SetType("last_seen", Serialize::Data::DT_INT); data["last_seen"] << this->last_seen; - data["nc"] << this->nc->display; - - if (this->HasVhost()) - { - data["vhost_ident"] << this->GetVhostIdent(); - data["vhost_host"] << this->GetVhostHost(); - data["vhost_creator"] << this->GetVhostCreator(); - data["vhost_time"] << this->GetVhostCreated(); - } - - Extensible::ExtensibleSerialize(this, this, data); -} - -Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string snc, snick; - - data["nc"] >> snc; - data["nick"] >> snick; - - NickCore *core = NickCore::Find(snc); - if (core == NULL) - return NULL; - - NickAlias *na; - if (obj) - na = anope_dynamic_static_cast<NickAlias *>(obj); - else - na = new NickAlias(snick, core); - - if (na->nc != core) - { - std::vector<NickAlias *>::iterator it = std::find(na->nc->aliases->begin(), na->nc->aliases->end(), na); - if (it != na->nc->aliases->end()) - na->nc->aliases->erase(it); - - if (na->nc->aliases->empty()) - delete na->nc; - else if (na->nick.equals_ci(na->nc->display)) - na->nc->SetDisplay(na->nc->aliases->front()); - - na->nc = core; - core->aliases->push_back(na); - } - - data["last_quit"] >> na->last_quit; - data["last_realname"] >> na->last_realname; - data["last_usermask"] >> na->last_usermask; - data["last_realhost"] >> na->last_realhost; - data["time_registered"] >> na->time_registered; - data["last_seen"] >> na->last_seen; - - Anope::string vhost_ident, vhost_host, vhost_creator; - time_t vhost_time; - - data["vhost_ident"] >> vhost_ident; - data["vhost_host"] >> vhost_host; - data["vhost_creator"] >> vhost_creator; - data["vhost_time"] >> vhost_time; - - na->SetVhost(vhost_ident, vhost_host, vhost_creator, vhost_time); - - Extensible::ExtensibleUnserialize(na, na, data); - - /* compat */ - bool b; - b = false; - data["extensible:NO_EXPIRE"] >> b; - if (b) - na->Extend<bool>("NS_NO_EXPIRE"); - /* end compat */ - - return na; -} - diff --git a/src/nickcore.cpp b/src/nickcore.cpp deleted file mode 100644 index 633f5a7cb..000000000 --- a/src/nickcore.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - * - * (C) 2003-2016 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 "services.h" -#include "modules.h" -#include "account.h" -#include "config.h" - -Serialize::Checker<nickcore_map> NickCoreList("NickCore"); - -NickCore::NickCore(const Anope::string &coredisplay) : Serializable("NickCore"), chanaccess("ChannelInfo"), aliases("NickAlias") -{ - if (coredisplay.empty()) - throw CoreException("Empty display passed to NickCore constructor"); - - this->o = NULL; - this->channelcount = 0; - this->lastmail = 0; - - this->display = coredisplay; - - size_t old = NickCoreList->size(); - (*NickCoreList)[this->display] = this; - if (old == NickCoreList->size()) - Log(LOG_DEBUG) << "Duplicate account " << coredisplay << " in nickcore table?"; - - FOREACH_MOD(OnNickCoreCreate, (this)); -} - -NickCore::~NickCore() -{ - UnsetExtensibles(); - - FOREACH_MOD(OnDelCore, (this)); - - if (!this->chanaccess->empty()) - Log(LOG_DEBUG) << "Non-empty chanaccess list in destructor!"; - - for (std::list<User *>::iterator it = this->users.begin(); it != this->users.end();) - { - User *user = *it++; - user->Logout(); - } - this->users.clear(); - - NickCoreList->erase(this->display); - - this->ClearAccess(); - - if (!this->memos.memos->empty()) - { - for (unsigned i = 0, end = this->memos.memos->size(); i < end; ++i) - delete this->memos.GetMemo(i); - this->memos.memos->clear(); - } -} - -void NickCore::Serialize(Serialize::Data &data) const -{ - data["display"] << this->display; - data["pass"] << this->pass; - data["email"] << this->email; - data["language"] << this->language; - for (unsigned i = 0; i < this->access.size(); ++i) - data["access"] << this->access[i] << " "; - data["memomax"] << this->memos.memomax; - for (unsigned i = 0; i < this->memos.ignores.size(); ++i) - data["memoignores"] << this->memos.ignores[i] << " "; - Extensible::ExtensibleSerialize(this, this, data); -} - -Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data) -{ - NickCore *nc; - - Anope::string sdisplay; - - data["display"] >> sdisplay; - - if (obj) - nc = anope_dynamic_static_cast<NickCore *>(obj); - else - nc = new NickCore(sdisplay); - - data["pass"] >> nc->pass; - data["email"] >> nc->email; - data["language"] >> nc->language; - { - Anope::string buf; - data["access"] >> buf; - spacesepstream sep(buf); - nc->access.clear(); - while (sep.GetToken(buf)) - nc->access.push_back(buf); - } - data["memomax"] >> nc->memos.memomax; - { - Anope::string buf; - data["memoignores"] >> buf; - spacesepstream sep(buf); - nc->memos.ignores.clear(); - while (sep.GetToken(buf)) - nc->memos.ignores.push_back(buf); - } - - Extensible::ExtensibleUnserialize(nc, nc, data); - - /* compat */ - bool b; - b = false; - data["extensible:SECURE"] >> b; - if (b) - nc->Extend<bool>("NS_SECURE"); - b = false; - data["extensible:PRIVATE"] >> b; - if (b) - nc->Extend<bool>("NS_PRIVATE"); - b = false; - data["extensible:AUTOOP"] >> b; - if (b) - nc->Extend<bool>("AUTOOP"); - b = false; - data["extensible:HIDE_EMAIL"] >> b; - if (b) - nc->Extend<bool>("HIDE_EMAIL"); - b = false; - data["extensible:HIDE_QUIT"] >> b; - if (b) - nc->Extend<bool>("HIDE_QUIT"); - b = false; - data["extensible:MEMO_RECEIVE"] >> b; - if (b) - nc->Extend<bool>("MEMO_RECEIVE"); - b = false; - data["extensible:MEMO_SIGNON"] >> b; - if (b) - nc->Extend<bool>("MEMO_SIGNON"); - b = false; - data["extensible:KILLPROTECT"] >> b; - if (b) - nc->Extend<bool>("KILLPROTECT"); - /* end compat */ - - return nc; -} - -void NickCore::SetDisplay(const NickAlias *na) -{ - if (na->nc != this || na->nick == this->display) - return; - - FOREACH_MOD(OnChangeCoreDisplay, (this, na->nick)); - - /* this affects the serialized aliases */ - for (unsigned i = 0; i < aliases->size(); ++i) - aliases->at(i)->QueueUpdate(); - - /* Remove the core from the list */ - NickCoreList->erase(this->display); - - this->display = na->nick; - - (*NickCoreList)[this->display] = this; -} - -bool NickCore::IsServicesOper() const -{ - return this->o != NULL; -} - -void NickCore::AddAccess(const Anope::string &entry) -{ - this->access.push_back(entry); - FOREACH_MOD(OnNickAddAccess, (this, entry)); -} - -Anope::string NickCore::GetAccess(unsigned entry) const -{ - if (this->access.empty() || entry >= this->access.size()) - return ""; - return this->access[entry]; -} - -unsigned NickCore::GetAccessCount() const -{ - return this->access.size(); -} - -bool NickCore::FindAccess(const Anope::string &entry) -{ - for (unsigned i = 0, end = this->access.size(); i < end; ++i) - if (this->access[i] == entry) - return true; - - return false; -} - -void NickCore::EraseAccess(const Anope::string &entry) -{ - for (unsigned i = 0, end = this->access.size(); i < end; ++i) - if (this->access[i] == entry) - { - FOREACH_MOD(OnNickEraseAccess, (this, entry)); - this->access.erase(this->access.begin() + i); - break; - } -} - -void NickCore::ClearAccess() -{ - FOREACH_MOD(OnNickClearAccess, (this)); - this->access.clear(); -} - -bool NickCore::IsOnAccess(const User *u) const -{ - Anope::string buf = u->GetIdent() + "@" + u->host, buf2, buf3; - if (!u->vhost.empty()) - buf2 = u->GetIdent() + "@" + u->vhost; - if (!u->GetCloakedHost().empty()) - buf3 = u->GetIdent() + "@" + u->GetCloakedHost(); - - for (unsigned i = 0, end = this->access.size(); i < end; ++i) - { - Anope::string a = this->GetAccess(i); - if (Anope::Match(buf, a) || (!buf2.empty() && Anope::Match(buf2, a)) || (!buf3.empty() && Anope::Match(buf3, a))) - return true; - } - return false; -} - -void NickCore::AddChannelReference(ChannelInfo *ci) -{ - ++(*this->chanaccess)[ci]; -} - -void NickCore::RemoveChannelReference(ChannelInfo *ci) -{ - int& i = (*this->chanaccess)[ci]; - if (--i <= 0) - this->chanaccess->erase(ci); -} - -void NickCore::GetChannelReferences(std::deque<ChannelInfo *> &queue) -{ - queue.clear(); - for (std::map<ChannelInfo *, int>::iterator it = this->chanaccess->begin(), it_end = this->chanaccess->end(); it != it_end; ++it) - queue.push_back(it->first); -} - -NickCore* NickCore::Find(const Anope::string &nick) -{ - nickcore_map::const_iterator it = NickCoreList->find(nick); - if (it != NickCoreList->end()) - { - it->second->QueueUpdate(); - return it->second; - } - - return NULL; -} - diff --git a/src/opertype.cpp b/src/opertype.cpp index 9438c2ff5..c9c1b762c 100644 --- a/src/opertype.cpp +++ b/src/opertype.cpp @@ -1,9 +1,21 @@ /* + * Anope IRC Services * - * (C) 2008-2011 Robin Burchell <w00t@inspircd.org> - * (C) 2008-2016 Anope Team <team@anope.org> + * Copyright (C) 2008-2011 Robin Burchell <w00t@inspircd.org> + * Copyright (C) 2009-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -11,31 +23,99 @@ #include "opertype.h" #include "config.h" -std::vector<Oper *> Oper::opers; +Anope::string Oper::GetName() +{ + return Get(&OperBlockType::name); +} -Oper::Oper(const Anope::string &n, OperType *o) : name(n), ot(o), require_oper(false) +void Oper::SetName(const Anope::string &n) { - opers.push_back(this); + Set(&OperBlockType::name, n); } -Oper::~Oper() +Anope::string Oper::GetPassword() { - std::vector<Oper *>::iterator it = std::find(opers.begin(), opers.end(), this); - if (it != opers.end()) - opers.erase(it); + return Get(&OperBlockType::password); } -Oper *Oper::Find(const Anope::string &name) +void Oper::SetPassword(const Anope::string &s) { - for (unsigned i = 0; i < opers.size(); ++i) - { - Oper *o = opers[i]; + Set(&OperBlockType::password, s); +} + +Anope::string Oper::GetCertFP() +{ + return Get(&OperBlockType::certfp); +} + +void Oper::SetCertFP(const Anope::string &s) +{ + Set(&OperBlockType::certfp, s); +} + +Anope::string Oper::GetHost() +{ + return Get(&OperBlockType::host); +} + +void Oper::SetHost(const Anope::string &h) +{ + Set(&OperBlockType::host, h); +} + +Anope::string Oper::GetVhost() +{ + return Get(&OperBlockType::vhost); +} + +void Oper::SetVhost(const Anope::string &s) +{ + Set(&OperBlockType::vhost, s); +} - if (o->name.equals_ci(name)) +OperType *Oper::GetType() +{ + return OperType::Find(Get(&OperBlockType::type)); +} + +void Oper::SetType(OperType *t) +{ + Set(&OperBlockType::type, t->GetName()); +} + +bool Oper::GetRequireOper() +{ + return Get(&OperBlockType::require_oper); +} + +void Oper::SetRequireOper(const bool &b) +{ + Set(&OperBlockType::require_oper, b); +} + +bool Oper::HasCommand(const Anope::string &cmdstr) +{ + OperType *type = GetType(); + if (type != nullptr) + return type->HasCommand(cmdstr); + return false; +} + +bool Oper::HasPriv(const Anope::string &cmdstr) +{ + OperType *type = GetType(); + if (type != nullptr) + return type->HasPriv(cmdstr); + return false; +} + +Oper *Oper::Find(const Anope::string &name) +{ + for (Oper *o : Serialize::GetObjects<Oper *>()) + if (o->GetName() == name) return o; - } - return NULL; + return nullptr; } OperType *OperType::Find(const Anope::string &name) diff --git a/src/pipeengine.cpp b/src/pipeengine.cpp index 0953387c1..1a133641f 100644 --- a/src/pipeengine.cpp +++ b/src/pipeengine.cpp @@ -1,12 +1,20 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2010-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -48,10 +56,11 @@ Pipe::~Pipe() bool Pipe::ProcessRead() { + char dummy[512]; + while (read(this->GetFD(), dummy, sizeof(dummy)) == sizeof(dummy)); + this->OnNotify(); - char dummy[512]; - while (read(this->GetFD(), dummy, 512) == 512); return true; } @@ -76,6 +85,6 @@ bool Pipe::SetWriteBlocking(bool state) void Pipe::Notify() { - this->Write("\0", 1); + this->Write("", 1); } diff --git a/src/process.cpp b/src/process.cpp index b095ab40b..afb12b352 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -1,12 +1,20 @@ -/* Main processing code for Services. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -14,12 +22,12 @@ #include "protocol.h" #include "servers.h" #include "users.h" -#include "regchannel.h" +#include "event.h" void Anope::Process(const Anope::string &buffer) { /* If debugging, log the buffer */ - Log(LOG_RAWIO) << "Received: " << buffer; + Anope::Logger.RawIO("Received: {0}", buffer); if (buffer.empty()) return; @@ -31,44 +39,54 @@ void Anope::Process(const Anope::string &buffer) if (Anope::ProtocolDebug) { - Log() << "Source : " << (source.empty() ? "No source" : source); - Log() << "Command: " << command; + Anope::Logger.Log("Source : {0}", source.empty() ? "No source" : source); + Anope::Logger.Log("Command: {0}", command); if (params.empty()) - Log() << "No params"; + Anope::Logger.Log("No params"); else - for (unsigned i = 0; i < params.size(); ++i) - Log() << "params " << i << ": " << params[i]; + for (unsigned int i = 0; i < params.size(); ++i) + Anope::Logger.Log("params {0}: {1}", i, params[i]); } if (command.empty()) { - Log(LOG_DEBUG) << "No command? " << buffer; + Anope::Logger.Debug("No command? {0}", buffer); return; } - static const Anope::string proto_name = ModuleManager::FindFirstOf(PROTOCOL) ? ModuleManager::FindFirstOf(PROTOCOL)->name : ""; - MessageSource src(source); - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnMessage, MOD_RESULT, (src, command, params)); - if (MOD_RESULT == EVENT_STOP) - return; - ServiceReference<IRCDMessage> m("IRCDMessage", proto_name + "/" + command.lower()); + EventReturn MOD_RESULT = EventManager::Get()->Dispatch(&Event::Message::OnMessage, src, command, params); + + ProcessCommand(src, command, params); +} + +void Anope::ProcessCommand(MessageSource &src, const Anope::string &command, const std::vector<Anope::string> ¶ms) +{ + static const Anope::string proto_name = ModuleManager::FindFirstOf(PROTOCOL) ? ModuleManager::FindFirstOf(PROTOCOL)->name : ""; + + ServiceReference<IRCDMessage> m(proto_name + "/" + command.lower()); if (!m) { - Log(LOG_DEBUG) << "unknown message from server (" << buffer << ")"; + Anope::string buffer = "[" + src.GetSource() + "] " + command; + if (!params.empty()) + { + for (unsigned int i = 0; i < params.size() - 1; ++i) + buffer += " " + params[i]; + buffer += " :" + params[params.size() - 1]; + } + + Anope::Logger.Debug("unknown command from server ({0})", buffer); return; } if (m->HasFlag(IRCDMESSAGE_SOFT_LIMIT) ? (params.size() < m->GetParamCount()) : (params.size() != m->GetParamCount())) - Log(LOG_DEBUG) << "invalid parameters for " << command << ": " << params.size() << " != " << m->GetParamCount(); + Anope::Logger.Debug("invalid parameters for {0}: {1} != {2}", command, params.size(), m->GetParamCount()); else if (m->HasFlag(IRCDMESSAGE_REQUIRE_USER) && !src.GetUser()) - Log(LOG_DEBUG) << "unexpected non-user source " << source << " for " << command; - else if (m->HasFlag(IRCDMESSAGE_REQUIRE_SERVER) && !source.empty() && !src.GetServer()) - Log(LOG_DEBUG) << "unexpected non-server source " << source << " for " << command; + Anope::Logger.Debug("unexpected non-user source {0} for {1}", src.GetSource(), command); + else if (m->HasFlag(IRCDMESSAGE_REQUIRE_SERVER) && !src.GetServer()) + Anope::Logger.Debug("unexpected non-server source {0} for {1}", src.GetSource().empty() ? "(no source)" : src.GetSource(), command); else m->Run(src, params); } @@ -100,11 +118,26 @@ void IRCDProto::Parse(const Anope::string &buffer, Anope::string &source, Anope: } } -Anope::string IRCDProto::Format(const Anope::string &source, const Anope::string &message) +Anope::string IRCDProto::Format(IRCMessage &message) { + std::stringstream buffer; + + const Anope::string &source = message.GetSource().GetUID(); if (!source.empty()) - return ":" + source + " " + message; - else - return message; + buffer << ":" << source << " "; + + buffer << message.GetCommand(); + + for (unsigned int i = 0; i < message.GetParameters().size(); ++i) + { + buffer << " "; + + if (i + 1 == message.GetParameters().size()) + buffer << ":"; + + buffer << message.GetParameters()[i]; + } + + return buffer.str(); } diff --git a/src/protocol.cpp b/src/protocol.cpp index c8320e25a..e299d1c2f 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -1,12 +1,20 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -18,334 +26,42 @@ #include "uplink.h" #include "bots.h" #include "channels.h" +#include "numeric.h" -IRCDProto *IRCD = NULL; +IRCDProto *IRCD = nullptr; -IRCDProto::IRCDProto(Module *creator, const Anope::string &p) : Service(creator, "IRCDProto", creator->name), proto_name(p) +IRCDProto::IRCDProto(Module *creator, const Anope::string &p) : Service(creator, NAME, p) + , proto_name(p) { - DefaultPseudoclientModes = "+io"; - CanSVSNick = CanSVSJoin = CanSetVHost = CanSetVIdent = CanSNLine = CanSQLine = CanSQLineChannel - = CanSZLine = CanSVSHold = CanSVSO = CanCertFP = RequiresID = AmbiguousID = false; - MaxModes = 3; - MaxLine = 512; - - if (IRCD == NULL) - IRCD = this; } IRCDProto::~IRCDProto() { - if (IRCD == this) - IRCD = NULL; } -const Anope::string &IRCDProto::GetProtocolName() +const Anope::string &IRCDProto::GetProtocolName() const { return this->proto_name; } -static inline char nextID(int pos, Anope::string &buf) -{ - char &c = buf[pos]; - if (c == 'Z') - c = '0'; - else if (c != '9') - ++c; - else if (pos) - c = 'A'; - else - c = '0'; - return c; -} - -Anope::string IRCDProto::UID_Retrieve() -{ - if (!IRCD || !IRCD->RequiresID) - return ""; - - static Anope::string current_uid = "AAAAAA"; - - do - { - int current_len = current_uid.length() - 1; - while (current_len >= 0 && nextID(current_len--, current_uid) == 'A'); - } - while (User::Find(Me->GetSID() + current_uid) != NULL); - - return Me->GetSID() + current_uid; -} - -Anope::string IRCDProto::SID_Retrieve() -{ - if (!IRCD || !IRCD->RequiresID) - return ""; - - static Anope::string current_sid = Config->GetBlock("serverinfo")->Get<const Anope::string>("id"); - if (current_sid.empty()) - current_sid = "00A"; - - do - { - int current_len = current_sid.length() - 1; - while (current_len >= 0 && nextID(current_len--, current_sid) == 'A'); - } - while (Server::Find(current_sid) != NULL); - - return current_sid; -} - -void IRCDProto::SendKill(const MessageSource &source, const Anope::string &target, const Anope::string &reason) -{ - UplinkSocket::Message(source) << "KILL " << target << " :" << reason; -} - -void IRCDProto::SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) -{ - UplinkSocket::Message(source) << "KILL " << user->GetUID() << " :" << buf; -} - -void IRCDProto::SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf) -{ - UplinkSocket::Message(source) << "MODE " << dest->name << " " << buf; -} - -void IRCDProto::SendModeInternal(const MessageSource &source, User *dest, const Anope::string &buf) -{ - UplinkSocket::Message(source) << "MODE " << dest->GetUID() << " " << buf; -} - -void IRCDProto::SendKickInternal(const MessageSource &source, const Channel *c, User *u, const Anope::string &r) -{ - if (!r.empty()) - UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID() << " :" << r; - else - UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID(); -} - -void IRCDProto::SendNoticeInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &msg) -{ - UplinkSocket::Message(source) << "NOTICE " << dest << " :" << msg; -} - -void IRCDProto::SendPrivmsgInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf) -{ - UplinkSocket::Message(source) << "PRIVMSG " << dest << " :" << buf; -} - -void IRCDProto::SendQuitInternal(User *u, const Anope::string &buf) -{ - if (!buf.empty()) - UplinkSocket::Message(u) << "QUIT :" << buf; - else - UplinkSocket::Message(u) << "QUIT"; -} - -void IRCDProto::SendPartInternal(User *u, const Channel *chan, const Anope::string &buf) -{ - if (!buf.empty()) - UplinkSocket::Message(u) << "PART " << chan->name << " :" << buf; - else - UplinkSocket::Message(u) << "PART " << chan->name; -} - -void IRCDProto::SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) -{ - UplinkSocket::Message(source) << "GLOBOPS :" << buf; -} - -void IRCDProto::SendCTCPInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf) +void IRCDProto::SendCTCPReply(const MessageSource &source, const Anope::string &dest, const Anope::string &buf) { Anope::string s = Anope::NormalizeBuffer(buf); - this->SendNoticeInternal(source, dest, "\1" + s + "\1"); + this->SendNotice(source, dest, "\1" + s + "\1"); } -void IRCDProto::SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf) +void IRCDProto::SendNumeric(int numeric, User *dest, IRCMessage &message) { - Anope::string n = stringify(numeric); - if (numeric < 10) - n = "0" + n; - if (numeric < 100) - n = "0" + n; - UplinkSocket::Message(Me) << n << " " << dest << " " << buf; + Uplink::SendMessage(message); } -void IRCDProto::SendTopic(const MessageSource &source, Channel *c) +void IRCDProto::SendAction(const MessageSource &source, const Anope::string &dest, const Anope::string &message) { - UplinkSocket::Message(source) << "TOPIC " << c->name << " :" << c->topic; -} + Anope::string actionbuf = "\1ACTION "; + actionbuf.append(message); + actionbuf.append('\1'); -void IRCDProto::SendSVSKill(const MessageSource &source, User *user, const char *fmt, ...) -{ - if (!user || !fmt) - return; - - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendSVSKillInternal(source, user, buf); -} - -void IRCDProto::SendMode(const MessageSource &source, const Channel *dest, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendModeInternal(source, dest, buf); -} - -void IRCDProto::SendMode(const MessageSource &source, User *u, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendModeInternal(source, u, buf); -} - -void IRCDProto::SendKick(const MessageSource &source, const Channel *chan, User *user, const char *fmt, ...) -{ - if (!chan || !user) - return; - - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendKickInternal(source, chan, user, buf); -} - -void IRCDProto::SendNotice(const MessageSource &source, const Anope::string &dest, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendNoticeInternal(source, dest, buf); -} - -void IRCDProto::SendAction(const MessageSource &source, const Anope::string &dest, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - Anope::string actionbuf = Anope::string("\1ACTION ") + buf + '\1'; - SendPrivmsgInternal(source, dest, actionbuf); -} - -void IRCDProto::SendPrivmsg(const MessageSource &source, const Anope::string &dest, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendPrivmsgInternal(source, dest, buf); -} - -void IRCDProto::SendQuit(User *u, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendQuitInternal(u, buf); -} - -void IRCDProto::SendPing(const Anope::string &servname, const Anope::string &who) -{ - if (servname.empty()) - UplinkSocket::Message(Me) << "PING " << who; - else - UplinkSocket::Message(Me) << "PING " << servname << " " << who; -} - -/** - * Send a PONG reply to a received PING. - * servname should be left NULL to send a one param reply. - * @param servname Daemon or client that is responding to the PING. - * @param who Origin of the PING and destination of the PONG message. - **/ -void IRCDProto::SendPong(const Anope::string &servname, const Anope::string &who) -{ - if (servname.empty()) - UplinkSocket::Message(Me) << "PONG " << who; - else - UplinkSocket::Message(Me) << "PONG " << servname << " " << who; -} - -void IRCDProto::SendInvite(const MessageSource &source, const Channel *c, User *u) -{ - UplinkSocket::Message(source) << "INVITE " << u->GetUID() << " " << c->name; -} - -void IRCDProto::SendPart(User *user, const Channel *chan, const char *fmt, ...) -{ - if (fmt) - { - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendPartInternal(user, chan, buf); - } - else - SendPartInternal(user, chan, ""); -} - -void IRCDProto::SendGlobops(const MessageSource &source, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendGlobopsInternal(source, buf); -} - -void IRCDProto::SendSquit(Server *s, const Anope::string &message) -{ - UplinkSocket::Message() << "SQUIT " << s->GetSID() << " :" << message; -} - -void IRCDProto::SendNickChange(User *u, const Anope::string &newnick) -{ - UplinkSocket::Message(u) << "NICK " << newnick << " " << Anope::CurTime; -} - -void IRCDProto::SendForceNickChange(User *u, const Anope::string &newnick, time_t when) -{ - UplinkSocket::Message() << "SVSNICK " << u->GetUID() << " " << newnick << " " << when; -} - -void IRCDProto::SendCTCP(const MessageSource &source, const Anope::string &dest, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendCTCPInternal(source, dest, buf); -} - -void IRCDProto::SendNumeric(int numeric, const Anope::string &dest, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendNumericInternal(numeric, dest, buf); + SendPrivmsg(source, dest, actionbuf); } bool IRCDProto::IsNickValid(const Anope::string &nick) @@ -360,16 +76,16 @@ bool IRCDProto::IsNickValid(const Anope::string &nick) if (nick.empty()) return false; - + Anope::string special = "[]\\`_^{|}"; - - for (unsigned i = 0; i < nick.length(); ++i) + + for (unsigned int i = 0; i < nick.length(); ++i) if (!(nick[i] >= 'A' && nick[i] <= 'Z') && !(nick[i] >= 'a' && nick[i] <= 'z') && special.find(nick[i]) == Anope::string::npos && (Config && Config->NickChars.find(nick[i]) == Anope::string::npos) && (!i || (!(nick[i] >= '0' && nick[i] <= '9') && nick[i] != '-'))) return false; - + return true; } @@ -389,7 +105,7 @@ bool IRCDProto::IsIdentValid(const Anope::string &ident) if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) return false; - for (unsigned i = 0; i < ident.length(); ++i) + for (unsigned int i = 0; i < ident.length(); ++i) { const char &c = ident[i]; @@ -407,8 +123,8 @@ bool IRCDProto::IsHostValid(const Anope::string &host) if (host.empty() || host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen")) return false; - const Anope::string &vhostdisablebe = Config->GetBlock("networkinfo")->Get<const Anope::string>("disallow_start_or_end"), - vhostchars = Config->GetBlock("networkinfo")->Get<const Anope::string>("vhost_chars"); + const Anope::string &vhostdisablebe = Config->GetBlock("networkinfo")->Get<Anope::string>("disallow_start_or_end"), + vhostchars = Config->GetBlock("networkinfo")->Get<Anope::string>("vhost_chars"); if (vhostdisablebe.find_first_of(host[0]) != Anope::string::npos) return false; @@ -416,7 +132,7 @@ bool IRCDProto::IsHostValid(const Anope::string &host) return false; int dots = 0; - for (unsigned i = 0; i < host.length(); ++i) + for (unsigned int i = 0; i < host.length(); ++i) { if (host[i] == '.') ++dots; @@ -427,13 +143,7 @@ bool IRCDProto::IsHostValid(const Anope::string &host) return dots > 0 || Config->GetBlock("networkinfo")->Get<bool>("allow_undotted_vhosts"); } -void IRCDProto::SendOper(User *u) -{ - SendNumericInternal(381, u->GetUID(), ":You are now an IRC operator (set by services)"); - u->SetMode(NULL, "OPER"); -} - -unsigned IRCDProto::GetMaxListFor(Channel *c) +unsigned int IRCDProto::GetMaxListFor(Channel *c) { return c->HasMode("LBAN") ? 0 : Config->GetBlock("networkinfo")->Get<int>("modelistsize"); } @@ -445,7 +155,7 @@ Anope::string IRCDProto::NormalizeMask(const Anope::string &mask) return Entry("", mask).GetNUHMask(); } -MessageSource::MessageSource(const Anope::string &src) : source(src), u(NULL), s(NULL) +MessageSource::MessageSource(const Anope::string &src) : source(src) { /* no source for incoming message is our uplink */ if (src.empty()) @@ -456,11 +166,11 @@ MessageSource::MessageSource(const Anope::string &src) : source(src), u(NULL), s this->u = User::Find(src); } -MessageSource::MessageSource(User *_u) : source(_u ? _u->nick : ""), u(_u), s(NULL) +MessageSource::MessageSource(User *_u) : source(_u ? _u->nick : ""), u(_u) { } -MessageSource::MessageSource(Server *_s) : source(_s ? _s->GetName() : ""), u(NULL), s(_s) +MessageSource::MessageSource(Server *_s) : source(_s ? _s->GetName() : ""), s(_s) { } @@ -474,6 +184,15 @@ const Anope::string &MessageSource::GetName() const return this->source; } +const Anope::string &MessageSource::GetUID() const +{ + if (this->s) + return this->s->GetSID(); + if (this->u) + return this->u->GetUID(); + return this->source; +} + const Anope::string &MessageSource::GetSource() const { return this->source; @@ -484,9 +203,9 @@ User *MessageSource::GetUser() const return this->u; } -BotInfo *MessageSource::GetBot() const +ServiceBot *MessageSource::GetBot() const { - return BotInfo::Find(this->GetName(), true); + return ServiceBot::Find(this->GetName(), true); } Server *MessageSource::GetServer() const @@ -494,11 +213,13 @@ Server *MessageSource::GetServer() const return this->s; } -IRCDMessage::IRCDMessage(Module *o, const Anope::string &n, unsigned p) : Service(o, "IRCDMessage", o->name + "/" + n.lower()), name(n), param_count(p) +IRCDMessage::IRCDMessage(Module *o, const Anope::string &n, unsigned int p) : Service(o, NAME, o->name + "/" + n.lower()) + , name(n) + , param_count(p) { } -unsigned IRCDMessage::GetParamCount() const +unsigned int IRCDMessage::GetParamCount() const { return this->param_count; } diff --git a/src/regchannel.cpp b/src/regchannel.cpp deleted file mode 100644 index 356ceb093..000000000 --- a/src/regchannel.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* Registered channel functions - * - * (C) 2003-2016 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 "services.h" -#include "modules.h" -#include "regchannel.h" -#include "account.h" -#include "access.h" -#include "channels.h" -#include "config.h" -#include "bots.h" -#include "servers.h" - -Serialize::Checker<registered_channel_map> RegisteredChannelList("ChannelInfo"); - -AutoKick::AutoKick() : Serializable("AutoKick") -{ -} - -AutoKick::~AutoKick() -{ - if (this->ci) - { - std::vector<AutoKick *>::iterator it = std::find(this->ci->akick->begin(), this->ci->akick->end(), this); - if (it != this->ci->akick->end()) - this->ci->akick->erase(it); - - const NickAlias *na = NickAlias::Find(this->mask); - if (na != NULL) - na->nc->RemoveChannelReference(this->ci); - } -} - -void AutoKick::Serialize(Serialize::Data &data) const -{ - data["ci"] << this->ci->name; - if (this->nc) - data["nc"] << this->nc->display; - else - data["mask"] << this->mask; - data["reason"] << this->reason; - data["creator"] << this->creator; - data.SetType("addtime", Serialize::Data::DT_INT); data["addtime"] << this->addtime; - data.SetType("last_used", Serialize::Data::DT_INT); data["last_used"] << this->last_used; -} - -Serializable* AutoKick::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string sci, snc; - - data["ci"] >> sci; - data["nc"] >> snc; - - ChannelInfo *ci = ChannelInfo::Find(sci); - if (!ci) - return NULL; - - AutoKick *ak; - NickCore *nc = NickCore::Find(snc); - if (obj) - { - ak = anope_dynamic_static_cast<AutoKick *>(obj); - data["creator"] >> ak->creator; - data["reason"] >> ak->reason; - ak->nc = NickCore::Find(snc); - data["mask"] >> ak->mask; - data["addtime"] >> ak->addtime; - data["last_used"] >> ak->last_used; - } - else - { - time_t addtime, lastused; - data["addtime"] >> addtime; - data["last_used"] >> lastused; - - Anope::string screator, sreason, smask; - - data["creator"] >> screator; - data["reason"] >> sreason; - data["mask"] >> smask; - - if (nc) - ak = ci->AddAkick(screator, nc, sreason, addtime, lastused); - else - ak = ci->AddAkick(screator, smask, sreason, addtime, lastused); - } - - return ak; -} - -ChannelInfo::ChannelInfo(const Anope::string &chname) : Serializable("ChannelInfo"), - access("ChanAccess"), akick("AutoKick") -{ - if (chname.empty()) - throw CoreException("Empty channel passed to ChannelInfo constructor"); - - this->founder = NULL; - this->successor = NULL; - this->c = Channel::Find(chname); - if (this->c) - this->c->ci = this; - this->banexpire = 0; - this->bi = NULL; - this->last_topic_time = 0; - - this->name = chname; - - this->bantype = 2; - this->memos.memomax = 0; - this->last_used = this->time_registered = Anope::CurTime; - - size_t old = RegisteredChannelList->size(); - (*RegisteredChannelList)[this->name] = this; - if (old == RegisteredChannelList->size()) - Log(LOG_DEBUG) << "Duplicate channel " << this->name << " in registered channel table?"; - - FOREACH_MOD(OnCreateChan, (this)); -} - -ChannelInfo::ChannelInfo(const ChannelInfo &ci) : Serializable("ChannelInfo"), - access("ChanAccess"), akick("AutoKick") -{ - *this = ci; - - if (this->founder) - ++this->founder->channelcount; - - this->access->clear(); - this->akick->clear(); - - FOREACH_MOD(OnCreateChan, (this)); -} - -ChannelInfo::~ChannelInfo() -{ - UnsetExtensibles(); - - FOREACH_MOD(OnDelChan, (this)); - - Log(LOG_DEBUG) << "Deleting channel " << this->name; - - if (this->c) - { - if (this->bi && this->c->FindUser(this->bi)) - this->bi->Part(this->c); - - /* Parting the service bot can cause the channel to go away */ - - if (this->c) - { - if (this->c && this->c->CheckDelete()) - this->c->QueueForDeletion(); - - this->c = NULL; - } - } - - RegisteredChannelList->erase(this->name); - - this->SetFounder(NULL); - this->SetSuccessor(NULL); - - this->ClearAccess(); - this->ClearAkick(); - - if (!this->memos.memos->empty()) - { - for (unsigned i = 0, end = this->memos.memos->size(); i < end; ++i) - delete this->memos.GetMemo(i); - this->memos.memos->clear(); - } -} - -void ChannelInfo::Serialize(Serialize::Data &data) const -{ - data["name"] << this->name; - if (this->founder) - data["founder"] << this->founder->display; - if (this->successor) - data["successor"] << this->successor->display; - data["description"] << this->desc; - data.SetType("time_registered", Serialize::Data::DT_INT); data["time_registered"] << this->time_registered; - data.SetType("last_used", Serialize::Data::DT_INT); data["last_used"] << this->last_used; - data["last_topic"] << this->last_topic; - data["last_topic_setter"] << this->last_topic_setter; - data.SetType("last_topic_time", Serialize::Data::DT_INT); data["last_topic_time"] << this->last_topic_time; - data.SetType("bantype", Serialize::Data::DT_INT); data["bantype"] << this->bantype; - { - Anope::string levels_buffer; - for (Anope::map<int16_t>::const_iterator it = this->levels.begin(), it_end = this->levels.end(); it != it_end; ++it) - levels_buffer += it->first + " " + stringify(it->second) + " "; - data["levels"] << levels_buffer; - } - if (this->bi) - data["bi"] << this->bi->nick; - data.SetType("banexpire", Serialize::Data::DT_INT); data["banexpire"] << this->banexpire; - data["memomax"] << this->memos.memomax; - for (unsigned i = 0; i < this->memos.ignores.size(); ++i) - data["memoignores"] << this->memos.ignores[i] << " "; - - Extensible::ExtensibleSerialize(this, this, data); -} - -Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string sname, sfounder, ssuccessor, slevels, sbi; - - data["name"] >> sname; - data["founder"] >> sfounder; - data["successor"] >> ssuccessor; - data["levels"] >> slevels; - data["bi"] >> sbi; - - ChannelInfo *ci; - if (obj) - ci = anope_dynamic_static_cast<ChannelInfo *>(obj); - else - ci = new ChannelInfo(sname); - - ci->SetFounder(NickCore::Find(sfounder)); - ci->SetSuccessor(NickCore::Find(ssuccessor)); - - data["description"] >> ci->desc; - data["time_registered"] >> ci->time_registered; - data["last_used"] >> ci->last_used; - data["last_topic"] >> ci->last_topic; - data["last_topic_setter"] >> ci->last_topic_setter; - data["last_topic_time"] >> ci->last_topic_time; - data["bantype"] >> ci->bantype; - { - std::vector<Anope::string> v; - spacesepstream(slevels).GetTokens(v); - for (unsigned i = 0; i + 1 < v.size(); i += 2) - try - { - ci->levels[v[i]] = convertTo<int16_t>(v[i + 1]); - } - catch (const ConvertException &) { } - } - BotInfo *bi = BotInfo::Find(sbi, true); - if (*ci->bi != bi) - { - if (bi) - bi->Assign(NULL, ci); - else if (ci->bi) - ci->bi->UnAssign(NULL, ci); - } - data["banexpire"] >> ci->banexpire; - data["memomax"] >> ci->memos.memomax; - { - Anope::string buf; - data["memoignores"] >> buf; - spacesepstream sep(buf); - ci->memos.ignores.clear(); - while (sep.GetToken(buf)) - ci->memos.ignores.push_back(buf); - } - - Extensible::ExtensibleUnserialize(ci, ci, data); - - /* compat */ - bool b; - b = false; - data["extensible:SECURE"] >> b; - if (b) - ci->Extend<bool>("CS_SECURE"); - b = false; - data["extensible:PRIVATE"] >> b; - if (b) - ci->Extend<bool>("CS_PRIVATE"); - b = false; - data["extensible:NO_EXPIRE"] >> b; - if (b) - ci->Extend<bool>("CS_NO_EXPIRE"); - b = false; - data["extensible:FANTASY"] >> b; - if (b) - ci->Extend<bool>("BS_FANTASY"); - b = false; - data["extensible:GREET"] >> b; - if (b) - ci->Extend<bool>("BS_GREET"); - b = false; - data["extensible:PEACE"] >> b; - if (b) - ci->Extend<bool>("PEACE"); - b = false; - data["extensible:SECUREFOUNDER"] >> b; - if (b) - ci->Extend<bool>("SECUREFOUNDER"); - b = false; - data["extensible:RESTRICTED"] >> b; - if (b) - ci->Extend<bool>("RESTRICTED"); - b = false; - data["extensible:KEEPTOPIC"] >> b; - if (b) - ci->Extend<bool>("KEEPTOPIC"); - b = false; - data["extensible:SIGNKICK"] >> b; - if (b) - ci->Extend<bool>("SIGNKICK"); - b = false; - data["extensible:SIGNKICK_LEVEL"] >> b; - if (b) - ci->Extend<bool>("SIGNKICK_LEVEL"); - /* end compat */ - - return ci; -} - - -void ChannelInfo::SetFounder(NickCore *nc) -{ - if (this->founder) - { - --this->founder->channelcount; - this->founder->RemoveChannelReference(this); - } - - this->founder = nc; - - if (this->founder) - { - ++this->founder->channelcount; - this->founder->AddChannelReference(this); - } -} - -NickCore *ChannelInfo::GetFounder() const -{ - return this->founder; -} - -void ChannelInfo::SetSuccessor(NickCore *nc) -{ - if (this->successor) - this->successor->RemoveChannelReference(this); - this->successor = nc; - if (this->successor) - this->successor->AddChannelReference(this); -} - -NickCore *ChannelInfo::GetSuccessor() const -{ - return this->successor; -} - -BotInfo *ChannelInfo::WhoSends() const -{ - if (this && this->bi) - return this->bi; - - BotInfo *ChanServ = Config->GetClient("ChanServ"); - if (ChanServ) - return ChanServ; - - if (!BotListByNick->empty()) - return BotListByNick->begin()->second; - - return NULL; -} - -void ChannelInfo::AddAccess(ChanAccess *taccess) -{ - this->access->push_back(taccess); -} - -ChanAccess *ChannelInfo::GetAccess(unsigned index) const -{ - if (this->access->empty() || index >= this->access->size()) - return NULL; - - ChanAccess *acc = (*this->access)[index]; - acc->QueueUpdate(); - return acc; -} - -static void FindMatchesRecurse(ChannelInfo *ci, const User *u, const NickCore *account, unsigned int depth, std::vector<ChanAccess::Path> &paths, ChanAccess::Path &path) -{ - if (depth > ChanAccess::MAX_DEPTH) - return; - - for (unsigned int i = 0; i < ci->GetAccessCount(); ++i) - { - ChanAccess *a = ci->GetAccess(i); - ChannelInfo *next = NULL; - - if (a->Matches(u, account, next)) - { - ChanAccess::Path next_path = path; - next_path.push_back(a); - - paths.push_back(next_path); - } - else if (next) - { - ChanAccess::Path next_path = path; - next_path.push_back(a); - - FindMatchesRecurse(next, u, account, depth + 1, paths, next_path); - } - } -} - -static void FindMatches(AccessGroup &group, ChannelInfo *ci, const User *u, const NickCore *account) -{ - ChanAccess::Path path; - FindMatchesRecurse(ci, u, account, 0, group.paths, path); -} - -AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed) -{ - AccessGroup group; - - if (u == NULL) - return group; - - const NickCore *nc = u->Account(); - if (nc == NULL && !this->HasExt("NS_SECURE") && u->IsRecognized()) - { - const NickAlias *na = NickAlias::Find(u->nick); - if (na != NULL) - nc = na->nc; - } - - group.super_admin = u->super_admin; - group.founder = IsFounder(u, this); - group.ci = this; - group.nc = nc; - - FindMatches(group, this, u, u->Account()); - - if (group.founder || !group.paths.empty()) - { - if (updateLastUsed) - this->last_used = Anope::CurTime; - - for (unsigned i = 0; i < group.paths.size(); ++i) - { - ChanAccess::Path &p = group.paths[i]; - - for (unsigned int j = 0; j < p.size(); ++j) - p[j]->last_seen = Anope::CurTime; - } - } - - return group; -} - -AccessGroup ChannelInfo::AccessFor(const NickCore *nc, bool updateLastUsed) -{ - AccessGroup group; - - group.founder = (this->founder && this->founder == nc); - group.ci = this; - group.nc = nc; - - FindMatches(group, this, NULL, nc); - - if (group.founder || !group.paths.empty()) - if (updateLastUsed) - this->last_used = Anope::CurTime; - - /* don't update access last seen here, this isn't the user requesting access */ - - return group; -} - -unsigned ChannelInfo::GetAccessCount() const -{ - return this->access->size(); -} - -static unsigned int GetDeepAccessCount(const ChannelInfo *ci, std::set<const ChannelInfo *> &seen, unsigned int depth) -{ - if (depth > ChanAccess::MAX_DEPTH || seen.count(ci)) - return 0; - seen.insert(ci); - - unsigned int total = 0; - - for (unsigned int i = 0; i < ci->GetAccessCount(); ++i) - { - ChanAccess::Path path; - ChanAccess *a = ci->GetAccess(i); - ChannelInfo *next = NULL; - - a->Matches(NULL, NULL, next); - ++total; - - if (next) - total += GetDeepAccessCount(ci, seen, depth + 1); - } - - return total; -} - -unsigned ChannelInfo::GetDeepAccessCount() const -{ - std::set<const ChannelInfo *> seen; - return ::GetDeepAccessCount(this, seen, 0); -} - -ChanAccess *ChannelInfo::EraseAccess(unsigned index) -{ - if (this->access->empty() || index >= this->access->size()) - return NULL; - - ChanAccess *ca = this->access->at(index); - this->access->erase(this->access->begin() + index); - return ca; -} - -void ChannelInfo::ClearAccess() -{ - for (unsigned i = this->access->size(); i > 0; --i) - delete this->GetAccess(i - 1); -} - -AutoKick *ChannelInfo::AddAkick(const Anope::string &user, NickCore *akicknc, const Anope::string &reason, time_t t, time_t lu) -{ - AutoKick *autokick = new AutoKick(); - autokick->ci = this; - autokick->nc = akicknc; - autokick->reason = reason; - autokick->creator = user; - autokick->addtime = t; - autokick->last_used = lu; - - this->akick->push_back(autokick); - - akicknc->AddChannelReference(this); - - return autokick; -} - -AutoKick *ChannelInfo::AddAkick(const Anope::string &user, const Anope::string &mask, const Anope::string &reason, time_t t, time_t lu) -{ - AutoKick *autokick = new AutoKick(); - autokick->ci = this; - autokick->mask = mask; - autokick->nc = NULL; - autokick->reason = reason; - autokick->creator = user; - autokick->addtime = t; - autokick->last_used = lu; - - this->akick->push_back(autokick); - - return autokick; -} - -AutoKick *ChannelInfo::GetAkick(unsigned index) const -{ - if (this->akick->empty() || index >= this->akick->size()) - return NULL; - - AutoKick *ak = (*this->akick)[index]; - ak->QueueUpdate(); - return ak; -} - -unsigned ChannelInfo::GetAkickCount() const -{ - return this->akick->size(); -} - -void ChannelInfo::EraseAkick(unsigned index) -{ - if (this->akick->empty() || index >= this->akick->size()) - return; - - delete this->GetAkick(index); -} - -void ChannelInfo::ClearAkick() -{ - while (!this->akick->empty()) - delete this->akick->back(); -} - -const Anope::map<int16_t> &ChannelInfo::GetLevelEntries() -{ - return this->levels; -} - -int16_t ChannelInfo::GetLevel(const Anope::string &priv) const -{ - if (PrivilegeManager::FindPrivilege(priv) == NULL) - { - Log(LOG_DEBUG) << "Unknown privilege " + priv; - return ACCESS_INVALID; - } - - Anope::map<int16_t>::const_iterator it = this->levels.find(priv); - if (it == this->levels.end()) - return 0; - return it->second; -} - -void ChannelInfo::SetLevel(const Anope::string &priv, int16_t level) -{ - if (PrivilegeManager::FindPrivilege(priv) == NULL) - { - Log(LOG_DEBUG) << "Unknown privilege " + priv; - return; - } - - this->levels[priv] = level; -} - -void ChannelInfo::RemoveLevel(const Anope::string &priv) -{ - this->levels.erase(priv); -} - -void ChannelInfo::ClearLevels() -{ - this->levels.clear(); -} - -Anope::string ChannelInfo::GetIdealBan(User *u) const -{ - int bt = this ? this->bantype : -1; - switch (bt) - { - case 0: - return "*!" + u->GetVIdent() + "@" + u->GetDisplayedHost(); - case 1: - if (u->GetVIdent()[0] == '~') - return "*!*" + u->GetVIdent() + "@" + u->GetDisplayedHost(); - else - return "*!" + u->GetVIdent() + "@" + u->GetDisplayedHost(); - case 3: - return "*!" + u->Mask(); - case 2: - default: - return "*!*@" + u->GetDisplayedHost(); - } -} - -ChannelInfo* ChannelInfo::Find(const Anope::string &name) -{ - registered_channel_map::const_iterator it = RegisteredChannelList->find(name); - if (it != RegisteredChannelList->end()) - { - it->second->QueueUpdate(); - return it->second; - } - - return NULL; -} - -bool IsFounder(const User *user, const ChannelInfo *ci) -{ - if (!user || !ci) - return false; - - if (user->super_admin) - return true; - - if (user->Account() && user->Account() == ci->GetFounder()) - return true; - - return false; -} - - -void ChannelInfo::AddChannelReference(const Anope::string &what) -{ - ++references[what]; -} - -void ChannelInfo::RemoveChannelReference(const Anope::string &what) -{ - int &i = references[what]; - if (--i <= 0) - references.erase(what); -} - -void ChannelInfo::GetChannelReferences(std::deque<Anope::string> &chans) -{ - chans.clear(); - for (Anope::map<int>::iterator it = references.begin(); it != references.end(); ++it) - chans.push_back(it->first); -} diff --git a/src/serialize.cpp b/src/serialize.cpp index 3c54b933d..5315a8469 100644 --- a/src/serialize.cpp +++ b/src/serialize.cpp @@ -1,178 +1,347 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2012-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "anope.h" #include "serialize.h" #include "modules.h" -#include "account.h" -#include "bots.h" -#include "regchannel.h" -#include "xline.h" -#include "access.h" +#include "event.h" using namespace Serialize; -std::vector<Anope::string> Type::TypeOrder; -std::map<Anope::string, Type *> Serialize::Type::Types; -std::list<Serializable *> *Serializable::SerializableItems; +static std::map<Serialize::TypeBase *, std::unordered_map<ID, Object *>> objects; -void Serialize::RegisterTypes() -{ - static Type nc("NickCore", NickCore::Unserialize), na("NickAlias", NickAlias::Unserialize), bi("BotInfo", BotInfo::Unserialize), - ci("ChannelInfo", ChannelInfo::Unserialize), access("ChanAccess", ChanAccess::Unserialize), - akick("AutoKick", AutoKick::Unserialize), memo("Memo", Memo::Unserialize), xline("XLine", XLine::Unserialize); -} +std::vector<FieldBase *> Serialize::serializableFields; + +std::multimap<Anope::string, Anope::string> Serialize::child_types; + +static ID curid; -void Serialize::CheckTypes() + +Object *Serialize::GetID(Serialize::TypeBase *type, ID id) { - for (std::map<Anope::string, Serialize::Type *>::const_iterator it = Serialize::Type::GetTypes().begin(), it_end = Serialize::Type::GetTypes().end(); it != it_end; ++it) - { - Serialize::Type *t = it->second; - t->Check(); - } + auto it = objects[type].find(id); + if (it != objects[type].end()) + return it->second; + return nullptr; } -Serializable::Serializable(const Anope::string &serialize_type) : last_commit(0), last_commit_time(0), id(0), redis_ignore(0) +void Serialize::GC() { - if (SerializableItems == NULL) - SerializableItems = new std::list<Serializable *>(); - SerializableItems->push_back(this); + for (auto it = objects.begin(); it != objects.end(); ++it) + for (auto it2 = it->second.begin(); it2 != it->second.end();) + { + Object *o = it2->second; - this->s_type = Type::Find(serialize_type); + if (!o->CanGC()) + { + // Wipe internal storage to force refetch + o->Wipe(); + ++it2; + continue; + } - this->s_iter = SerializableItems->end(); - --this->s_iter; + Anope::Logger.Debug2("garbage collected object {0}", o->id); - FOREACH_MOD(OnSerializableConstruct, (this)); + it2 = it->second.erase(it2); + delete o; + } } -Serializable::Serializable(const Serializable &other) : last_commit(0), last_commit_time(0), id(0), redis_ignore(0) +void Serialize::Unregister(Module *m) { - SerializableItems->push_back(this); - this->s_iter = SerializableItems->end(); - --this->s_iter; + for (TypeBase *s : ServiceManager::Get()->FindServices<Serialize::TypeBase *>()) + if (s->GetOwner() == m) + s->Unregister(); - this->s_type = other.s_type; + for (FieldBase *field : serializableFields) + if (field->GetOwner() == m) + field->Unregister(); +} - FOREACH_MOD(OnSerializableConstruct, (this)); +void Serialize::Object::Wipe() +{ + for (Serialize::FieldBase *base : s_type->GetFields()) + { + base->Uncache(this); + } } -Serializable::~Serializable() +std::vector<Edge> Object::GetEdges(TypeBase *type) { - FOREACH_MOD(OnSerializableDestruct, (this)); + std::vector<Edge> refs; + EventReturn result = EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializeGetRefs, this, type, refs); + if (result == EVENT_ALLOW) + return refs; - SerializableItems->erase(this->s_iter); + if (type == nullptr) + { + refs.clear(); + for (const std::pair<TypeBase *, std::vector<Edge>> &p : edges) + { + const std::vector<Edge> &e = p.second; + refs.insert(refs.end(), e.begin(), e.end()); + } + return refs; + } + + auto it = edges.find(type); + if (it != edges.end()) + return it->second; + return std::vector<Edge>(); } -Serializable &Serializable::operator=(const Serializable &) +Object::Object(TypeBase *type) { - return *this; + ID i; + EventReturn result = EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializableGetId, type, i); + if (result != EVENT_ALLOW) + { + while (GetID(type, ++curid)); + i = curid; + } + + id = i; + objects[type][id] = this; + + this->s_type = type; + + type->objects.insert(this); + + Anope::Logger.Debug2("Creating object id #{0} address {1} type {2}", id, static_cast<void *>(this), type->GetName()); + + EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializableCreate, this); } -void Serializable::QueueUpdate() +Object::Object(TypeBase *type, ID i) { - /* Schedule updater */ - FOREACH_MOD(OnSerializableUpdate, (this)); + this->id = i; + objects[type][id] = this; + + this->s_type = type; - /* Check for modifications now - this can delete this object! */ - FOREACH_MOD(OnSerializeCheck, (this->GetSerializableType())); + type->objects.insert(this); + + Anope::Logger.Debug2("Creating object from id #{0} address {1} type {2}", id, static_cast<void *>(this), type->GetName()); } -bool Serializable::IsCached(Serialize::Data &data) +Object::~Object() { - return this->last_commit == data.Hash(); + Anope::Logger.Debug2("Destructing object id #{0} address {1} type {2}", id, static_cast<void *>(this), s_type->GetName()); + + /* Remove in memory edges */ + std::map<TypeBase *, std::vector<Edge>> copy = edges; + for (const std::pair<TypeBase *, std::vector<Edge>> &p : copy) + for (const Edge &edge : p.second) + { + if (!edge.direction) + { + Anope::Logger.Debug2("Removing edge from object id #{0} type {1} on field {2}", edge.other->id, edge.other->GetSerializableType()->GetName(), edge.field->serialize_name); + edge.other->RemoveEdge(this, edge.field); + } + else + { + Anope::Logger.Debug2("Removing edge to object id #{0} type {1} on field {2}", edge.other->id, edge.other->GetSerializableType()->GetName(), edge.field->serialize_name); + this->RemoveEdge(edge.other, edge.field); + } + } + + objects[s_type].erase(id); + s_type->objects.erase(this); } -void Serializable::UpdateCache(Serialize::Data &data) +void Object::Delete() { - this->last_commit = data.Hash(); + Anope::Logger.Debug2("Deleting object id #{0} type {1}", id, s_type->GetName()); + + /* Delete dependant objects */ + for (const Edge &edge : GetEdges(nullptr)) + { + Object *other = edge.other; + FieldBase *field = edge.field; + + if (edge.direction) + continue; + + if (field->depends) + { + Anope::Logger.Debug2("Deleting dependent object #{0} type {1} due to edge on {2}", other->id, other->GetSerializableType()->GetName(), field->serialize_name); + other->Delete(); + } + else + { + Anope::Logger.Debug2("Unsetting field {0} on object #{1} type {2}", field->serialize_name, other->id, other->GetSerializableType()->GetName()); + field->UnsetS(other); + } + } + + EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializableDelete, this); + + delete this; } -bool Serializable::IsTSCached() +void Object::AddEdge(Object *other, FieldBase *field) { - return this->last_commit_time == Anope::CurTime; + // field = the field on 'this' object + this->edges[other->GetSerializableType()].emplace_back(other, field, true); + // field = the field on the other object + other->edges[this->GetSerializableType()].emplace_back(this, field, false); } -void Serializable::UpdateTS() +void Object::RemoveEdge(Object *other, FieldBase *field) { - this->last_commit_time = Anope::CurTime; + std::vector<Edge> &myedges = this->edges[other->GetSerializableType()]; + auto it = std::find(myedges.begin(), myedges.end(), Edge(other, field, true)); + if (it != myedges.end()) + myedges.erase(it); + else + Anope::Logger.Debug2("Unable to locate edge for removal on #{0} type {1} -> #{2} type {3}", this->id, s_type->GetName(), other->id, other->GetSerializableType()->GetName()); + + if (myedges.empty()) + this->edges.erase(other->GetSerializableType()); + + std::vector<Edge> &theiredges = other->edges[this->GetSerializableType()]; + it = std::find(theiredges.begin(), theiredges.end(), Edge(this, field, false)); + if (it != theiredges.end()) + theiredges.erase(it); + else + Anope::Logger.Debug2("Unable to locate edge for removal on #{0} type {1} <- #{2} type {3}", this->id, s_type->GetName(), other->id, other->GetSerializableType()->GetName()); + + if (theiredges.empty()) + other->edges.erase(this->GetSerializableType()); } -const std::list<Serializable *> &Serializable::GetItems() +TypeBase::TypeBase(Module *o, const Anope::string &n) : Service(o, TypeBase::NAME, n), name(n), owner(o) { - return *SerializableItems; } -Type::Type(const Anope::string &n, unserialize_func f, Module *o) : name(n), unserialize(f), owner(o), timestamp(0) +void TypeBase::Unregister() { - TypeOrder.push_back(this->name); - Types[this->name] = this; + Anope::Logger.Debug2("Unregistering type {0}", this->GetName()); + + // Delete in memory objects + std::unordered_map<ID, Object *> objs = ::objects[this]; + for (auto &pair : objs) + delete pair.second; - FOREACH_MOD(OnSerializeTypeCreate, (this)); + ::objects.erase(this); + + for (FieldBase *field : serializableFields) + { + if (field->serialize_type == this->GetName()) + { + field->Unregister(); + } + } } -Type::~Type() +Serialize::FieldBase *TypeBase::GetField(const Anope::string &fname) { - /* null the type of existing serializable objects of this type */ - if (Serializable::SerializableItems != NULL) - for (std::list<Serializable *>::iterator it = Serializable::SerializableItems->begin(); it != Serializable::SerializableItems->end(); ++it) - { - Serializable *s = *it; + /* is this too slow? */ + for (FieldBase *fb : ServiceManager::Get()->FindServices<FieldBase *>()) + if (fb->serialize_type == this->GetName() && fb->serialize_name == fname) + return fb; - if (s->s_type == this) - s->s_type = NULL; - } + Anope::Logger.Debug2("GetField() for unknown field {0} on {1}", fname, this->GetName()); - std::vector<Anope::string>::iterator it = std::find(TypeOrder.begin(), TypeOrder.end(), this->name); - if (it != TypeOrder.end()) - TypeOrder.erase(it); - Types.erase(this->name); + return nullptr; } -Serializable *Type::Unserialize(Serializable *obj, Serialize::Data &data) +std::vector<Serialize::FieldBase *> TypeBase::GetFields() { - return this->unserialize(obj, data); + std::vector<Serialize::FieldBase *> fields; + + for (FieldBase *fb : ServiceManager::Get()->FindServices<FieldBase *>()) + if (fb->serialize_type == this->GetName()) + fields.push_back(fb); + + return fields; } -void Type::Check() +TypeBase *TypeBase::Find(const Anope::string &name) { - FOREACH_MOD(OnSerializeCheck, (this)); + return ServiceManager::Get()->FindService<TypeBase *>(name); } -time_t Type::GetTimestamp() const +std::vector<TypeBase *> TypeBase::GetTypes() { - return this->timestamp; + return ServiceManager::Get()->FindServices<TypeBase *>(); } -void Type::UpdateTimestamp() +FieldBase::FieldBase(Module *c, const Anope::string &n, const Anope::string &t, bool d) + : Service(c, FieldBase::NAME) + , serialize_type(t) + , serialize_name(n) + , depends(d) { - this->timestamp = Anope::CurTime; + serializableFields.push_back(this); } -Type *Serialize::Type::Find(const Anope::string &name) +FieldBase::~FieldBase() { - std::map<Anope::string, Type *>::iterator it = Types.find(name); - if (it != Types.end()) - return it->second; - return NULL; + auto it = std::find(serializableFields.begin(), serializableFields.end(), this); + if (it != serializableFields.end()) + serializableFields.erase(it); } -const std::vector<Anope::string> &Type::GetTypeOrder() +void FieldBase::Unregister() { - return TypeOrder; + Anope::Logger.Debug2("Unregistering field {0} on {1}", serialize_name, serialize_type); + + /* find edges on this field */ + for (Object *s : Serialize::GetObjects<Object *>(serialize_type)) + { + for (const std::pair<TypeBase *, std::vector<Edge>> &p : s->edges) + for (const Edge &edge : p.second) + if (edge.direction && edge.field == this) + { + Anope::Logger.Debug2("Removing edge on #{0} type {1} -> #{2} type {3}", s->id, s->GetSerializableType()->GetName(), edge.other->id, edge.other->GetSerializableType()->GetName()); + s->RemoveEdge(edge.other, edge.field); + + goto cont; + } + cont:; + } } -const std::map<Anope::string, Serialize::Type *>& Type::GetTypes() +void Serialize::SetParent(const Anope::string &child, const Anope::string &parent) { - return Types; + child_types.insert(std::make_pair(parent, child)); } +std::vector<Serialize::TypeBase *> Serialize::GetTypes(const Anope::string &name) +{ + std::vector<Serialize::TypeBase *> v; + + Serialize::TypeBase *t = Serialize::TypeBase::Find(name); + if (t != nullptr) + v.push_back(t); + else + Anope::Logger.Debug2("GetTypes for unknown type {0}", name); + + auto its = child_types.equal_range(name); + for (; its.first != its.second; ++its.first) + { + t = Serialize::TypeBase::Find(its.first->second); + if (t != nullptr) + v.push_back(t); + } + + return v; +} diff --git a/src/servers.cpp b/src/servers.cpp index b78cd19f7..d1fa2bf26 100644 --- a/src/servers.cpp +++ b/src/servers.cpp @@ -1,12 +1,20 @@ -/* Routines to maintain a list of connected servers +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2004-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -14,10 +22,11 @@ #include "xline.h" #include "servers.h" #include "bots.h" -#include "regchannel.h" #include "protocol.h" #include "config.h" #include "channels.h" +#include "event.h" +#include "modules/chanserv.h" /* Anope */ Server *Me = NULL; @@ -27,7 +36,7 @@ Anope::map<Server *> Servers::ByID; std::set<Anope::string> Servers::Capab; -Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Anope::string &desc, const Anope::string &ssid, bool jupe) : name(sname), hops(shops), description(desc), sid(ssid), uplink(up), users(0) +Server::Server(Server *up, const Anope::string &sname, unsigned int shops, const Anope::string &desc, const Anope::string &ssid, bool jupe) : name(sname), hops(shops), description(desc), sid(ssid), uplink(up), users(0) { syncing = true; juped = jupe; @@ -37,7 +46,7 @@ Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Ano if (!ssid.empty()) Servers::ByID[ssid] = this; - Log(this, "connect") << "has connected to the network (uplinked to " << (this->uplink ? this->uplink->GetName() : "no uplink") << ")"; + this->logger.Category("connect").Log(_("{0} has connected to the network (uplinked to {1})"), this->GetName(), this->uplink ? this->uplink->GetName() : "no uplink"); /* Add this server to our uplinks leaf list */ if (this->uplink) @@ -46,98 +55,15 @@ Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Ano /* Check to be sure this isn't a juped server */ if (Me == this->uplink && !juped) - { - /* Now do mode related stuff as we know what modes exist .. */ - for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) - { - BotInfo *bi = it->second; - Anope::string modes = !bi->botmodes.empty() ? ("+" + bi->botmodes) : IRCD->DefaultPseudoclientModes; - - bi->SetModesInternal(bi, modes.c_str()); - for (unsigned i = 0; i < bi->botchannels.size(); ++i) - { - size_t h = bi->botchannels[i].find('#'); - if (h == Anope::string::npos) - continue; - Anope::string chname = bi->botchannels[i].substr(h); - Channel *c = Channel::Find(chname); - if (c && c->FindUser(bi)) - { - Anope::string want_modes = bi->botchannels[i].substr(0, h); - for (unsigned j = 0; j < want_modes.length(); ++j) - { - ChannelMode *cm = ModeManager::FindChannelModeByChar(want_modes[j]); - if (cm == NULL) - cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_modes[j])); - if (cm && cm->type == MODE_STATUS) - { - MessageSource ms = bi; - c->SetModeInternal(ms, cm, bi->nick); - } - } - } - } - } - - IRCD->SendBOB(); - - for (unsigned i = 0; i < Me->GetLinks().size(); ++i) - { - Server *s = Me->GetLinks()[i]; - - if (s->juped) - IRCD->SendServer(s); - } - - /* We make the bots go online */ - for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) - { - User *u = it->second; - - BotInfo *bi = BotInfo::Find(u->GetUID()); - if (bi) - { - XLine x(bi->nick, "Reserved for services"); - IRCD->SendSQLine(NULL, &x); - } - - IRCD->SendClientIntroduction(u); - if (bi) - bi->introduced = true; - } - - for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it) - { - Channel *c = it->second; - - if (c->users.empty()) - IRCD->SendChannel(c); - else - for (Channel::ChanUserList::const_iterator cit = c->users.begin(), cit_end = c->users.end(); cit != cit_end; ++cit) - IRCD->SendJoin(cit->second->user, c, &cit->second->status); - - for (Channel::ModeList::const_iterator it2 = c->GetModes().begin(); it2 != c->GetModes().end(); ++it2) - { - ChannelMode *cm = ModeManager::FindChannelModeByName(it2->first); - if (!cm || cm->type != MODE_LIST) - continue; - ModeManager::StackerAdd(c->ci->WhoSends(), c, cm, true, it2->second); - } - - if (!c->topic.empty() && !c->topic_setter.empty()) - IRCD->SendTopic(c->ci->WhoSends(), c); - - c->syncing = true; - } - } + Burst(); } - FOREACH_MOD(OnNewServer, (this)); + EventManager::Get()->Dispatch(&Event::NewServer::OnNewServer, this); } Server::~Server() { - Log(this, "quit") << "quit from " << (this->uplink ? this->uplink->GetName() : "no uplink") << " for " << this->quit_reason; + this->logger.Category("quit").Log(_("{0} quit from {1} for {2}"), this->GetName(), this->uplink ? this->uplink->GetName() : "no uplink", this->quit_reason); for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) { @@ -150,14 +76,14 @@ Server::~Server() } } - Log(LOG_DEBUG) << "Finished removing all users for " << this->GetName(); + this->logger.Debug("Finished removing all users for {0}", this->GetName()); if (this->uplink) this->uplink->DelLink(this); - for (unsigned i = this->links.size(); i > 0; --i) + for (unsigned int i = this->links.size(); i > 0; --i) this->links[i - 1]->Delete(this->quit_reason); - + Servers::ByName.erase(this->name); if (!this->sid.empty()) Servers::ByID.erase(this->sid); @@ -167,10 +93,67 @@ void Server::Delete(const Anope::string &reason) { this->quit_reason = reason; this->quitting = true; - FOREACH_MOD(OnServerQuit, (this)); + EventManager::Get()->Dispatch(&Event::ServerQuit::OnServerQuit, this); delete this; } +void Server::Burst() +{ + IRCD->SendBOB(); + + for (unsigned int i = 0; i < Me->GetLinks().size(); ++i) + { + Server *s = Me->GetLinks()[i]; + + if (s->juped) + IRCD->Send<messages::MessageServer>(s); + } + + /* We make the bots go online */ + for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) + { + User *u = it->second; + + ServiceBot *bi = ServiceBot::Find(u->GetUID()); + if (bi) + { +#warning "xline on stack" + //XLine x(bi->nick, "Reserved for services"); + //IRCD->SendSQLine(NULL, &x); + } + + IRCD->Send<messages::NickIntroduction>(u); + if (bi) + bi->introduced = true; + } + + ServiceBot *chanserv = Config->GetClient("ChanServ"); + + for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it) + { + Channel *c = it->second; + + if (c->users.empty()) + IRCD->Send<messages::MessageChannel>(c); + else + for (Channel::ChanUserList::const_iterator cit = c->users.begin(), cit_end = c->users.end(); cit != cit_end; ++cit) + IRCD->Send<messages::Join>(cit->second->user, c, &cit->second->status); + + for (Channel::ModeList::const_iterator it2 = c->GetModes().begin(); it2 != c->GetModes().end(); ++it2) + { + ChannelMode *cm = ModeManager::FindChannelModeByName(it2->first); + if (!cm || cm->type != MODE_LIST) + continue; + ModeManager::StackerAdd(nullptr, c, cm, true, it2->second); + } + + if (!c->topic.empty() && !c->topic_setter.empty()) + IRCD->Send<messages::Topic>(c->ci ? c->ci->WhoSends() : chanserv, c, c->topic, c->topic_ts, c->topic_setter); + + c->syncing = true; + } +} + const Anope::string &Server::GetName() const { return this->name; @@ -226,7 +209,7 @@ void Server::AddLink(Server *s) { this->links.push_back(s); - Log(this, "connect") << "introduced " << s->GetName(); + this->logger.Category("connect").Log(_("{0} introduced {1}"), this->GetName(), s->GetName()); } void Server::DelLink(Server *s) @@ -243,7 +226,7 @@ void Server::DelLink(Server *s) } } - Log(this, "quit") << "quit " << s->GetName(); + this->logger.Category("quit").Log(_("{0} quit {1}"), this->GetName(), s->GetName()); } void Server::Sync(bool sync_links) @@ -253,9 +236,9 @@ void Server::Sync(bool sync_links) syncing = false; - Log(this, "sync") << "is done syncing"; + this->logger.Category("sync").Log(_("{0} is done syncing"), this->GetName()); - FOREACH_MOD(OnServerSync, (this)); + EventManager::Get()->Dispatch(&Event::ServerSync::OnServerSync, this); if (sync_links && !this->links.empty()) { @@ -267,7 +250,7 @@ void Server::Sync(bool sync_links) if (me) { - FOREACH_MOD(OnPreUplinkSync, (this)); + EventManager::Get()->Dispatch(&Event::PreUplinkSync::OnPreUplinkSync, this); } for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end;) @@ -284,11 +267,11 @@ void Server::Sync(bool sync_links) IRCD->SendEOB(); Me->Sync(false); - FOREACH_MOD(OnUplinkSync, (this)); + EventManager::Get()->Dispatch(&Event::UplinkSync::OnUplinkSync, this); if (!Anope::NoFork) { - Log(LOG_TERMINAL) << "Successfully linked, launching into background..."; + Anope::Logger.Terminal(_("Successfully linked, launching into background...")); Anope::Fork(); } } @@ -325,29 +308,29 @@ bool Server::IsQuitting() const return quitting; } -void Server::Notice(BotInfo *source, const Anope::string &message) +void Server::Notice(ServiceBot *source, const Anope::string &message) { if (Config->UsePrivmsg && Config->DefPrivmsg) - IRCD->SendGlobalPrivmsg(source, this, message); + IRCD->Send<messages::GlobalPrivmsg>(source, this, message); else - IRCD->SendGlobalNotice(source, this, message); + IRCD->Send<messages::GlobalNotice>(source, this, message); } Server *Server::Find(const Anope::string &name, bool name_only) { Anope::map<Server *>::iterator it; - + if (!name_only) { it = Servers::ByID.find(name); if (it != Servers::ByID.end()) return it->second; } - + it = Servers::ByName.find(name); if (it != Servers::ByName.end()) return it->second; - + return NULL; } diff --git a/src/service.cpp b/src/service.cpp new file mode 100644 index 000000000..9e99d0cad --- /dev/null +++ b/src/service.cpp @@ -0,0 +1,67 @@ +/* + * Anope IRC Services + * + * Copyright (C) 2016 Adam <Adam@anope.org> + * Copyright (C) 2014-2016 Anope Team <team@anope.org> + * + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. + */ + +#include "services.h" +#include "service.h" +#include "modules/nickserv.h" +#include "modules/chanserv.h" +#include "modules/memoserv.h" + +NickServ::NickServService *NickServ::service = nullptr; +ChanServ::ChanServService *ChanServ::service = nullptr; +MemoServ::MemoServService *MemoServ::service = nullptr; + +ServiceReferenceBase::ServiceReferenceBase(const Anope::string &_type, const Anope::string &_name) : type(_type), name(_name) +{ + ServiceManager::Get()->RegisterReference(this); +} + +ServiceReferenceBase::ServiceReferenceBase(const Anope::string &_type) : ServiceReferenceBase(_type, "") +{ +} + +ServiceReferenceBase::~ServiceReferenceBase() +{ + ServiceManager::Get()->UnregisterReference(this); +} + +void ServiceReferenceBase::SetService(Service *service) +{ + if (service == nullptr) + this->services.clear(); + else + this->services = { service }; +} + +void ServiceReferenceBase::SetServices(const std::vector<Service *> &s) +{ + this->services = s; +} + +Service::Service(Module *o, const Anope::string &t, const Anope::string &n) : owner(o), type(t), name(n) +{ + ServiceManager::Get()->Register(this); +} + +Service::~Service() +{ + ServiceManager::Get()->Unregister(this); +} + diff --git a/src/service_manager.cpp b/src/service_manager.cpp new file mode 100644 index 000000000..aa2de8b07 --- /dev/null +++ b/src/service_manager.cpp @@ -0,0 +1,139 @@ +/* + * Anope IRC Services + * + * Copyright (C) 2016 Adam <Adam@anope.org> + * Copyright (C) 2016 Anope Team <team@anope.org> + * + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. + */ + +#include "services.h" +#include "service.h" +#include "logger.h" +#include "modules.h" + +ServiceManager *ServiceManager::manager = nullptr; + +void ServiceManager::Init() +{ + assert(manager == nullptr); + manager = new ServiceManager(); +} + +ServiceManager *ServiceManager::Get() +{ + return manager; +} + +void ServiceManager::Destroy() +{ + delete manager; + manager = nullptr; +} + +Service *ServiceManager::FindService(const Anope::string &name) +{ + for (Service *s : services) + if (s->GetName() == name) + return s; + return nullptr; +} + +Service *ServiceManager::FindService(const Anope::string &type, const Anope::string &name) +{ + for (Service *s : services) + if (s->GetType() == type && s->GetName() == name) + return s; + return nullptr; +} + +std::vector<Service *> ServiceManager::FindServices(const Anope::string &type) +{ + std::vector<Service *> v; + + for (Service *s : services) + if (s->GetType() == type) + v.push_back(s); + + return v; +} + +void ServiceManager::Register(Service *service) +{ + // assert type + if (service->GetType().empty()) + throw ModuleException("Service type must be non empty"); + + if (service->GetName().empty() == false) + { + Service *s = FindService(service->GetType(), service->GetName()); + + if (s != nullptr) + throw ModuleException("Service of type " + service->GetType() + " with name " + service->GetName() + " already exists from " + service->GetOwner()->name); + } + + Anope::Logger.Debug3("Service registered: {0} {1} address {2} by {3}", service->GetType(), service->GetName(), static_cast<void *>(this), service->GetOwner()); + + services.push_back(service); + + LookupAll(); +} + +void ServiceManager::Unregister(Service *service) +{ + Anope::Logger.Debug3("Service unregistered: {0} {1} address {2} by {3}", service->GetType(), service->GetName(), static_cast<void *>(service), service->GetOwner()); + + auto it = std::find(services.begin(), services.end(), service); + if (it != services.end()) + { + services.erase(it); + + LookupAll(); + } +} + +void ServiceManager::Lookup(ServiceReferenceBase *reference) +{ + if (reference->GetName().empty()) + { + std::vector<Service *> services = this->FindServices(reference->GetType()); + Anope::Logger.Debug3("Service lookup {0} type {1} name {2}: {3} services", static_cast<void *>(reference), reference->GetType(), reference->GetName(), services.size()); + reference->SetServices(services); + } + else + { + Service *service = this->FindService(reference->GetType(), reference->GetName()); + Anope::Logger.Debug3("Service lookup {0} type {1} name {2}: {3}", static_cast<void *>(reference), reference->GetType(), reference->GetName(), service); + reference->SetService(service); + } +} + +void ServiceManager::LookupAll() +{ + for (ServiceReferenceBase *s : references) + Lookup(s); +} + +void ServiceManager::RegisterReference(ServiceReferenceBase *reference) +{ + Lookup(reference); + this->references.push_back(reference); +} + +void ServiceManager::UnregisterReference(ServiceReferenceBase *reference) +{ + auto it = std::find(this->references.begin(), this->references.end(), reference); + if (it != this->references.end()) + this->references.erase(it); +} diff --git a/src/socket_clients.cpp b/src/socket_clients.cpp index bb0618f31..5c45cdf51 100644 --- a/src/socket_clients.cpp +++ b/src/socket_clients.cpp @@ -1,12 +1,20 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2011-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -34,7 +42,7 @@ bool ConnectionSocket::Process() } catch (const SocketException &ex) { - Log() << ex.GetReason(); + Anope::Logger.Log(ex.GetReason()); } return false; } @@ -54,7 +62,7 @@ void ConnectionSocket::OnConnect() void ConnectionSocket::OnError(const Anope::string &error) { - Log(LOG_DEBUG) << "Socket error: " << error; + Anope::Logger.Debug("Socket error: {0}", error); } ClientSocket::ClientSocket(ListenSocket *l, const sockaddrs &addr) : ls(l), clientaddr(addr) @@ -74,7 +82,7 @@ bool ClientSocket::Process() } catch (const SocketException &ex) { - Log() << ex.GetReason(); + Anope::Logger.Log(ex.GetReason()); } return false; } @@ -94,6 +102,6 @@ void ClientSocket::OnAccept() void ClientSocket::OnError(const Anope::string &error) { - Log(LOG_DEBUG) << "Socket error: " << error; + Anope::Logger.Debug("Socket error: {0}", error); } diff --git a/src/socket_transport.cpp b/src/socket_transport.cpp index 070807264..6b17aa5b7 100644 --- a/src/socket_transport.cpp +++ b/src/socket_transport.cpp @@ -1,12 +1,20 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2011-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -32,7 +40,7 @@ bool BufferedSocket::ProcessRead() return false; if (len < 0) return SocketEngine::IgnoreErrno(); - + tbuffer[len] = 0; this->read_buffer.append(tbuffer); this->recv_len = len; @@ -72,21 +80,6 @@ void BufferedSocket::Write(const char *buffer, size_t l) SocketEngine::Change(this, true, SF_WRITABLE); } -void BufferedSocket::Write(const char *message, ...) -{ - va_list vi; - char tbuffer[BUFSIZE]; - - if (!message) - return; - - va_start(vi, message); - int len = vsnprintf(tbuffer, sizeof(tbuffer), message, vi); - va_end(vi); - - this->Write(tbuffer, std::min(len, static_cast<int>(sizeof(tbuffer)))); -} - void BufferedSocket::Write(const Anope::string &message) { this->Write(message.c_str(), message.length()); @@ -130,7 +123,7 @@ bool BinarySocket::ProcessRead() int len = this->io->Recv(this, tbuffer, sizeof(tbuffer)); if (len <= 0) return false; - + return this->Read(tbuffer, len); } @@ -172,21 +165,6 @@ void BinarySocket::Write(const char *buffer, size_t l) SocketEngine::Change(this, true, SF_WRITABLE); } -void BinarySocket::Write(const char *message, ...) -{ - va_list vi; - char tbuffer[BUFSIZE]; - - if (!message) - return; - - va_start(vi, message); - int len = vsnprintf(tbuffer, sizeof(tbuffer), message, vi); - va_end(vi); - - this->Write(tbuffer, std::min(len, static_cast<int>(sizeof(tbuffer)))); -} - void BinarySocket::Write(const Anope::string &message) { this->Write(message.c_str(), message.length()); diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/socketengine_epoll.cpp index f132ba2b9..314e1ec67 100644 --- a/src/socketengines/socketengine_epoll.cpp +++ b/src/socketengines/socketengine_epoll.cpp @@ -1,6 +1,6 @@ /* * - * (C) 2003-2016 Anope Team + * (C) 2003-2014 Anope Team * Contact us at team@anope.org * * Please read COPYING and README for further details. @@ -28,7 +28,7 @@ void SocketEngine::Init() if (EngineHandle == -1) throw SocketException("Could not initialize epoll socket engine: " + Anope::LastError()); - + events.resize(DefaultSize); } @@ -46,7 +46,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag) bool before_registered = s->flags[SF_READABLE] || s->flags[SF_WRITABLE]; s->flags[flag] = set; - + bool now_registered = s->flags[SF_READABLE] || s->flags[SF_WRITABLE]; epoll_event ev; @@ -65,7 +65,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag) mod = EPOLL_CTL_MOD; else return; - + if (epoll_ctl(EngineHandle, mod, ev.data.fd, &ev) == -1) throw SocketException("Unable to epoll_ctl() fd " + stringify(ev.data.fd) + " to epoll: " + Anope::LastError()); } @@ -82,7 +82,7 @@ void SocketEngine::Process() if (total == -1) { if (errno != EINTR) - Log() << "SockEngine::Process(): error: " << Anope::LastError(); + Anope::Logger.Log("SocketEngine::Process(): error: {0}", Anope::LastError()); return; } diff --git a/src/socketengines/socketengine_kqueue.cpp b/src/socketengines/socketengine_kqueue.cpp index 9ccf128d5..a3f6d78aa 100644 --- a/src/socketengines/socketengine_kqueue.cpp +++ b/src/socketengines/socketengine_kqueue.cpp @@ -1,6 +1,6 @@ /* * - * (C) 2003-2016 Anope Team + * (C) 2003-2014 Anope Team * Contact us at team@anope.org * * Please read COPYING and README for further details. @@ -39,7 +39,7 @@ void SocketEngine::Init() if (kq_fd < 0) throw SocketException("Unable to create kqueue engine: " + Anope::LastError()); - + change_events.resize(DefaultSize); event_events.resize(DefaultSize); } @@ -56,7 +56,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag) return; s->flags[flag] = set; - + int mod; if (flag == SF_READABLE) mod = EVFILT_READ; @@ -83,7 +83,7 @@ void SocketEngine::Process() if (total == -1) { if (errno != EINTR) - Log() << "SockEngine::Process(): error: " << Anope::LastError(); + Anope::Logger.Log("SocketEngine::Process(): error: {0}", Anope::LastError()); return; } diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/socketengine_poll.cpp index 8475dd414..c469ed8e8 100644 --- a/src/socketengines/socketengine_poll.cpp +++ b/src/socketengines/socketengine_poll.cpp @@ -1,6 +1,6 @@ /* * - * (C) 2003-2016 Anope Team + * (C) 2003-2014 Anope Team * Contact us at team@anope.org * * Please read COPYING and README for further details. @@ -106,14 +106,14 @@ void SocketEngine::Process() if (total < 0) { if (errno != EINTR) - Log() << "SockEngine::Process(): error: " << Anope::LastError(); + Anope::Logger.Log("SocketEngine::Process(): error: {0}", Anope::LastError()); return; } for (unsigned i = 0, processed = 0; i < events.size() && processed != static_cast<unsigned>(total); ++i) { pollfd *ev = &events[i]; - + if (ev->revents != 0) ++processed; diff --git a/src/socketengines/socketengine_select.cpp b/src/socketengines/socketengine_select.cpp index 86b2085ea..7987010ec 100644 --- a/src/socketengines/socketengine_select.cpp +++ b/src/socketengines/socketengine_select.cpp @@ -1,6 +1,6 @@ /* * - * (C) 2003-2016 Anope Team + * (C) 2003-2014 Anope Team * Contact us at team@anope.org * * Please read COPYING and README for further details. @@ -46,7 +46,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag) bool before_registered = s->flags[SF_READABLE] || s->flags[SF_WRITABLE]; s->flags[flag] = set; - + bool now_registered = s->flags[SF_READABLE] || s->flags[SF_WRITABLE]; if (!before_registered && now_registered) @@ -107,7 +107,7 @@ void SocketEngine::Process() if (sresult == -1) { - Log() << "SockEngine::Process(): error: " << Anope::LastError(); + Anope::Logger.Log("SocketEngine::Process(): error: {0}", Anope::LastError()); } else if (sresult) { diff --git a/src/sockets.cpp b/src/sockets.cpp index f15f0ccbd..ecdddfbb2 100644 --- a/src/sockets.cpp +++ b/src/sockets.cpp @@ -1,12 +1,20 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2010-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -282,7 +290,7 @@ bool cidr::operator<(const cidr &other) const { if (this->addr.sa.sa_family != other.addr.sa.sa_family) return this->addr.sa.sa_family < other.addr.sa.sa_family; - + switch (this->addr.sa.sa_family) { case AF_INET: @@ -544,7 +552,7 @@ bool ListenSocket::ProcessRead() } catch (const SocketException &ex) { - Log() << ex.GetReason(); + Anope::Logger.Log(ex.GetReason()); } return true; } diff --git a/src/threadengine.cpp b/src/threadengine.cpp index f392ac472..bfd7605c3 100644 --- a/src/threadengine.cpp +++ b/src/threadengine.cpp @@ -1,48 +1,26 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2010-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "threadengine.h" #include "anope.h" - -#ifndef _WIN32 -#include <pthread.h> -#endif - -static inline pthread_attr_t *get_engine_attr() -{ - /* Threadengine attributes used by this thread engine */ - static pthread_attr_t attr; - static bool inited = false; - - if (inited == false) - { - if (pthread_attr_init(&attr)) - throw CoreException("Error calling pthread_attr_init"); - if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)) - throw CoreException("Unable to mark threads as joinable"); - inited = true; - } - - return &attr; -} - -static void *entry_point(void *parameter) -{ - Thread *thread = static_cast<Thread *>(parameter); - thread->Run(); - thread->SetExitState(); - pthread_exit(0); - return NULL; -} +#include <system_error> Thread::Thread() : exit(false) { @@ -55,7 +33,15 @@ Thread::~Thread() void Thread::Join() { this->SetExitState(); - pthread_join(handle, NULL); + try + { + if (this->handle.joinable()) + this->handle.join(); + } + catch (const std::system_error &error) + { + throw CoreException("Unable to join thread: " + Anope::string(error.what())); + } } void Thread::SetExitState() @@ -64,18 +50,28 @@ void Thread::SetExitState() exit = true; } -void Thread::Exit() -{ - this->SetExitState(); - pthread_exit(0); -} - void Thread::Start() { - if (pthread_create(&this->handle, get_engine_attr(), entry_point, this)) + try + { + this->handle = std::thread([this]() + { + try + { + this->Run(); + } + catch (...) + { + this->SetExitState(); + throw; + } + this->SetExitState(); + }); + } + catch (const std::system_error &error) { this->flags[SF_DEAD] = true; - throw CoreException("Unable to create thread: " + Anope::LastError()); + throw CoreException("Unable to create thread: " + Anope::string(error.what())); } } @@ -90,47 +86,28 @@ void Thread::OnNotify() this->flags[SF_DEAD] = true; } -Mutex::Mutex() -{ - pthread_mutex_init(&mutex, NULL); -} - -Mutex::~Mutex() -{ - pthread_mutex_destroy(&mutex); -} - void Mutex::Lock() { - pthread_mutex_lock(&mutex); -} - -void Mutex::Unlock() -{ - pthread_mutex_unlock(&mutex); + this->m.lock(); } bool Mutex::TryLock() { - return pthread_mutex_trylock(&mutex) == 0; + return this->m.try_lock(); } -Condition::Condition() : Mutex() +void Mutex::Unlock() { - pthread_cond_init(&cond, NULL); + this->m.unlock(); } -Condition::~Condition() +void Condition::Wait() { - pthread_cond_destroy(&cond); + this->cv.wait(this->m); } void Condition::Wakeup() { - pthread_cond_signal(&cond); + this->cv.notify_one(); } -void Condition::Wait() -{ - pthread_cond_wait(&cond, &mutex); -} diff --git a/src/timers.cpp b/src/timers.cpp index a4538c05d..dd32a9395 100644 --- a/src/timers.cpp +++ b/src/timers.cpp @@ -1,9 +1,20 @@ -/* Timer stuff. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2009-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 3e00b981d..76442b4ab 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,39 +1,22 @@ -# Find all the *.cpp files within the current source directory, and sort the list -file(GLOB TOOLS_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") -sort_list(TOOLS_SRCS) +if(PREFER_EMBEDDED_SQLITE OR NOT SQLITE_FOUND) + include_directories(${Anope_SOURCE_DIR}/lib/sqlite) +endif() -# Set all the files to use C++ as well as set their compile flags -set_source_files_properties(${TOOLS_SRCS} PROPERTIES LANGUAGE CXX COMPILE_FLAGS "${CXXFLAGS}") +function(build_sqlite LIBNAME) + add_library(tools_anope_sqlite_${LIBNAME} SHARED anope_sqlite.cpp) + if(PREFER_EMBEDDED_SQLITE OR NOT SQLITE_FOUND) + target_link_libraries(tools_anope_sqlite_${LIBNAME} sqlite3) + else() + target_link_libraries(tools_anope_sqlite_${LIBNAME} ${SQLITE_LIBRARIES}) + endif() + set_source_files_properties(anope_sqlite.cpp PROPERTIES LANGUAGE CXX COMPILE_FLAGS "${CXXFLAGS}") + set_target_properties(tools_anope_sqlite_${LIBNAME} PROPERTIES LINKER_LANGUAGE CXX LINK_FLAGS "${LDFLAGS}" OUTPUT_NAME "anope_sqlite_${LIBNAME}") + install(TARGETS tools_anope_sqlite_${LIBNAME} DESTINATION ${LIB_DIR}) +endfunction() -# Iterate through all the source files -foreach(SRC ${TOOLS_SRCS}) - # Convert the source file extension to have no extension - string(REGEX REPLACE "\\.cpp$" "" EXE ${SRC}) - # Calculate the header file dependencies for the given source file - calculate_depends(${SRC}) - # Only continue if this file isn't skipped - if(NOT SKIP) - # Generate the executable and set its linker flags, also set it to depend on the main Anope executable to be built beforehand - add_executable(${EXE} ${SRC}) - set_target_properties(${EXE} PROPERTIES LINKER_LANGUAGE CXX LINK_FLAGS "${LDFLAGS}") - add_dependencies(${EXE} ${PROGRAM_NAME}) - # Only for Windows, set anopesmtp to require the wsock32 library - if(WIN32 AND ${EXE} STREQUAL anopesmtp) - target_link_libraries(${EXE} wsock32) - endif(WIN32 AND ${EXE} STREQUAL anopesmtp) - if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS" AND ${EXE} STREQUAL anopesmtp) - target_link_libraries(${EXE} socket nsl) - endif(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS" AND ${EXE} STREQUAL anopesmtp) - # Set the executable to be installed to the bin directory under the main directory - install(TARGETS ${EXE} - DESTINATION ${BIN_DIR} - ) - # Add the executable to the list of files for CPack to ignore - get_target_property(EXE_BINARY ${EXE} LOCATION) - get_filename_component(EXE_BINARY ${EXE_BINARY} NAME) - add_to_cpack_ignored_files("${EXE_BINARY}$" TRUE) - endif(NOT SKIP) -endforeach(SRC) +build_sqlite(ascii) +build_sqlite(rfc1459) +build_sqlite(rfc1459_inspircd) # If not on Windows, generate anoperc and install it along with mydbgen if(NOT WIN32) @@ -44,9 +27,9 @@ if(NOT WIN32) install (PROGRAMS geoipupdate.sh DESTINATION ${BIN_DIR} ) -endif(NOT WIN32) +endif() # On non-Windows platforms, if RUNGROUP is set, change the permissions of the tools directory if(NOT WIN32 AND RUNGROUP) install(CODE "execute_process(COMMAND ${CHMOD} 2770 \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin\")") -endif(NOT WIN32 AND RUNGROUP) +endif() diff --git a/src/tools/anope_sqlite.cpp b/src/tools/anope_sqlite.cpp new file mode 100644 index 000000000..e03f99bd2 --- /dev/null +++ b/src/tools/anope_sqlite.cpp @@ -0,0 +1,132 @@ +/* + * Anope IRC Services + * + * Copyright (C) 2016 Anope Team <team@anope.org> + * + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. + */ + +#include <sqlite3ext.h> + +#include <algorithm> +#include <string> + +#ifdef _WIN32 +# define DllExport __declspec(dllexport) +#else +# define DllExport +#endif + +SQLITE_EXTENSION_INIT1 + +namespace +{ + +enum collation +{ + ANOPE_ASCII, + ANOPE_RFC1459, + ANOPE_RFC1459_INSPIRCD +}; + +char (*anope_tolower)(char) = nullptr; + +char tolower_ascii(char c) +{ + if (c >= 'A' && c <= 'Z') + return c + 0x20; + else + return c; +} + +char tolower_rfc1459_inspircd(char c) +{ + if (c == '[' || c == ']' || c == '\\') + return c + 0x20; + else + return tolower_ascii(c); +} + +char tolower_rfc1459(char c) +{ + if (c == '[' || c == ']' || c == '\\' || c == '^') + return c + 0x20; + else + return tolower_ascii(c); +} + +void anope_canonicalize(sqlite3_context *context, int argc, sqlite3_value **argv) +{ + sqlite3_value *arg = argv[0]; + const unsigned char *text = sqlite3_value_text(arg); + + if (text == nullptr || anope_tolower == nullptr) + return; + + std::string result(reinterpret_cast<const char *>(text)); + std::transform(result.begin(), result.end(), result.begin(), anope_tolower); + + sqlite3_result_text(context, result.c_str(), -1, SQLITE_TRANSIENT); +} + +int sqlite_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi, collation col) +{ + SQLITE_EXTENSION_INIT2(pApi); + + switch (col) + { + case ANOPE_ASCII: + anope_tolower = tolower_ascii; + break; + case ANOPE_RFC1459: + anope_tolower = tolower_rfc1459; + break; + case ANOPE_RFC1459_INSPIRCD: + anope_tolower = tolower_rfc1459_inspircd; + break; + default: + return SQLITE_INTERNAL; + } + + int rc = sqlite3_create_function_v2(db, "anope_canonicalize", 1, SQLITE_DETERMINISTIC, NULL, anope_canonicalize, NULL, NULL, NULL); + + return rc; +} + +} // namespace + +extern "C" DllExport +int sqlite3_anopesqliteascii_init(sqlite3 *, char **, const sqlite3_api_routines *); + +extern "C" DllExport +int sqlite3_anopesqliterfc1459_init(sqlite3 *, char **, const sqlite3_api_routines *); + +extern "C" DllExport +int sqlite3_anopesqliterfc1459inspircd_init(sqlite3 *, char **, const sqlite3_api_routines *); + +int sqlite3_anopesqliteascii_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) +{ + return sqlite_init(db, pzErrMsg, pApi, ANOPE_ASCII); +} + +int sqlite3_anopesqliterfc1459_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) +{ + return sqlite_init(db, pzErrMsg, pApi, ANOPE_RFC1459); +} + +int sqlite3_anopesqliterfc1459inspircd_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) +{ + return sqlite_init(db, pzErrMsg, pApi, ANOPE_RFC1459_INSPIRCD); +} + diff --git a/src/tools/anoperc.in b/src/tools/anoperc.in index 2802e57e2..ac379ed90 100644 --- a/src/tools/anoperc.in +++ b/src/tools/anoperc.in @@ -2,7 +2,7 @@ # # Configuration script for Services # -# (C) 2003-2016 Anope Team +# (C) 2003-2014 Anope Team # Contact us at team@anope.org # # Please read COPYING and README for further details. @@ -14,8 +14,8 @@ -ANOPEPID="@INSTDIR@/data/services.pid" -ANOPROG="@INSTDIR@/bin/services" +ANOPEPID="@INSTDIR@/data/anope.pid" +ANOPROG="@INSTDIR@/bin/anope" LOG="@INSTDIR@/logs/" ARCVERSION="2" @@ -65,7 +65,7 @@ if [ "$1" = "start" ] ; then echo "This error has been logged in your Anope Log file" echo "Located in "$LOG"" echo "This may help you diagnose the problem" - echo "Further help may be available from http://www.anope.org/" + echo "Further help may be available from https://anope.org/" exit 1 fi @@ -101,7 +101,7 @@ elif [ "$1" = "restart" ] ; then echo "This error has been logged in your Anope Log file" echo "Located in "$LOG"" echo "This may help you diagnose the problem" - echo "Further help may be available from http://www.anope.org/" + echo "Further help may be available from https://anope.org/" exit 1 fi @@ -128,7 +128,7 @@ elif [ "$1" = "help" ] ; then echo "$0 help Show this help menu" echo "If you need further help please check the /docs/" echo "folder or make use of our extensive online support at" - echo "http://www.anope.org/" + echo "https://anope.org/" fi else diff --git a/src/tools/anopesmtp.cpp b/src/tools/anopesmtp.cpp deleted file mode 100644 index b0cf0847d..000000000 --- a/src/tools/anopesmtp.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/* smtp stuff handler for win32. - * - * (C) 2003-2016 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. - * - * Written by Dominick Meglio <codemastr@unrealircd.com> - * *nix port by Trystan Scott Lee <trystan@nomadirc.net> - */ - -#include "sysconf.h" - -/* Some Linux boxes (or maybe glibc includes) require this for the - * prototype of strsignal(). */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#include <string> -#include <vector> -#include <cstdarg> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <ctime> -#include <cerrno> -#include <iostream> -#include <fstream> - -#ifndef _WIN32 -# include <unistd.h> -# include <netdb.h> -# include <netinet/in.h> -# include <sys/socket.h> -# include <arpa/inet.h> -# include <sys/time.h> -#else -# include <winsock.h> -# define WIN32_LEAN_AND_MEAN -# include <windows.h> -#endif - -#include <sys/types.h> - -#ifdef _AIX -extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, size_t); -# if 0 /* These break on some AIX boxes (4.3.1 reported). */ -extern int socket(int, int, int); -extern int connect(int, struct sockaddr *, int); -# endif -#endif /* _AIX */ - -/* Some SUN fixs */ -#ifdef __sun -/* Solaris specific code, types that do not exist in Solaris' - * * sys/types.h - * **/ -# ifndef INADDR_NONE -# define INADDR_NONE (-1) -# endif -#endif - -#ifdef _WIN32 -typedef SOCKET ano_socket_t; -#define ano_sockclose(fd) closesocket(fd) -#define ano_sockread(fd, buf, len) recv(fd, buf, len, 0) -#define ano_sockwrite(fd, buf, len) send(fd, buf, len, 0) -#else -typedef int ano_socket_t; -#define ano_sockclose(fd) close(fd) -#define ano_sockread(fd, buf, len) read(fd, buf, len) -#define ano_sockwrite(fd, buf, len) write(fd, buf, len) -#define SOCKET_ERROR -1 -#endif - -/* Data structures */ -struct smtp_message -{ - std::vector<std::string> smtp_headers; - std::vector<std::string> smtp_body; - std::string from; - std::string to; - ano_socket_t sock; -}; - -int smtp_debug = 0; - -struct smtp_message smail; - -static std::string get_logname(struct tm *tm = NULL) -{ - char timestamp[32]; - - if (!tm) - { - time_t t = time(NULL); - tm = localtime(&t); - } - - strftime(timestamp, sizeof(timestamp), "%Y%m%d", tm); - std::string name = std::string("anopesmtp.") + timestamp; - return name; -} - -/* TimeStamp for Email Header */ -static std::string GetTimeStamp() -{ - char tbuf[256]; - time_t t = time(NULL); - struct tm *tm = localtime(&t); - - strftime(tbuf, sizeof(tbuf) - 1, "%a, %d %b %Y %H:%M:%S %z", tm); - - return tbuf; -} - -/* Log stuff to the log file with a datestamp. Note that errno is - * preserved by this routine and log_perror(). - */ - -void alog(const char *fmt, ...) -{ - if (!smtp_debug || !fmt) - return; - - std::fstream file; - file.open(get_logname().c_str(), std::ios_base::out | std::ios_base::app); - - if (!file.is_open()) - return; - - va_list args; - va_start(args, fmt); - - time_t t = time(NULL); - struct tm *tm = localtime(&t); - - char buf[256]; - strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", tm); - file << buf; - vsnprintf(buf, sizeof(buf), fmt, args); - file << buf << std::endl; - va_end(args); - va_end(args); - - file.close(); -} - -/* Remove a trailing \r\n */ -std::string strip(const std::string &buf) -{ - std::string newbuf = buf; - char c = newbuf[newbuf.size() - 1]; - while (c == '\n' || c == '\r') - { - newbuf.erase(newbuf.end() - 1); - c = newbuf[newbuf.size() - 1]; - } - return newbuf; -} - -/* Is the buffer a header? */ -bool smtp_is_header(const std::string &buf) -{ - size_t tmp = buf.find(' '); - - if (tmp == std::string::npos) - return false; - - if (tmp > 0 && buf[tmp - 1] == ':') - return true; - return false; -} - -/* Parse a header into a name and value */ -void smtp_parse_header(const std::string &buf, std::string &header, std::string &value) -{ - std::string newbuf = strip(buf); - - size_t space = newbuf.find(' '); - if (space != std::string::npos) - { - header = newbuf.substr(0, space); - value = newbuf.substr(space + 1); - } - else - { - header = newbuf; - value = ""; - } -} - -/* Have we reached the end of input? */ -bool smtp_is_end(const std::string &buf) -{ - if (buf[0] == '.') - if (buf[1] == '\r' || buf[1] == '\n') - return true; - - return false; -} - -/* Set who the email is to */ -void smtp_set_to(const std::string &to) -{ - smail.to = to; - size_t c = smail.to.rfind('<'); - if (c != std::string::npos && c + 1 < smail.to.size()) - { - smail.to = smail.to.substr(c + 1); - smail.to.erase(smail.to.end() - 1); - } -} - -/* Establish a connection to the SMTP server */ -int smtp_connect(const char *host, unsigned short port) -{ - struct sockaddr_in addr; - - if ((smail.sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) - return 0; - - if ((addr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) - { - struct hostent *hent; - if (!(hent = gethostbyname(host))) - return 0; - memcpy(&addr.sin_addr, hent->h_addr, hent->h_length); - } - addr.sin_family = AF_INET; - addr.sin_port = htons(port ? port : 25); - if (connect(smail.sock, reinterpret_cast<struct sockaddr *>(&addr), sizeof(struct sockaddr_in)) == SOCKET_ERROR) - { - ano_sockclose(smail.sock); - return 0; - } - - return 1; -} - -/* Send a line of text */ -int smtp_send(const char *text) -{ - int result = ano_sockwrite(smail.sock, text, strlen(text)); - - alog("SMTP: sent %s",text); - - if (result == SOCKET_ERROR) - ano_sockclose(smail.sock); - - return result; -} - -/* Read a line of text */ -int smtp_read(char *buf, int len) -{ - int result; - - memset(buf, 0, len); - result = ano_sockread(smail.sock, buf, len); - - if (result == SOCKET_ERROR) - ano_sockclose(smail.sock); - - return result; -} - -/* Retrieve a response code */ -int smtp_get_code(const std::string &text) -{ - size_t tmp = text.find(' '); - - if (tmp == std::string::npos) - return 0; - - return atol(text.substr(0, tmp).c_str()); -} - -/* Send the email */ -int smtp_send_email() -{ - char buf[1024]; - if (!smtp_read(buf, 1024)) - { - alog("SMTP: error reading buffer"); - return 0; - } - - int code = smtp_get_code(buf); - if (code != 220) - { - alog("SMTP: error expected code 220 got %d",code); - return 0; - } - - if (!smtp_send("HELO anope\r\n")) - { - alog("SMTP: error writting to socket"); - return 0; - } - - if (!smtp_read(buf, 1024)) - { - alog("SMTP: error reading buffer"); - return 0; - } - - code = smtp_get_code(buf); - if (code != 250) - { - alog("SMTP: error expected code 250 got %d",code); - return 0; - } - - strcpy(buf, "MAIL FROM: <"); - strcat(buf, smail.from.c_str()); - strcat(buf, ">\r\n"); - - if (!smtp_send(buf)) - { - alog("SMTP: error writting to socket"); - return 0; - } - - if (!smtp_read(buf, 1024)) - { - alog("SMTP: error reading buffer"); - return 0; - } - - code = smtp_get_code(buf); - if (code != 250) - return 0; - - strcpy(buf, "RCPT TO: <"); - strcat(buf, smail.to.c_str()); - strcat(buf, ">\r\n"); - - if (!smtp_send(buf)) - { - alog("SMTP: error writting to socket"); - return 0; - } - - if (!smtp_read(buf, 1024)) - { - alog("SMTP: error reading buffer"); - return 0; - } - - code = smtp_get_code(buf); - if (smtp_get_code(buf) != 250) - { - alog("SMTP: error expected code 250 got %d",code); - return 0; - } - - if (!smtp_send("DATA\r\n")) - { - alog("SMTP: error writting to socket"); - return 0; - } - - if (!smtp_read(buf, 1024)) - { - alog("SMTP: error reading buffer"); - return 0; - } - - code = smtp_get_code(buf); - if (code != 354) - { - alog("SMTP: error expected code 354 got %d",code); - return 0; - } - - for (std::vector<std::string>::const_iterator it = smail.smtp_headers.begin(), it_end = smail.smtp_headers.end(); it != it_end; ++it) - if (!smtp_send(it->c_str())) - { - alog("SMTP: error writting to socket"); - return 0; - } - - if (!smtp_send("\r\n")) - { - alog("SMTP: error writting to socket"); - return 0; - } - - bool skip_done = false; - for (std::vector<std::string>::const_iterator it = smail.smtp_body.begin(), it_end = smail.smtp_body.end(); it != it_end; ++it) - if (skip_done) - { - if (!smtp_send(it->c_str())) - { - alog("SMTP: error writting to socket"); - return 0; - } - } - else - skip_done = true; - - if (!smtp_send("\r\n.\r\n")) - { - alog("SMTP: error writting to socket"); - return 0; - } - - return 1; -} - -void smtp_disconnect() -{ - smtp_send("QUIT\r\n"); - ano_sockclose(smail.sock); -} - -int main(int argc, char *argv[]) -{ - /* Win32 stuff */ -#ifdef _WIN32 - WSADATA wsa; -#endif - - if (argc == 1) - return 0; - - if (argc == 3 && !strcmp(argv[2], "--debug")) - smtp_debug = 1; - - char *server = strtok(argv[1], ":"), *aport; - short port; - if ((aport = strtok(NULL, ""))) - port = atoi(aport); - else - port = 25; - - if (!server) - { - alog("No Server"); - /* Bad, bad, bad. This was a return from main with no value! -GD */ - return 0; - } - else - alog("SMTP: server %s port %d",server,port); - - /* The WSAStartup function initiates use of WS2_32.DLL by a process. */ - /* guessing we can skip it under *nix */ -#ifdef _WIN32 - if (WSAStartup(MAKEWORD(1, 1), &wsa)) - return 0; -#endif - - char buf[8192]; - bool headers_done = false; - /* Read the message and parse it */ - while (fgets(buf, 8192, stdin)) - { - if (smtp_is_header(buf) && !headers_done) - { - smail.smtp_headers.push_back(strip(buf) + "\r\n"); - std::string header, value; - smtp_parse_header(buf, header, value); - if (header == "From:") - { - alog("SMTP: from: %s", value.c_str()); - smail.from = value; - } - else if (header == "To:") - { - alog("SMTP: to: %s", value.c_str()); - smtp_set_to(value); - } - else if (smtp_is_end(buf)) - break; - else - { - smail.smtp_headers.push_back("Date: " + GetTimeStamp() + "\r\n"); - headers_done = true; - smail.smtp_body.push_back(strip(buf) + "\r\n"); - } - } - else - smail.smtp_body.push_back(strip(buf) + "\r\n"); - } - - if (!smtp_connect(server, port)) - { - alog("SMTP: failed to connect to %s:%d", server, port); - return 0; - } - if (!smtp_send_email()) - { - alog("SMTP: error during sending of mail"); - return 0; - } - smtp_disconnect(); - - return 1; -} diff --git a/src/uplink.cpp b/src/uplink.cpp index df38f98f2..0f47788e7 100644 --- a/src/uplink.cpp +++ b/src/uplink.cpp @@ -1,12 +1,20 @@ /* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2012-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "uplink.h" @@ -14,6 +22,10 @@ #include "config.h" #include "protocol.h" #include "servers.h" +#include "event.h" +#include "bots.h" +#include "timers.h" +#include "modules.h" UplinkSocket *UplinkSock = NULL; @@ -22,7 +34,7 @@ class ReconnectTimer : public Timer public: ReconnectTimer(int wait) : Timer(wait) { } - void Tick(time_t) + void Tick(time_t) override { try { @@ -30,7 +42,7 @@ class ReconnectTimer : public Timer } catch (const SocketException &ex) { - Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << "): " << ex.GetReason(); + Anope::Logger.Terminal(_("Unable to connect to uplink #{0} ({1}:{2}): {3}"), Anope::CurrentUplink + 1, Config->Uplinks[Anope::CurrentUplink].host, Config->Uplinks[Anope::CurrentUplink].port, ex.GetReason()); } } }; @@ -39,7 +51,7 @@ void Uplink::Connect() { if (Config->Uplinks.empty()) { - Log() << "Warning: There are no configured uplinks."; + Anope::Logger.Log(_("Warning: There are no configured uplinks.")); return; } @@ -49,11 +61,11 @@ void Uplink::Connect() Configuration::Uplink &u = Config->Uplinks[Anope::CurrentUplink]; new UplinkSocket(); - if (!Config->GetBlock("serverinfo")->Get<const Anope::string>("localhost").empty()) - UplinkSock->Bind(Config->GetBlock("serverinfo")->Get<const Anope::string>("localhost")); - FOREACH_MOD(OnPreServerConnect, ()); + if (!Config->GetBlock("serverinfo")->Get<Anope::string>("localhost").empty()) + UplinkSock->Bind(Config->GetBlock("serverinfo")->Get<Anope::string>("localhost")); + EventManager::Get()->Dispatch(&Event::PreServerConnect::OnPreServerConnect); Anope::string ip = Anope::Resolve(u.host, u.ipv6 ? AF_INET6 : AF_INET); - Log(LOG_TERMINAL) << "Attempting to connect to uplink #" << (Anope::CurrentUplink + 1) << " " << u.host << " (" << ip << "), port " << u.port; + Anope::Logger.Terminal(_("Attempting to connect to uplink #{0} {1} ({2}), port {3}"), Anope::CurrentUplink + 1, u.host, ip, u.port); UplinkSock->Connect(ip, u.port); } @@ -70,14 +82,14 @@ UplinkSocket::~UplinkSocket() this->OnError(""); Module *protocol = ModuleManager::FindFirstOf(PROTOCOL); if (protocol && !protocol->name.find("inspircd")) - Log(LOG_TERMINAL) << "Check that you have loaded m_spanningtree.so on InspIRCd, and are not connecting Anope to an SSL enabled port without configuring SSL in Anope (or vice versa)"; + Anope::Logger.Terminal(_("Check that you have loaded m_spanningtree.so on InspIRCd, and are not connecting Anope to an SSL enabled port without configuring SSL in Anope (or vice versa)")); else - Log(LOG_TERMINAL) << "Check that you are not connecting Anope to an SSL enabled port without configuring SSL in Anope (or vice versa)"; + Anope::Logger.Terminal(_("Check that you are not connecting Anope to an SSL enabled port without configuring SSL in Anope (or vice versa)")); } if (IRCD && Servers::GetUplink() && Servers::GetUplink()->IsSynced()) { - FOREACH_MOD(OnServerDisconnect, ()); + EventManager::Get()->Dispatch(&Event::ServerDisconnect::OnServerDisconnect); for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) { @@ -87,13 +99,13 @@ UplinkSocket::~UplinkSocket() { /* Don't use quitmsg here, it may contain information you don't want people to see */ IRCD->SendQuit(u, "Shutting down"); - BotInfo* bi = BotInfo::Find(u->GetUID()); + ServiceBot* bi = ServiceBot::Find(u->GetUID()); if (bi != NULL) bi->introduced = false; } } - IRCD->SendSquit(Me, Anope::QuitReason); + IRCD->Send<messages::SQuit>(Me, Anope::QuitReason); this->ProcessWrite(); // Write out the last bit } @@ -123,7 +135,7 @@ UplinkSocket::~UplinkSocket() { time_t retry = Config->GetBlock("options")->Get<time_t>("retrywait"); - Log() << "Disconnected, retrying in " << retry << " seconds"; + Anope::Logger.Log(_("Disconnected, retrying in {0} seconds"), retry); new ReconnectTimer(retry); } } @@ -142,72 +154,59 @@ bool UplinkSocket::ProcessRead() void UplinkSocket::OnConnect() { - Log(LOG_TERMINAL) << "Successfully connected to uplink #" << (Anope::CurrentUplink + 1) << " " << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port; - IRCD->SendConnect(); - FOREACH_MOD(OnServerConnect, ()); + Anope::Logger.Terminal(_("Successfully connected to uplink #{0} {1}:{2}"), Anope::CurrentUplink + 1, Config->Uplinks[Anope::CurrentUplink].host, Config->Uplinks[Anope::CurrentUplink].port); + IRCD->Handshake(); + EventManager::Get()->Dispatch(&Event::ServerConnect::OnServerConnect); } void UplinkSocket::OnError(const Anope::string &err) { - Anope::string what = !this->flags[SF_CONNECTED] ? "Unable to connect to" : "Lost connection from"; - Log(LOG_TERMINAL) << what << " uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << ")" << (!err.empty() ? (": " + err) : ""); + if (!this->flags[SF_CONNECTED]) + Anope::Logger.Terminal(_("Unable to connect to uplink #{0} ({1}:{2}): {3}{4}"), Anope::CurrentUplink + 1, Config->Uplinks[Anope::CurrentUplink].host, Config->Uplinks[Anope::CurrentUplink].port, !err.empty() ? (": " + err) : ""); + else + Anope::Logger.Terminal(_("Lost connection from uplink #{0} ({1}:{2}): {3}{4}"), Anope::CurrentUplink + 1, Config->Uplinks[Anope::CurrentUplink].host, Config->Uplinks[Anope::CurrentUplink].port, !err.empty() ? (": " + err) : ""); error |= !err.empty(); } -UplinkSocket::Message::Message() : source(Me) -{ -} - -UplinkSocket::Message::Message(const MessageSource &src) : source(src) -{ -} - -UplinkSocket::Message::~Message() +void Uplink::SendMessage(IRCMessage &message) { - Anope::string message_source; + const MessageSource &source = message.GetSource(); + Anope::string buffer = IRCD->Format(message); - if (this->source.GetServer() != NULL) + if (source.GetServer() != NULL) { - const Server *s = this->source.GetServer(); + const Server *s = source.GetServer(); if (s != Me && !s->IsJuped()) { - Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << s->GetName() << " who is not from me?"; + Anope::Logger.Debug("Attempted to send \"{0}\" from {1} who is not from me?", buffer, s->GetName()); return; } - - message_source = s->GetSID(); } - else if (this->source.GetUser() != NULL) + else if (source.GetUser() != NULL) { - const User *u = this->source.GetUser(); + const User *u = source.GetUser(); if (u->server != Me && !u->server->IsJuped()) { - Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << u->nick << " who is not from me?"; + Anope::Logger.Debug("Attempted to send \"{0}\" from {1} who is not from me?", buffer, u->nick); return; } - const BotInfo *bi = this->source.GetBot(); + const ServiceBot *bi = source.GetBot(); if (bi != NULL && bi->introduced == false) { - Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << bi->nick << " when not introduced"; + Anope::Logger.Debug("Attempted to send \"{0}\" from {1} when not introduced", buffer, bi->nick); return; } - - message_source = u->GetUID(); } if (!UplinkSock) { - if (!message_source.empty()) - Log(LOG_DEBUG) << "Attempted to send \"" << message_source << " " << this->buffer.str() << "\" with UplinkSock NULL"; - else - Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" with UplinkSock NULL"; + Anope::Logger.Debug("Attempted to send \"{0}\" when not connected", buffer); return; } - Anope::string sent = IRCD->Format(message_source, this->buffer.str()); - UplinkSock->Write(sent); - Log(LOG_RAWIO) << "Sent: " << sent; + UplinkSock->Write(buffer); + Anope::Logger.RawIO("Sent: {0}", buffer); } diff --git a/src/users.cpp b/src/users.cpp index 25e558c5f..018f88476 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -1,18 +1,25 @@ -/* Routines to maintain a list of online users. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2003-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "modules.h" #include "users.h" -#include "account.h" #include "protocol.h" #include "servers.h" #include "channels.h" @@ -22,16 +29,18 @@ #include "language.h" #include "sockets.h" #include "uplink.h" +#include "event.h" +#include "messages.h" +#include "modules/nickserv.h" -user_map UserListByNick, UserListByUID; +user_map UserListByNick; +uid_map UserListByUID; int OperCount = 0; -unsigned MaxUserCount = 0; -time_t MaxUserTime = 0; std::list<User *> User::quitting_users; -User::User(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &uip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *account) : ip(uip) +User::User(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &uip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickServ::Account *account) : ip(uip), logger(this) { if (snick.empty() || sident.empty() || shost.empty()) throw CoreException("Bad args passed to User::User"); @@ -53,14 +62,13 @@ User::User(const Anope::string &snick, const Anope::string &sident, const Anope: this->SetModesInternal(sserver, "%s", smodes.c_str()); this->uid = suid; this->super_admin = false; - this->nc = NULL; size_t old = UserListByNick.size(); UserListByNick[snick] = this; if (!suid.empty()) UserListByUID[suid] = this; if (old == UserListByNick.size()) - Log(LOG_DEBUG) << "Duplicate user " << snick << " in user table?"; + Anope::Logger.Debug("Duplicate user {0} in user table?", snick); this->Login(account); this->UpdateHost(); @@ -69,21 +77,13 @@ User::User(const Anope::string &snick, const Anope::string &sident, const Anope: { ++sserver->users; if (server->IsSynced()) - Log(this, "connect") << (!vhost.empty() && vhost != host ? "(" + vhost + ") " : "") << "(" << srealname << ") " << (!uip.empty() && uip != host ? "[" + uip + "] " : "") << "connected to the network (" << sserver->GetName() << ")"; - } - - if (UserListByNick.size() > MaxUserCount) - { - MaxUserCount = UserListByNick.size(); - MaxUserTime = Anope::CurTime; - if (sserver && sserver->IsSynced()) - Log(this, "maxusers") << "connected - new maximum user count: " << UserListByNick.size(); + logger.Category("connect").Log(_("{0} ({1}) ({2}) [{3}] connected to the network ({4})"), this->GetMask(), vhost.empty() ? host : vhost, srealname, uip.empty() ? host : uip, sserver->GetName()); } bool exempt = false; if (server && server->IsULined()) exempt = true; - FOREACH_MOD(OnUserConnect, (this, exempt)); + EventManager::Get()->Dispatch(&Event::UserConnect::OnUserConnect, this, exempt); } static void CollideKill(User *target, const Anope::string &reason) @@ -93,10 +93,10 @@ static void CollideKill(User *target, const Anope::string &reason) else { // Be sure my user is really dead - IRCD->SendQuit(target, "%s", reason.c_str()); + IRCD->SendQuit(target, reason); // Reintroduce my client - if (BotInfo *bi = dynamic_cast<BotInfo *>(target)) + if (ServiceBot *bi = dynamic_cast<ServiceBot *>(target)) bi->OnKill(); else target->Quit(reason); @@ -106,12 +106,12 @@ static void CollideKill(User *target, const Anope::string &reason) static void Collide(User *u, const Anope::string &id, const Anope::string &type) { // Kill incoming user - IRCD->SendKill(Me, id, type); + IRCD->Send<messages::Kill>(Me, id, Me->GetName() + " (" + type + ")"); // Quit colliding user CollideKill(u, type); } -User* User::OnIntroduce(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *nc) +User* User::OnIntroduce(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickServ::Account *nc) { // How IRCds handle collisions varies a lot, for safety well just always kill both sides // With properly set qlines, this can almost never happen anyway @@ -141,9 +141,9 @@ void User::ChangeNick(const Anope::string &newnick, time_t ts) /* Sanity check to make sure we don't segfault */ if (newnick.empty()) throw CoreException("User::ChangeNick() got a bad argument"); - + this->super_admin = false; - Log(this, "nick") << "(" << this->realname << ") changed nick to " << newnick; + logger.Category("nick").Log(_("{0} ({1}) changed nick to {2}"), this->GetMask(), this->realname, newnick); Anope::string old = this->nick; this->timestamp = ts; @@ -152,10 +152,10 @@ void User::ChangeNick(const Anope::string &newnick, time_t ts) this->nick = newnick; else { - NickAlias *old_na = NickAlias::Find(this->nick); + NickServ::Nick *old_na = NickServ::FindNick(this->nick); if (old_na && (this->IsIdentified(true) || this->IsRecognized())) - old_na->last_seen = Anope::CurTime; - + old_na->SetLastSeen(Anope::CurTime); + UserListByNick.erase(this->nick); this->nick = newnick; @@ -170,18 +170,23 @@ void User::ChangeNick(const Anope::string &newnick, time_t ts) other = this; on_access = false; - NickAlias *na = NickAlias::Find(this->nick); - if (na) - on_access = na->nc->IsOnAccess(this); - - if (na && na->nc == this->Account()) + if (NickServ::service) { - na->last_seen = Anope::CurTime; - this->UpdateHost(); + NickServ::Nick *na = NickServ::service->FindNick(this->nick); + if (na) + { + on_access = na->GetAccount()->IsOnAccess(this); + + if (na->GetAccount() == this->Account()) + { + na->SetLastSeen(Anope::CurTime); + this->UpdateHost(); + } + } } } - FOREACH_MOD(OnUserNickChange, (this, old)); + EventManager::Get()->Dispatch(&Event::UserNickChange::OnUserNickChange, this, old); } void User::SetDisplayedHost(const Anope::string &shost) @@ -191,9 +196,9 @@ void User::SetDisplayedHost(const Anope::string &shost) this->vhost = shost; - Log(this, "host") << "changed vhost to " << shost; + logger.Category("host").Log(_("{0} changed vhost to {1}"), this->GetMask(), shost); - FOREACH_MOD(OnSetDisplayedHost, (this)); + EventManager::Get()->Dispatch(&Event::SetDisplayedHost::OnSetDisplayedHost, this); this->UpdateHost(); } @@ -215,7 +220,7 @@ void User::SetCloakedHost(const Anope::string &newhost) chost = newhost; - Log(this, "host") << "changed cloaked host to " << newhost; + logger.Category("host").Log(_("{0} changed cloaked host to {1}"), this->GetMask(), newhost); this->UpdateHost(); } @@ -237,7 +242,7 @@ void User::SetVIdent(const Anope::string &sident) { this->vident = sident; - Log(this, "ident") << "changed vident to " << sident; + logger.Category("ident").Log(_("{0} changed vident to {1}"), this->GetMask(), sident); this->UpdateHost(); } @@ -254,7 +259,7 @@ void User::SetIdent(const Anope::string &sident) { this->ident = sident; - Log(this, "ident") << "changed real ident to " << sident; + logger.Category("ident").Log(_("{0} changed real ident to {1}"), this->GetMask(), sident); this->UpdateHost(); } @@ -280,26 +285,26 @@ void User::SetRealname(const Anope::string &srealname) throw CoreException("realname empty in SetRealname"); this->realname = srealname; - NickAlias *na = NickAlias::Find(this->nick); + + //XXX event + NickServ::Nick *na = NickServ::FindNick(this->nick); if (na && (this->IsIdentified(true) || this->IsRecognized())) - na->last_realname = srealname; + na->SetLastRealname(srealname); - Log(this, "realname") << "changed realname to " << srealname; + logger.Category("realname").Log(_("{0} changed realname to {1}"), this->GetMask(), srealname); } User::~User() { - UnsetExtensibles(); - if (this->server != NULL) { if (this->server->IsSynced()) - Log(this, "disconnect") << "(" << this->realname << ") disconnected from the network (" << this->server->GetName() << ")"; + logger.Category("disconnect").Log(_("{0} ({1}) disconnected from the network ({2})"), this->GetMask(), this->realname, this->server->GetName()); --this->server->users; } - FOREACH_MOD(OnPreUserLogoff, (this)); + EventManager::Get()->Dispatch(&Event::PreUserLogoff::OnPreUserLogoff, this); ModeManager::StackerDel(this); this->Logout(); @@ -314,25 +319,10 @@ User::~User() if (!this->uid.empty()) UserListByUID.erase(this->uid); - FOREACH_MOD(OnPostUserLogoff, (this)); -} - -void User::SendMessage(BotInfo *source, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - - const char *translated_message = Language::Translate(this, fmt); - - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, translated_message, args); - - this->SendMessage(source, Anope::string(buf)); - - va_end(args); + EventManager::Get()->Dispatch(&Event::PostUserLogoff::OnPostUserLogoff, this); } -void User::SendMessage(BotInfo *source, const Anope::string &msg) +void User::SendMessage(const MessageSource &source, const Anope::string &msg) { const char *translated_message = Language::Translate(this, msg.c_str()); @@ -341,54 +331,85 @@ void User::SendMessage(BotInfo *source, const Anope::string &msg) * - The user is not registered and NSDefMsg is enabled * - The user is registered and has set /ns set msg on */ - bool send_privmsg = Config->UsePrivmsg && ((!this->nc && Config->DefPrivmsg) || (this->nc && this->nc->HasExt("MSG"))); + bool send_privmsg = Config->UsePrivmsg && ((!this->nc && Config->DefPrivmsg) || (this->nc && this->nc->IsMsg())); sepstream sep(translated_message, '\n', true); for (Anope::string tok; sep.GetToken(tok);) { - if (send_privmsg) - IRCD->SendPrivmsg(source, this->GetUID(), "%s", tok.c_str()); - else - IRCD->SendNotice(source, this->GetUID(), "%s", tok.c_str()); + if (tok.empty()) + tok = " "; + spacesepstream ssep(tok, true); + Anope::string buf; + for (Anope::string word; ssep.GetToken(word);) + { + Anope::string add; + if (word.empty()) // was two spaces + word = " "; + + if (buf.empty() || buf[buf.length() - 1] == ' ') + add = word; + else + add = " " + word; + + if (buf.length() + add.length() > Config->LineWrap) + { + if (send_privmsg) + IRCD->SendPrivmsg(source, this->GetUID(), buf); + else + IRCD->SendNotice(source, this->GetUID(), buf); + buf.clear(); + + add = word; + } + + buf.append(add); + } + + if (!buf.empty()) + { + if (send_privmsg) + IRCD->SendPrivmsg(source, this->GetUID(), buf); + else + IRCD->SendNotice(source, this->GetUID(), buf); + } } } -void User::Identify(NickAlias *na) +void User::Identify(NickServ::Nick *na) { - if (this->nick.equals_ci(na->nick)) + if (this->nick.equals_ci(na->GetNick())) { - na->last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost(); - na->last_realhost = this->GetIdent() + "@" + this->host; - na->last_realname = this->realname; - na->last_seen = Anope::CurTime; + na->SetLastUsermask(this->GetIdent() + "@" + this->GetDisplayedHost()); + na->SetLastRealhost(this->GetIdent() + "@" + this->host); + na->SetLastRealname(this->realname); + na->SetLastSeen(Anope::CurTime); } - IRCD->SendLogin(this, na); + IRCD->Send<messages::Login>(this, na); - this->Login(na->nc); + this->Login(na->GetAccount()); - FOREACH_MOD(OnNickIdentify, (this)); + EventManager::Get()->Dispatch(&Event::NickIdentify::OnNickIdentify, this); - if (this->IsServicesOper()) + Oper *oper = this->nc->GetOper(); + if (oper != nullptr && oper->GetType() != nullptr) { - if (!this->nc->o->ot->modes.empty()) + Anope::string m = oper->GetType()->modes; + if (!m.empty()) { - this->SetModes(NULL, "%s", this->nc->o->ot->modes.c_str()); - this->SendMessage(NULL, "Changing your usermodes to \002%s\002", this->nc->o->ot->modes.c_str()); - UserMode *um = ModeManager::FindUserModeByName("OPER"); - if (um && !this->HasMode("OPER") && this->nc->o->ot->modes.find(um->mchar) != Anope::string::npos) - IRCD->SendOper(this); + this->SetModes(NULL, "%s", m.c_str()); + this->SendMessage(Me, "Changing your usermodes to \002{0}\002", m.c_str()); } - if (IRCD->CanSetVHost && !this->nc->o->vhost.empty()) + if (IRCD->CanSetVHost && !oper->GetVhost().empty()) { - this->SendMessage(NULL, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str()); - this->SetDisplayedHost(this->nc->o->vhost); - IRCD->SendVhost(this, "", this->nc->o->vhost); + this->SendMessage(Me, "Changing your vhost to \002{0}\002", oper->GetVhost()); + this->SetDisplayedHost(oper->GetVhost()); + IRCD->Send<messages::VhostSet>(this, "", oper->GetVhost()); } } } -void User::Login(NickCore *core) +void User::Login(NickServ::Account *core) { if (!core || core == this->nc) return; @@ -400,26 +421,26 @@ void User::Login(NickCore *core) this->UpdateHost(); if (this->server->IsSynced()) - Log(this, "account") << "is now identified as " << this->nc->display; - - FOREACH_MOD(OnUserLogin, (this)); + logger.Category("account").Log(_("{0} is now identified as {1}"), this->GetMask(), this->nc->GetDisplay()); + + EventManager::Get()->Dispatch(&Event::UserLogin::OnUserLogin, this); } void User::Logout() { if (!this->nc) return; - - Log(this, "account") << "is no longer identified as " << this->nc->display; - std::list<User *>::iterator it = std::find(this->nc->users.begin(), this->nc->users.end(), this); + logger.Category("account").Log(_("{0} is no longer identified as {1}"), this->GetMask(), this->nc->GetDisplay()); + + auto it = std::find(this->nc->users.begin(), this->nc->users.end(), this); if (it != this->nc->users.end()) this->nc->users.erase(it); this->nc = NULL; } -NickCore *User::Account() const +NickServ::Account *User::Account() const { return this->nc; } @@ -428,8 +449,8 @@ bool User::IsIdentified(bool check_nick) const { if (check_nick && this->nc) { - NickAlias *na = NickAlias::Find(this->nick); - return na && *na->nc == *this->nc; + NickServ::Nick *na = NickServ::FindNick(nick); + return na && na->GetAccount() == *this->nc; } return this->nc ? true : false; @@ -439,9 +460,9 @@ bool User::IsRecognized(bool check_secure) const { if (check_secure && on_access) { - const NickAlias *na = NickAlias::Find(this->nick); + NickServ::Nick *na = NickServ::FindNick(nick); - if (!na || na->nc->HasExt("NS_SECURE")) + if (!na || na->GetAccount()->IsSecure()) return false; } @@ -450,27 +471,38 @@ bool User::IsRecognized(bool check_secure) const bool User::IsServicesOper() { - if (!this->nc || !this->nc->IsServicesOper()) + if (!this->nc || !this->nc->GetOper()) // No opertype. return false; - else if (this->nc->o->require_oper && !this->HasMode("OPER")) + + Oper *oper = this->nc->GetOper(); + + if (oper->GetType() == nullptr) + return false; + + if (oper->GetRequireOper() && !this->HasMode("OPER")) return false; - else if (!this->nc->o->certfp.empty() && this->fingerprint != this->nc->o->certfp) + + if (!oper->GetCertFP().empty() && this->fingerprint != oper->GetCertFP()) // Certfp mismatch return false; - else if (!this->nc->o->hosts.empty()) + + if (!oper->GetHost().empty()) { + std::vector<Anope::string> hosts; + spacesepstream(oper->GetHost()).GetTokens(hosts); + bool match = false; Anope::string match_host = this->GetIdent() + "@" + this->host; - for (unsigned i = 0; i < this->nc->o->hosts.size(); ++i) - if (Anope::Match(match_host, this->nc->o->hosts[i])) + for (Anope::string h : hosts) + if (Anope::Match(match_host, h)) match = true; if (match == false) return false; } EventReturn MOD_RESULT; - FOREACH_RESULT(IsServicesOper, MOD_RESULT, (this)); + MOD_RESULT = EventManager::Get()->Dispatch(&Event::IsServicesOperEvent::IsServicesOper, this); if (MOD_RESULT == EVENT_STOP) return false; @@ -480,14 +512,14 @@ bool User::IsServicesOper() bool User::HasCommand(const Anope::string &command) { if (this->IsServicesOper()) - return this->nc->o->ot->HasCommand(command); + return this->nc->GetOper()->HasCommand(command); return false; } bool User::HasPriv(const Anope::string &priv) { if (this->IsServicesOper()) - return this->nc->o->ot->HasPriv(priv); + return this->nc->GetOper()->HasPriv(priv); return false; } @@ -496,19 +528,20 @@ void User::UpdateHost() if (this->host.empty()) return; - NickAlias *na = NickAlias::Find(this->nick); + //XXX event + NickServ::Nick *na = NickServ::FindNick(this->nick); on_access = false; if (na) - on_access = na->nc->IsOnAccess(this); + on_access = na->GetAccount()->IsOnAccess(this); if (na && (this->IsIdentified(true) || this->IsRecognized())) { Anope::string last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost(); Anope::string last_realhost = this->GetIdent() + "@" + this->host; - na->last_usermask = last_usermask; - na->last_realhost = last_realhost; + na->SetLastUsermask(last_usermask); + na->SetLastRealhost(last_realhost); // This is called on signon, and if users are introduced with an account it won't update - na->last_realname = this->realname; + na->SetLastRealname(this->realname); } } @@ -530,19 +563,18 @@ void User::SetModeInternal(const MessageSource &source, UserMode *um, const Anop if (this->IsServicesOper()) { - if (!this->nc->o->ot->modes.empty()) + Oper *oper = this->nc->GetOper(); + Anope::string m = oper->GetType()->modes; + if (!m.empty()) { - this->SetModes(NULL, "%s", this->nc->o->ot->modes.c_str()); - this->SendMessage(NULL, "Changing your usermodes to \002%s\002", this->nc->o->ot->modes.c_str()); - UserMode *oper = ModeManager::FindUserModeByName("OPER"); - if (oper && !this->HasMode("OPER") && this->nc->o->ot->modes.find(oper->mchar) != Anope::string::npos) - IRCD->SendOper(this); + this->SetModes(NULL, "%s", m.c_str()); + this->SendMessage(Me, "Changing your usermodes to \002{0}\002", m); } - if (IRCD->CanSetVHost && !this->nc->o->vhost.empty()) + if (IRCD->CanSetVHost && !oper->GetVhost().empty()) { - this->SendMessage(NULL, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str()); - this->SetDisplayedHost(this->nc->o->vhost); - IRCD->SendVhost(this, "", this->nc->o->vhost); + this->SendMessage(Me, "Changing your vhost to \002{0}\002", oper->GetVhost()); + this->SetDisplayedHost(oper->GetVhost()); + IRCD->Send<messages::VhostSet>(this, "", oper->GetVhost()); } } } @@ -550,7 +582,7 @@ void User::SetModeInternal(const MessageSource &source, UserMode *um, const Anop if (um->name == "CLOAK" || um->name == "VHOST") this->UpdateHost(); - FOREACH_MOD(OnUserModeSet, (source, this, um->name)); + EventManager::Get()->Dispatch(&Event::UserModeSet::OnUserModeSet, source, this, um->name); } void User::RemoveModeInternal(const MessageSource &source, UserMode *um) @@ -569,10 +601,10 @@ void User::RemoveModeInternal(const MessageSource &source, UserMode *um) this->UpdateHost(); } - FOREACH_MOD(OnUserModeUnset, (source, this, um->name)); + EventManager::Get()->Dispatch(&Event::UserModeUnset::OnUserModeUnset, source, this, um->name); } -void User::SetMode(BotInfo *bi, UserMode *um, const Anope::string ¶m) +void User::SetMode(ServiceBot *bi, UserMode *um, const Anope::string ¶m) { if (!um || HasMode(um->name)) return; @@ -581,12 +613,12 @@ void User::SetMode(BotInfo *bi, UserMode *um, const Anope::string ¶m) SetModeInternal(bi, um, param); } -void User::SetMode(BotInfo *bi, const Anope::string &uname, const Anope::string ¶m) +void User::SetMode(ServiceBot *bi, const Anope::string &uname, const Anope::string ¶m) { SetMode(bi, ModeManager::FindUserModeByName(uname), param); } -void User::RemoveMode(BotInfo *bi, UserMode *um, const Anope::string ¶m) +void User::RemoveMode(ServiceBot *bi, UserMode *um, const Anope::string ¶m) { if (!um || !HasMode(um->name)) return; @@ -595,12 +627,12 @@ void User::RemoveMode(BotInfo *bi, UserMode *um, const Anope::string ¶m) RemoveModeInternal(bi, um); } -void User::RemoveMode(BotInfo *bi, const Anope::string &name, const Anope::string ¶m) +void User::RemoveMode(ServiceBot *bi, const Anope::string &name, const Anope::string ¶m) { RemoveMode(bi, ModeManager::FindUserModeByName(name), param); } -void User::SetModes(BotInfo *bi, const char *umodes, ...) +void User::SetModes(ServiceBot *bi, const char *umodes, ...) { char buf[BUFSIZE] = ""; va_list args; @@ -655,7 +687,7 @@ void User::SetModesInternal(const MessageSource &source, const char *umodes, ... va_end(args); if (this->server && this->server->IsSynced() && Anope::string(buf) != "+") - Log(this, "mode") << "changes modes to " << buf; + logger.Category("mode").Log(_("{0} changes mode to {1}"), this->GetMask(), buf); spacesepstream sep(buf); sep.GetToken(modebuf); @@ -732,18 +764,18 @@ void User::Kill(const MessageSource &source, const Anope::string &reason) { Anope::string real_reason = source.GetName() + " (" + reason + ")"; - IRCD->SendSVSKill(source, this, "%s", real_reason.c_str()); + IRCD->SendKill(source, this, real_reason); } void User::KillInternal(const MessageSource &source, const Anope::string &reason) { if (this->quit) { - Log(LOG_DEBUG) << "Duplicate quit for " << this->nick; + Anope::Logger.Debug("Duplicate quit for {0}", this->nick); return; } - Log(this, "killed") << "was killed by " << source.GetName() << " (Reason: " << reason << ")"; + logger.Category("killed").Log(_("{0} was killed by {1} (Reason: {2})"), this->GetMask(), source.GetName(), reason); this->Quit(reason); } @@ -752,11 +784,11 @@ void User::Quit(const Anope::string &reason) { if (this->quit) { - Log(LOG_DEBUG) << "Duplicate quit for " << this->nick; + Anope::Logger.Debug("Duplicate quit for {0}", this->nick); return; } - FOREACH_MOD(OnUserQuit, (this, reason)); + EventManager::Get()->Dispatch(&Event::UserQuit::OnUserQuit, this, reason); this->quit = true; quitting_users.push_back(this); @@ -767,7 +799,7 @@ bool User::Quitting() const return this->quit; } -Anope::string User::Mask() const +Anope::string User::WildMask() const { Anope::string mask; const Anope::string &mident = this->GetIdent(); @@ -781,7 +813,7 @@ Anope::string User::Mask() const sockaddrs addr(mhost); if (addr.valid() && addr.sa.sa_family == AF_INET) { - size_t dot = mhost.find('.'); + size_t dot = mhost.rfind('.'); mask += mhost.substr(0, dot) + (dot == Anope::string::npos ? "" : ".*"); } else @@ -818,7 +850,7 @@ User* User::Find(const Anope::string &name, bool nick_only) { if (!nick_only && IRCD && IRCD->RequiresID) { - user_map::iterator it = UserListByUID.find(name); + uid_map::iterator it = UserListByUID.find(name); if (it != UserListByUID.end()) return it->second; diff --git a/src/version.sh b/src/version.sh index cc83d73e7..db1881df3 100644 --- a/src/version.sh +++ b/src/version.sh @@ -1,7 +1,7 @@ #!/bin/sh VERSION_MAJOR=2 -VERSION_MINOR=0 -VERSION_PATCH=5 -VERSION_EXTRA="-git" +VERSION_MINOR=1 +VERSION_PATCH=0 +VERSION_EXTRA="-exploding-tacos" diff --git a/src/win32/Config.cs b/src/win32/Config.cs deleted file mode 100644 index d7c9661ec..000000000 --- a/src/win32/Config.cs +++ /dev/null @@ -1,363 +0,0 @@ -/*
- * Config.cs - Windows Configuration
- *
- * (C) 2003-2016 Anope Team
- * Contact us at team@anope.org
- *
- * This program is free but copyrighted software; see the file COPYING for
- * details.
- *
- * Based on the original code of Epona by Lara.
- * Based on the original code of Services by Andy Church.
- *
- * Written by Scott <stealtharcher.scott@gmail.com>
- * Written by Adam <Adam@anope.org>
- * Cleaned up by Naram Qashat <cyberbotx@anope.org>
- *
- * Compile with: csc /out:../../Config.exe /win32icon:anope-icon.ico Config.cs
- */
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Reflection;
-
-namespace Config
-{
- class Config
- {
- static string ExecutablePath, InstallDirectory, ExtraIncludeDirs, ExtraLibDirs, ExtraArguments;
- static bool UseNMake = true, BuildDebug = false;
-
- static bool CheckResponse(string InstallerResponse)
- {
- if (string.Compare(InstallerResponse, "yes", true) == 0 || string.Compare(InstallerResponse, "y", true) == 0)
- return true;
- return false;
- }
-
- static bool LoadCache()
- {
- try
- {
- string[] cache = File.ReadAllLines(string.Format(@"{0}\config.cache", ExecutablePath));
- if (cache.Length > 0)
- Console.WriteLine("Using defaults from config.cache");
- foreach (string line in cache)
- {
- int e = line.IndexOf('=');
- string name = line.Substring(0, e);
- string value = line.Substring(e + 1);
-
- if (name == "INSTDIR")
- InstallDirectory = value;
- else if (name == "DEBUG")
- BuildDebug = CheckResponse(value);
- else if (name == "USENMAKE")
- UseNMake = CheckResponse(value);
- else if (name == "EXTRAINCLUDE")
- ExtraIncludeDirs = value;
- else if (name == "EXTRALIBS")
- ExtraLibDirs = value;
- else if (name == "EXTRAARGS")
- ExtraArguments = value;
- }
-
- return true;
- }
- catch (Exception)
- {
- }
-
- return false;
- }
-
- static void SaveCache()
- {
- using (TextWriter tw = new StreamWriter(string.Format(@"{0}\config.cache", ExecutablePath)))
- {
- tw.WriteLine("INSTDIR={0}", InstallDirectory);
- tw.WriteLine("DEBUG={0}", BuildDebug ? "yes" : "no");
- tw.WriteLine("USENMAKE={0}", UseNMake ? "yes" : "no");
- tw.WriteLine("EXTRAINCLUDE={0}", ExtraIncludeDirs);
- tw.WriteLine("EXTRALIBS={0}", ExtraLibDirs);
- tw.WriteLine("EXTRAARGS={0}", ExtraArguments);
- }
- }
-
- static string HandleCache(int i)
- {
- switch (i)
- {
- case 0:
- Console.Write("[{0}] ", InstallDirectory);
- return InstallDirectory;
- case 1:
- Console.Write("[{0}] ", UseNMake ? "yes" : "no");
- return UseNMake ? "yes" : "no";
- case 2:
- Console.Write("[{0}] ", BuildDebug ? "yes" : "no");
- return BuildDebug ? "yes" : "no";
- case 3:
- Console.Write("[{0}] ", ExtraIncludeDirs);
- return ExtraIncludeDirs;
- case 4:
- Console.Write("[{0}] ", ExtraLibDirs);
- return ExtraLibDirs;
- case 5:
- Console.Write("[{0}] ", ExtraArguments);
- return ExtraArguments;
- default:
- break;
- }
-
- return null;
- }
-
- static string FindAnopeVersion()
- {
- if (!File.Exists(string.Format(@"{0}\src\version.sh", ExecutablePath)))
- return "Unknown";
-
- Dictionary<string, string> versions = new Dictionary<string, string>();
- string[] versionfile = File.ReadAllLines(string.Format(@"{0}\src\version.sh", ExecutablePath));
- foreach (string line in versionfile)
- if (line.StartsWith("VERSION_"))
- {
- string key = line.Split('_')[1].Split('=')[0];
- if (!versions.ContainsKey(key))
- versions.Add(key, line.Split('=')[1].Replace("\"", "").Replace("\'", ""));
- }
-
- try
- {
- if (versions.ContainsKey("BUILD"))
- return string.Format("{0}.{1}.{2}.{3}{4}", versions["MAJOR"], versions["MINOR"], versions["PATCH"], versions["BUILD"], versions["EXTRA"]);
- else
- return string.Format("{0}.{1}.{2}{3}", versions["MAJOR"], versions["MINOR"], versions["PATCH"], versions["EXTRA"]);
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- return "Unknown";
- }
- }
-
- static void RunCMake(string cMake)
- {
- Console.WriteLine("cmake {0}", cMake);
- try
- {
- ProcessStartInfo processStartInfo = new ProcessStartInfo("cmake")
- {
- RedirectStandardError = true,
- RedirectStandardOutput = true,
- UseShellExecute = false,
- Arguments = cMake
- };
- Process pCMake = Process.Start(processStartInfo);
- StreamReader stdout = pCMake.StandardOutput, stderr = pCMake.StandardError;
- string stdoutr, stderrr;
- List<string> errors = new List<string>();
- while (!pCMake.HasExited)
- {
- if ((stdoutr = stdout.ReadLine()) != null)
- Console.WriteLine(stdoutr);
- if ((stderrr = stderr.ReadLine()) != null)
- errors.Add(stderrr);
- }
- foreach (string error in errors)
- Console.WriteLine(error);
- Console.WriteLine();
- if (pCMake.ExitCode == 0)
- {
- if (UseNMake)
- Console.WriteLine("To compile Anope, run 'nmake'. To install, run 'nmake install'");
- else
- Console.WriteLine("To compile Anope, open Anope.sln and build the solution. To install, do a build on the INSTALL project");
- }
- else
- Console.WriteLine("There was an error attempting to run CMake! Check the above error message, and contact the Anope team if you are unsure how to proceed.");
- }
- catch (Exception e)
- {
- Console.WriteLine();
- Console.WriteLine(DateTime.UtcNow + " UTC: " + e.Message);
- Console.WriteLine("There was an error attempting to run CMake! Check the above error message, and contact the Anope team if you are unsure how to proceed.");
- }
- }
-
- static int Main(string[] args)
- {
- bool IgnoreCache = false, NoIntro = false, DoQuick = false;
-
- if (args.Length > 0)
- {
- if (args[0] == "--help")
- {
- Console.WriteLine("Config utility for Anope");
- Console.WriteLine("------------------------");
- Console.WriteLine("Syntax: .\\Config.exe [options]");
- Console.WriteLine("-nocache Ignore settings saved in config.cache");
- Console.WriteLine("-nointro Skip intro (disclaimer, etc)");
- Console.WriteLine("-quick or -q Skip questions, go straight to cmake");
- return 0;
- }
- else if (args[0] == "-nocache")
- IgnoreCache = true;
- else if (args[0] == "-nointro")
- NoIntro = true;
- else if (args[0] == "-quick" || args[0] == "-q")
- DoQuick = true;
- }
-
- ExecutablePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
-
- string AnopeVersion = FindAnopeVersion();
-
- if (!NoIntro && File.Exists(string.Format(@"{0}\.BANNER", ExecutablePath)))
- Console.WriteLine(File.ReadAllText(string.Format(@"{0}\.BANNER", ExecutablePath)).Replace("CURVER", AnopeVersion).Replace("For more options type SOURCE_DIR/Config --help", ""));
-
- Console.WriteLine("Press Enter to begin");
- Console.WriteLine();
- Console.ReadKey();
-
- bool UseCache = false;
-
- if (DoQuick || !IgnoreCache)
- {
- UseCache = LoadCache();
- if (DoQuick && !UseCache)
- {
- Console.WriteLine("Can't find cache file (config.cache), aborting...");
- return 1;
- }
- }
-
- if (!DoQuick)
- {
- List<string> InstallerQuestions = new List<string>()
- {
- "Where do you want Anope to be installed?",
- "Would you like to build using NMake instead of using Visual Studio?\r\nNOTE: If you decide to use NMake, you must be in an environment where\r\nNMake can function, such as the Visual Studio command line. If you say\r\nyes to this while not in an environment that can run NMake, it can\r\ncause the CMake configuration to enter an endless loop. [y/n]",
- "Would you like to build a debug version of Anope? [y/n]",
- "Are there any extra include directories you wish to use?\nYou may only need to do this if CMake is unable to locate missing dependencies without hints.\nSeparate directories with semicolons and use slashes (aka /) instead of backslashes (aka \\).\nIf you need no extra include directories, enter NONE in all caps.",
- "Are there any extra library directories you wish to use?\nYou may only need to do this if CMake is unable to locate missing dependencies without hints.\nSeparate directories with semicolons and use slashes (aka /) instead of backslashes (aka \\).\nIf you need no extra library directories, enter NONE in all caps.",
- "Are there any extra arguments you wish to pass to CMake?\nIf you need no extra arguments to CMake, enter NONE in all caps."
- };
-
- for (int i = 0; i < InstallerQuestions.Count; ++i)
- {
- Console.WriteLine(InstallerQuestions[i]);
- string CacheResponse = null;
- if (UseCache)
- CacheResponse = HandleCache(i);
- string InstallerResponse = Console.ReadLine();
- Console.WriteLine();
-
- if (!string.IsNullOrWhiteSpace(CacheResponse) && string.IsNullOrWhiteSpace(InstallerResponse))
- InstallerResponse = CacheResponse;
-
- // Question 4+ are optional
- if (i < 3 && string.IsNullOrWhiteSpace(InstallerResponse))
- {
- Console.WriteLine("Invalid option");
- --i;
- continue;
- }
-
- switch (i)
- {
- case 0:
- if (!Directory.Exists(InstallerResponse))
- {
- Console.WriteLine("Directory does not exist! Creating directory.");
- Console.WriteLine();
- try
- {
- Directory.CreateDirectory(InstallerResponse);
- InstallDirectory = InstallerResponse;
- }
- catch (Exception e)
- {
- Console.WriteLine("Unable to create directory: " + e.Message);
- --i;
- }
- }
- else if (File.Exists(InstallerResponse + @"\include\services.h"))
- {
- Console.WriteLine("You cannot use the Anope source directory as the target directory!");
- --i;
- }
- else
- InstallDirectory = InstallerResponse;
- break;
- case 1:
- UseNMake = CheckResponse(InstallerResponse);
- if (UseNMake)
- ++i;
- break;
- case 2:
- BuildDebug = CheckResponse(InstallerResponse);
- break;
- case 3:
- if (InstallerResponse == "NONE")
- ExtraIncludeDirs = null;
- else
- ExtraIncludeDirs = InstallerResponse;
- break;
- case 4:
- if (InstallerResponse == "NONE")
- ExtraLibDirs = null;
- else
- ExtraLibDirs = InstallerResponse;
- break;
- case 5:
- if (InstallerResponse == "NONE")
- ExtraArguments = null;
- else
- ExtraArguments = InstallerResponse;
- break;
- default:
- break;
- }
- }
- }
-
- Console.WriteLine("Anope will be compiled with the following options:");
- Console.WriteLine("Install directory: {0}", InstallDirectory);
- Console.WriteLine("Use NMake: {0}", UseNMake ? "Yes" : "No");
- Console.WriteLine("Build debug: {0}", BuildDebug ? "Yes" : "No");
- Console.WriteLine("Anope Version: {0}", AnopeVersion);
- Console.WriteLine("Extra Include Directories: {0}", ExtraIncludeDirs);
- Console.WriteLine("Extra Library Directories: {0}", ExtraLibDirs);
- Console.WriteLine("Extra Arguments: {0}", ExtraArguments);
- Console.WriteLine("Press Enter to continue...");
- Console.ReadKey();
-
- SaveCache();
-
- if (!string.IsNullOrWhiteSpace(ExtraIncludeDirs))
- ExtraIncludeDirs = string.Format("-DEXTRA_INCLUDE:STRING={0} ", ExtraIncludeDirs);
- else
- ExtraIncludeDirs = "";
- if (!string.IsNullOrWhiteSpace(ExtraLibDirs))
- ExtraLibDirs = string.Format("-DEXTRA_LIBS:STRING={0} ", ExtraLibDirs);
- else
- ExtraLibDirs = "";
- if (!string.IsNullOrWhiteSpace(ExtraArguments))
- ExtraArguments += " ";
- else
- ExtraArguments = "";
-
- InstallDirectory = "-DINSTDIR:STRING=\"" + InstallDirectory.Replace('\\', '/') + "\" ";
- string NMake = UseNMake ? "-G\"NMake Makefiles\" " : "";
- string Debug = BuildDebug ? "-DCMAKE_BUILD_TYPE:STRING=DEBUG " : "-DCMAKE_BUILD_TYPE:STRING=RELEASE ";
- string cMake = InstallDirectory + NMake + Debug + ExtraIncludeDirs + ExtraLibDirs + ExtraArguments + "\"" + ExecutablePath.Replace('\\', '/') + "\"";
- RunCMake(cMake);
-
- return 0;
- }
- }
-}
diff --git a/src/win32/anope_windows.h b/src/win32/anope_windows.h index 14c83b4d4..061934752 100644 --- a/src/win32/anope_windows.h +++ b/src/win32/anope_windows.h @@ -1,7 +1,7 @@ /* POSIX emulation layer for Windows. * - * (C) 2008-2011 Robin Burchell <w00t@inspircd.org> - * (C) 2008-2016 Anope Team <team@anope.org> + * Copyright (C) 2008-2011 Robin Burchell <w00t@inspircd.org> + * Copyright (C) 2008-2014 Anope Team <info@anope.org> * * Please read COPYING and README for further details. * @@ -42,6 +42,13 @@ /* VS2008 hates having this define before its own */ #define vsnprintf _vsnprintf +#define popen _popen +#define pclose _pclose + +#define PATH_MAX MAX_PATH + +#define sleep(x) Sleep(x * 1000) + #define anope_close windows_close #define stat _stat @@ -56,7 +63,6 @@ #include "dir/dir.h" #include "dl/dl.h" #include "pipe/pipe.h" -#include "pthread/pthread.h" #include "sigaction/sigaction.h" typedef int ssize_t; diff --git a/src/win32/dir/dir.cpp b/src/win32/dir/dir.cpp index d660c9694..16809bd9c 100644 --- a/src/win32/dir/dir.cpp +++ b/src/win32/dir/dir.cpp @@ -1,14 +1,13 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. */ #include "dir.h" #include <stdio.h> - + DIR *opendir(const char *path) { char real_path[MAX_PATH]; diff --git a/src/win32/dir/dir.h b/src/win32/dir/dir.h index a6c9a055f..4d1433658 100644 --- a/src/win32/dir/dir.h +++ b/src/win32/dir/dir.h @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. */ @@ -21,7 +20,7 @@ struct DIR WIN32_FIND_DATA data; bool read_first; }; - + DIR *opendir(const char *); dirent *readdir(DIR *); int closedir(DIR *); diff --git a/src/win32/dl/dl.cpp b/src/win32/dl/dl.cpp index bdcbe636c..5b19d7441 100644 --- a/src/win32/dl/dl.cpp +++ b/src/win32/dl/dl.cpp @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. */ diff --git a/src/win32/dl/dl.h b/src/win32/dl/dl.h index 81c115fef..02a2f1d3d 100644 --- a/src/win32/dl/dl.h +++ b/src/win32/dl/dl.h @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. */ diff --git a/src/win32/pipe/pipe.cpp b/src/win32/pipe/pipe.cpp index 70690ab2b..676909b9a 100644 --- a/src/win32/pipe/pipe.cpp +++ b/src/win32/pipe/pipe.cpp @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. */ @@ -56,6 +55,7 @@ int pipe(int fds[2]) fds[0] = cfd; fds[1] = afd; - + return 0; } + diff --git a/src/win32/pipe/pipe.h b/src/win32/pipe/pipe.h index d77d0706b..8e67bafc7 100644 --- a/src/win32/pipe/pipe.h +++ b/src/win32/pipe/pipe.h @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. */ diff --git a/src/win32/pthread/pthread.cpp b/src/win32/pthread/pthread.cpp deleted file mode 100644 index 36b8cd54d..000000000 --- a/src/win32/pthread/pthread.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* POSIX emulation layer for Windows. - * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - */ - -#include "pthread.h" - -struct ThreadInfo -{ - void *(*entry)(void *); - void *param; -}; - -static DWORD WINAPI entry_point(void *parameter) -{ - ThreadInfo *ti = static_cast<ThreadInfo *>(parameter); - ti->entry(ti->param); - delete ti; - return 0; -} - -int pthread_attr_init(pthread_attr_t *) -{ - /* No need for this */ - return 0; -} - -int pthread_attr_setdetachstate(pthread_attr_t *, int) -{ - /* No need for this */ - return 0; -} - -int pthread_create(pthread_t *thread, const pthread_attr_t *, void *(*entry)(void *), void *param) -{ - ThreadInfo *ti = new ThreadInfo; - ti->entry = entry; - ti->param = param; - - *thread = CreateThread(NULL, 0, entry_point, ti, 0, NULL); - if (!*thread) - { - delete ti; - return -1; - } - - return 0; -} - -int pthread_join(pthread_t thread, void **) -{ - if (WaitForSingleObject(thread, INFINITE) == WAIT_FAILED) - return -1; - CloseHandle(thread); - return 0; -} - -void pthread_exit(int i) -{ - ExitThread(i); -} - -int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *) -{ - InitializeCriticalSection(mutex); - return 0; -} - -int pthread_mutex_destroy(pthread_mutex_t *mutex) -{ - DeleteCriticalSection(mutex); - return 0; -} - -int pthread_mutex_lock(pthread_mutex_t *mutex) -{ - EnterCriticalSection(mutex); - return 0; -} - -int pthread_mutex_trylock(pthread_mutex_t *mutex) -{ - return !TryEnterCriticalSection(mutex); -} - -int pthread_mutex_unlock(pthread_mutex_t *mutex) -{ - LeaveCriticalSection(mutex); - return 0; -} - -int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *) -{ - *cond = CreateEvent(NULL, false, false, NULL); - if (*cond == NULL) - return -1; - return 0; -} - -int pthread_cond_destroy(pthread_cond_t *cond) -{ - return !CloseHandle(*cond); -} - -int pthread_cond_signal(pthread_cond_t *cond) -{ - return !PulseEvent(*cond); -} - -int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - LeaveCriticalSection(mutex); - WaitForSingleObject(*cond, INFINITE); - EnterCriticalSection(mutex); - return 0; -} diff --git a/src/win32/pthread/pthread.h b/src/win32/pthread/pthread.h deleted file mode 100644 index 18909a17d..000000000 --- a/src/win32/pthread/pthread.h +++ /dev/null @@ -1,35 +0,0 @@ -/* POSIX emulation layer for Windows. - * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - */ - -#include <Windows.h> - -typedef HANDLE pthread_t; -typedef CRITICAL_SECTION pthread_mutex_t; -typedef HANDLE pthread_cond_t; -typedef int pthread_attr_t; -typedef void pthread_mutexattr_t; -typedef void pthread_condattr_t; - -#define PTHREAD_CREATE_JOINABLE 0 - -extern int pthread_attr_init(pthread_attr_t *); -extern int pthread_attr_setdetachstate(pthread_attr_t *, int); -extern int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); -extern int pthread_join(pthread_t, void **); -extern void pthread_exit(int); - -extern int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); -extern int pthread_mutex_destroy(pthread_mutex_t *); -extern int pthread_mutex_lock(pthread_mutex_t *); -extern int pthread_mutex_trylock(pthread_mutex_t *); -extern int pthread_mutex_unlock(pthread_mutex_t *); - -extern int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); -extern int pthread_cond_destroy(pthread_cond_t *); -extern int pthread_cond_signal(pthread_cond_t *); -extern int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); diff --git a/src/win32/resource.h b/src/win32/resource.h index 0fb755b56..e4fa54b70 100644 --- a/src/win32/resource.h +++ b/src/win32/resource.h @@ -1,11 +1,3 @@ -/* - * - * (C) 2005-2016 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - */ - //{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by Win32GUI.rc @@ -16,7 +8,7 @@ // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 diff --git a/src/win32/sigaction/sigaction.cpp b/src/win32/sigaction/sigaction.cpp index 17faaf2fb..51615cf39 100644 --- a/src/win32/sigaction/sigaction.cpp +++ b/src/win32/sigaction/sigaction.cpp @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. * @@ -9,12 +8,12 @@ * Based on the original code of Services by Andy Church. */ -#include <windows.h> -#include "sigaction.h" -#include <signal.h> + #include <windows.h> + #include "sigaction.h" + #include <signal.h> -int sigaction(int sig, struct sigaction *action, struct sigaction *old) -{ + int sigaction(int sig, struct sigaction *action, struct sigaction *old) + { if (sig == -1) return 0; if (old == NULL) @@ -28,4 +27,4 @@ int sigaction(int sig, struct sigaction *action, struct sigaction *old) return -1; } return 0; -} + } diff --git a/src/win32/sigaction/sigaction.h b/src/win32/sigaction/sigaction.h index c517ba16d..9e74eeffa 100644 --- a/src/win32/sigaction/sigaction.h +++ b/src/win32/sigaction/sigaction.h @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. * @@ -9,20 +8,21 @@ * Based on the original code of Services by Andy Church. */ -#define sigemptyset(x) memset((x), 0, sizeof(*(x))) + #define sigemptyset(x) memset((x), 0, sizeof(*(x))) -#ifndef SIGHUP -# define SIGHUP -1 -#endif -#ifndef SIGPIPE -# define SIGPIPE -1 -#endif + #ifndef SIGHUP + # define SIGHUP -1 + #endif + #ifndef SIGPIPE + # define SIGPIPE -1 + #endif -struct sigaction -{ + struct sigaction + { void (*sa_handler)(int); int sa_flags; int sa_mask; -}; + }; + + extern int sigaction(int, struct sigaction *, struct sigaction *); -extern int sigaction(int, struct sigaction *, struct sigaction *); diff --git a/src/win32/socket.cpp b/src/win32/socket.cpp index 489192679..7f6ef4df1 100644 --- a/src/win32/socket.cpp +++ b/src/win32/socket.cpp @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. */ @@ -86,7 +85,7 @@ int windows_inet_pton(int af, const char *src, void *dst) } return 1; } - + return 0; } diff --git a/src/win32/socket.h b/src/win32/socket.h index a8064589e..d587618a9 100644 --- a/src/win32/socket.h +++ b/src/win32/socket.h @@ -1,7 +1,6 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2014 Anope Team <team@anope.org> * * Please read COPYING and README for further details. */ diff --git a/src/win32/win32.rc.cmake b/src/win32/win32.rc.cmake index 1e86c7e0d..4cca9d89d 100644 --- a/src/win32/win32.rc.cmake +++ b/src/win32/win32.rc.cmake @@ -54,7 +54,7 @@ BEGIN VALUE "FileDescription", "Anope IRC Services" VALUE "FileVersion", "@VERSION_FULL@" VALUE "InternalName", "Anope" - VALUE "LegalCopyright", "Copyright (C) 2003-2016 Anope Team" + VALUE "LegalCopyright", "Copyright (C) 2003-2014 Anope Team" VALUE "OriginalFilename", "anope.exe" VALUE "ProductName", "Anope" VALUE "ProductVersion", "@VERSION_DOTTED@" diff --git a/src/win32/windows.cpp b/src/win32/windows.cpp index ac6801cba..f5bbde2f8 100644 --- a/src/win32/windows.cpp +++ b/src/win32/windows.cpp @@ -1,7 +1,7 @@ -/* POSIX emulation layer for Windows. + /* POSIX emulation layer for Windows. * - * (C) 2008-2011 Robin Burchell <w00t@inspircd.org> - * (C) 2008-2016 Anope Team <team@anope.org> + * Copyright (C) 2008-2011 Robin Burchell <w00t@inspircd.org> + * Copyright (C) 2008-2014 Anope Team <info@anope.org> * * Please read COPYING and README for further details. * @@ -73,10 +73,10 @@ int gettimeofday(timeval *tv, void *) { SYSTEMTIME st; GetSystemTime(&st); - + tv->tv_sec = Anope::CurTime; tv->tv_usec = st.wMilliseconds; - + return 0; } @@ -248,7 +248,7 @@ int mkstemp(char *input) errno = EEXIST; return -1; } - + int fd = open(input, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE); return fd; } diff --git a/src/xline.cpp b/src/xline.cpp index 21cbc2501..8fa7085c8 100644 --- a/src/xline.cpp +++ b/src/xline.cpp @@ -1,12 +1,20 @@ -/* XLine functions. +/* + * Anope IRC Services * - * (C) 2003-2016 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2012-2016 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" @@ -14,66 +22,67 @@ #include "xline.h" #include "users.h" #include "sockets.h" -#include "regexpr.h" #include "config.h" #include "commands.h" #include "servers.h" /* List of XLine managers we check users against in XLineManager::CheckAll */ -std::list<XLineManager *> XLineManager::XLineManagers; -Serialize::Checker<std::multimap<Anope::string, XLine *, ci::less> > XLineManager::XLinesByUID("XLine"); +std::vector<XLineManager *> XLineManager::XLineManagers; -void XLine::Init() +void XLine::Recache() { - if (this->mask.length() >= 2 && this->mask[0] == '/' && this->mask[this->mask.length() - 1] == '/' && !Config->GetBlock("options")->Get<const Anope::string>("regexengine").empty()) + delete regex; + regex = nullptr; + + delete c; + c = nullptr; + + Anope::string mask = GetMask(); + if (mask.length() >= 2 && mask[0] == '/' && mask[mask.length() - 1] == '/' && Config->regex_flags) { - Anope::string stripped_mask = this->mask.substr(1, this->mask.length() - 2); + Anope::string stripped_mask = mask.substr(1, mask.length() - 2); - ServiceReference<RegexProvider> provider("Regex", Config->GetBlock("options")->Get<const Anope::string>("regexengine")); - if (provider) + try { - try - { - this->regex = provider->Compile(stripped_mask); - } - catch (const RegexException &ex) - { - Log(LOG_DEBUG) << ex.GetReason(); - } + this->regex = new std::regex(stripped_mask.str(), Config->regex_flags); + } + catch (const std::regex_error &ex) + { + Anope::Logger.Debug(ex.what()); } } - size_t nick_t = this->mask.find('!'); + size_t nick_t = mask.find('!'); if (nick_t != Anope::string::npos) - nick = this->mask.substr(0, nick_t); + nick = mask.substr(0, nick_t); - size_t user_t = this->mask.find('!'), host_t = this->mask.find('@'); + size_t user_t = mask.find('!'), host_t = mask.find('@'); if (host_t != Anope::string::npos) { if (user_t != Anope::string::npos && host_t > user_t) - user = this->mask.substr(user_t + 1, host_t - user_t - 1); + user = mask.substr(user_t + 1, host_t - user_t - 1); else - user = this->mask.substr(0, host_t); + user = mask.substr(0, host_t); } - size_t real_t = this->mask.find('#'); + size_t real_t = mask.find('#'); if (host_t != Anope::string::npos) { if (real_t != Anope::string::npos && real_t > host_t) - host = this->mask.substr(host_t + 1, real_t - host_t - 1); + host = mask.substr(host_t + 1, real_t - host_t - 1); else - host = this->mask.substr(host_t + 1); + host = mask.substr(host_t + 1); } else { if (real_t != Anope::string::npos) - host = this->mask.substr(0, real_t); + host = mask.substr(0, real_t); else - host = this->mask; + host = mask; } if (real_t != Anope::string::npos) - real = this->mask.substr(real_t + 1); + real = mask.substr(real_t + 1); if (host.find('/') != Anope::string::npos) { @@ -86,31 +95,80 @@ void XLine::Init() } } -XLine::XLine(const Anope::string &ma, const Anope::string &r, const Anope::string &uid) : Serializable("XLine"), mask(ma), by(Me->GetName()), created(0), expires(0), reason(r), id(uid) +XLine::~XLine() +{ + delete regex; + delete c; +} + +void XLine::SetType(const Anope::string &t) { - regex = NULL; - manager = NULL; - c = NULL; + Set(&XLineType::type, t); +} - this->Init(); +Anope::string XLine::GetType() +{ + return Get(&XLineType::type); } -XLine::XLine(const Anope::string &ma, const Anope::string &b, const time_t ex, const Anope::string &r, const Anope::string &uid) : Serializable("XLine"), mask(ma), by(b), created(Anope::CurTime), expires(ex), reason(r), id(uid) +void XLine::SetMask(const Anope::string &m) { - regex = NULL; - manager = NULL; - c = NULL; + Set(&XLineType::mask, m); +} - this->Init(); +Anope::string XLine::GetMask() +{ + return Get<Anope::string>(&XLineType::mask); } -XLine::~XLine() +void XLine::SetBy(const Anope::string &b) { - if (manager) - manager->RemoveXLine(this); + Set(&XLineType::by, b); +} - delete regex; - delete c; +Anope::string XLine::GetBy() +{ + return Get(&XLineType::by); +} + +void XLine::SetReason(const Anope::string &r) +{ + Set(&XLineType::reason, r); +} + +Anope::string XLine::GetReason() +{ + return Get(&XLineType::reason); +} + +void XLine::SetID(const Anope::string &id) +{ + Set(&XLineType::id, id); +} + +Anope::string XLine::GetID() +{ + return Get(&XLineType::id); +} + +void XLine::SetCreated(const time_t &t) +{ + Set(&XLineType::created, t); +} + +time_t XLine::GetCreated() +{ + return Get(&XLineType::created); +} + +void XLine::SetExpires(const time_t &e) +{ + Set(&XLineType::expires, e); +} + +time_t XLine::GetExpires() +{ + return Get(&XLineType::created); } const Anope::string &XLine::GetNick() const @@ -133,11 +191,11 @@ const Anope::string &XLine::GetReal() const return real; } -Anope::string XLine::GetReason() const +Anope::string XLine::GetReasonWithID() { - Anope::string r = this->reason; - if (!this->id.empty()) - r += " (ID: " + this->id + ")"; + Anope::string r = this->GetReason(); + if (!this->GetID().empty()) + r += " (ID: " + this->GetID() + ")"; return r; } @@ -146,67 +204,20 @@ bool XLine::HasNickOrReal() const return !this->GetNick().empty() || !this->GetReal().empty(); } -bool XLine::IsRegex() const +bool XLine::IsRegex() { - return !this->mask.empty() && this->mask[0] == '/' && this->mask[this->mask.length() - 1] == '/'; + Anope::string mask = GetMask(); + return mask.length() > 2 && mask[0] == '/' && mask[mask.length() - 1] == '/'; } -void XLine::Serialize(Serialize::Data &data) const +XLineManager *XLine::GetManager() { - data["mask"] << this->mask; - data["by"] << this->by; - data["created"] << this->created; - data["expires"] << this->expires; - data["reason"] << this->reason; - data["uid"] << this->id; - if (this->manager) - data["manager"] << this->manager->name; + return ServiceManager::Get()->FindService<XLineManager *>(GetType()); } -Serializable* XLine::Unserialize(Serializable *obj, Serialize::Data &data) +void XLineType::Mask::OnSet(XLine *s, const Anope::string &value) { - Anope::string smanager; - - data["manager"] >> smanager; - - ServiceReference<XLineManager> xlm("XLineManager", smanager); - if (!xlm) - return NULL; - - XLine *xl; - if (obj) - { - xl = anope_dynamic_static_cast<XLine *>(obj); - data["mask"] >> xl->mask; - data["by"] >> xl->by; - data["reason"] >> xl->reason; - data["uid"] >> xl->id; - - if (xlm != xl->manager) - { - xl->manager->DelXLine(xl); - xlm->AddXLine(xl); - } - } - else - { - Anope::string smask, sby, sreason, suid; - time_t expires; - - data["mask"] >> smask; - data["by"] >> sby; - data["reason"] >> sreason; - data["uid"] >> suid; - data["expires"] >> expires; - - xl = new XLine(smask, sby, expires, sreason, suid); - xlm->AddXLine(xl); - } - - data["created"] >> xl->created; - xl->manager = xlm; - - return xl; + s->Recache(); } void XLineManager::RegisterXLineManager(XLineManager *xlm) @@ -216,52 +227,35 @@ void XLineManager::RegisterXLineManager(XLineManager *xlm) void XLineManager::UnregisterXLineManager(XLineManager *xlm) { - std::list<XLineManager *>::iterator it = std::find(XLineManagers.begin(), XLineManagers.end(), xlm); - + auto it = std::find(XLineManagers.begin(), XLineManagers.end(), xlm); if (it != XLineManagers.end()) XLineManagers.erase(it); } void XLineManager::CheckAll(User *u) { - for (std::list<XLineManager *>::iterator it = XLineManagers.begin(), it_end = XLineManagers.end(); it != it_end; ++it) - { - XLineManager *xlm = *it; - + for (XLineManager *xlm : XLineManagers) if (xlm->CheckAllXLines(u)) break; - } } Anope::string XLineManager::GenerateUID() { Anope::string id; - int count = 0; - do - { - id.clear(); - if (++count > 10) - { - Log(LOG_DEBUG) << "Unable to generate XLine UID"; - break; - } - - for (int i = 0; i < 10; ++i) - { - char c; - do - c = (rand() % 75) + 48; - while (!isupper(c) && !isdigit(c)); - id += c; - } + for (int i = 0; i < 10; ++i) + { + char c; + do + c = (rand() % 75) + 48; + while (!isupper(c) && !isdigit(c)); + id += c; } - while (XLinesByUID->count(id) > 0); return id; } -XLineManager::XLineManager(Module *creator, const Anope::string &xname, char t) : Service(creator, "XLineManager", xname), type(t), xlines("XLine") +XLineManager::XLineManager(Module *creator, const Anope::string &xname, char t) : Service(creator, NAME, xname), type(t) { } @@ -270,147 +264,82 @@ XLineManager::~XLineManager() this->Clear(); } -const char &XLineManager::Type() +char XLineManager::Type() { return this->type; } -size_t XLineManager::GetCount() const +std::vector<XLine *> XLineManager::GetXLines() const { - return this->xlines->size(); -} + std::vector<XLine *> xlines; -const std::vector<XLine *> &XLineManager::GetList() const -{ - return this->xlines; -} + for (XLine *x : Serialize::GetObjects<XLine *>()) + if (x->GetType() == this->GetName()) + xlines.push_back(x); -void XLineManager::AddXLine(XLine *x) -{ - if (!x->id.empty()) - XLinesByUID->insert(std::make_pair(x->id, x)); - this->xlines->push_back(x); - x->manager = this; + return xlines; } -void XLineManager::RemoveXLine(XLine *x) -{ - /* called from the destructor */ - - std::vector<XLine *>::iterator it = std::find(this->xlines->begin(), this->xlines->end(), x); - - if (!x->id.empty()) - { - std::multimap<Anope::string, XLine *, ci::less>::iterator it2 = XLinesByUID->find(x->id), it3 = XLinesByUID->upper_bound(x->id); - for (; it2 != XLinesByUID->end() && it2 != it3; ++it2) - if (it2->second == x) - { - XLinesByUID->erase(it2); - break; - } - } - - if (it != this->xlines->end()) - { - this->SendDel(x); - this->xlines->erase(it); - } -} - -bool XLineManager::DelXLine(XLine *x) +void XLineManager::AddXLine(XLine *x) { - std::vector<XLine *>::iterator it = std::find(this->xlines->begin(), this->xlines->end(), x); - - if (!x->id.empty()) - { - std::multimap<Anope::string, XLine *, ci::less>::iterator it2 = XLinesByUID->find(x->id), it3 = XLinesByUID->upper_bound(x->id); - for (; it2 != XLinesByUID->end() && it2 != it3; ++it2) - if (it2->second == x) - { - XLinesByUID->erase(it2); - break; - } - } - - if (it != this->xlines->end()) - { - this->SendDel(x); - - x->manager = NULL; // Don't call remove - delete x; - this->xlines->erase(it); - - return true; - } - - return false; + x->SetType(this->GetName()); } XLine* XLineManager::GetEntry(unsigned index) { - if (index >= this->xlines->size()) - return NULL; + std::vector<XLine *> xlines = GetXLines(); + + if (index >= xlines.size()) + return nullptr; - XLine *x = this->xlines->at(index); - x->QueueUpdate(); - return x; + return xlines.at(index); } void XLineManager::Clear() { - std::vector<XLine *> xl; - this->xlines->swap(xl); - - for (unsigned i = 0; i < xl.size(); ++i) - { - XLine *x = xl[i]; - if (!x->id.empty()) - XLinesByUID->erase(x->id); - delete x; - } + for (XLine *x : GetXLines()) + x->Delete(); } bool XLineManager::CanAdd(CommandSource &source, const Anope::string &mask, time_t expires, const Anope::string &reason) { - for (unsigned i = this->GetCount(); i > 0; --i) + for (XLine *x : GetXLines()) { - XLine *x = this->GetEntry(i - 1); - - if (x->mask.equals_ci(mask)) + if (x->GetMask().equals_ci(mask)) { - if (!x->expires || x->expires >= expires) + if (!x->GetExpires() || x->GetExpires() >= expires) { - if (x->reason != reason) + if (x->GetReason() != reason) { - x->reason = reason; - source.Reply(_("Reason for %s updated."), x->mask.c_str()); + x->SetReason(reason); + source.Reply(_("Reason for %s updated."), x->GetMask().c_str()); } else source.Reply(_("%s already exists."), mask.c_str()); } else { - x->expires = expires; - if (x->reason != reason) + x->SetExpires(expires); + if (x->GetReason() != reason) { - x->reason = reason; - source.Reply(_("Expiry and reason updated for %s."), x->mask.c_str()); + x->SetReason(reason); + source.Reply(_("Expiry and reason updated for %s."), x->GetMask().c_str()); } else - source.Reply(_("Expiry for %s updated."), x->mask.c_str()); + source.Reply(_("Expiry for %s updated."), x->GetMask().c_str()); } return false; } - else if (Anope::Match(mask, x->mask) && (!x->expires || x->expires >= expires)) + else if (Anope::Match(mask, x->GetMask()) && (!x->GetExpires() || x->GetExpires() >= expires)) { - source.Reply(_("%s is already covered by %s."), mask.c_str(), x->mask.c_str()); + source.Reply(_("%s is already covered by %s."), mask.c_str(), x->GetMask().c_str()); return false; } - else if (Anope::Match(x->mask, mask) && (!expires || x->expires <= expires)) + else if (Anope::Match(x->GetMask(), mask) && (!expires || x->GetExpires() <= expires)) { - source.Reply(_("Removing %s because %s covers it."), x->mask.c_str(), mask.c_str()); - this->DelXLine(x); + source.Reply(_("Removing %s because %s covers it."), x->GetMask().c_str(), mask.c_str()); + x->Delete(); } } @@ -419,38 +348,21 @@ bool XLineManager::CanAdd(CommandSource &source, const Anope::string &mask, time XLine* XLineManager::HasEntry(const Anope::string &mask) { - std::multimap<Anope::string, XLine *, ci::less>::iterator it = XLinesByUID->find(mask); - if (it != XLinesByUID->end()) - for (std::multimap<Anope::string, XLine *, ci::less>::iterator it2 = XLinesByUID->upper_bound(mask); it != it2; ++it) - if (it->second->manager == NULL || it->second->manager == this) - { - it->second->QueueUpdate(); - return it->second; - } - for (unsigned i = 0, end = this->xlines->size(); i < end; ++i) - { - XLine *x = this->xlines->at(i); - - if (x->mask.equals_ci(mask)) - { - x->QueueUpdate(); + for (XLine *x : GetXLines()) + if (x->GetMask().equals_ci(mask)) return x; - } - } - return NULL; + return nullptr; } XLine *XLineManager::CheckAllXLines(User *u) { - for (unsigned i = this->xlines->size(); i > 0; --i) + for (XLine *x : Serialize::GetObjects<XLine *>()) { - XLine *x = this->xlines->at(i - 1); - - if (x->expires && x->expires < Anope::CurTime) + if (x->GetExpires() && x->GetExpires() < Anope::CurTime) { this->OnExpire(x); - this->DelXLine(x); + x->Delete(); continue; } @@ -461,10 +373,10 @@ XLine *XLineManager::CheckAllXLines(User *u) } } - return NULL; + return nullptr; } -void XLineManager::OnExpire(const XLine *x) +void XLineManager::OnExpire(XLine *x) { } |