summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt99
-rw-r--r--src/access.cpp103
-rw-r--r--src/account.cpp6
-rw-r--r--src/base.cpp8
-rw-r--r--src/bots.cpp75
-rw-r--r--src/channels.cpp123
-rw-r--r--src/command.cpp103
-rw-r--r--src/config.cpp475
-rw-r--r--src/extensible.cpp7
-rw-r--r--src/hashcomp.cpp8
-rw-r--r--src/init.cpp177
-rw-r--r--src/language.cpp114
-rw-r--r--src/logger.cpp82
-rw-r--r--src/mail.cpp65
-rw-r--r--src/main.cpp67
-rw-r--r--src/memos.cpp34
-rw-r--r--src/messages.cpp180
-rw-r--r--src/misc.cpp425
-rw-r--r--src/modes.cpp143
-rw-r--r--src/module.cpp12
-rw-r--r--src/modulemanager.cpp81
-rw-r--r--src/nickalias.cpp97
-rw-r--r--src/nickcore.cpp227
-rw-r--r--src/opertype.cpp54
-rw-r--r--src/pipeengine.cpp2
-rw-r--r--src/process.cpp137
-rw-r--r--src/protocol.cpp326
-rw-r--r--src/regchannel.cpp183
-rw-r--r--src/serialize.cpp61
-rw-r--r--src/servers.cpp83
-rw-r--r--src/siphash.cpp139
-rw-r--r--src/socket_clients.cpp2
-rw-r--r--src/socket_transport.cpp18
-rw-r--r--src/socketengines/epoll.cpp (renamed from src/socketengines/socketengine_epoll.cpp)8
-rw-r--r--src/socketengines/kqueue.cpp (renamed from src/socketengines/socketengine_kqueue.cpp)2
-rw-r--r--src/socketengines/poll.cpp (renamed from src/socketengines/socketengine_poll.cpp)6
-rw-r--r--src/socketengines/select.cpp (renamed from src/socketengines/socketengine_select.cpp)9
-rw-r--r--src/sockets.cpp102
-rw-r--r--src/threadengine.cpp89
-rw-r--r--src/timers.cpp44
-rw-r--r--src/tools/CMakeLists.txt30
-rw-r--r--src/tools/anope.service.in17
-rw-r--r--src/tools/anoperc.in8
-rw-r--r--src/tools/anopesmtp.cpp535
-rwxr-xr-xsrc/tools/mkauthors57
-rw-r--r--src/uplink.cpp143
-rw-r--r--src/users.cpp242
-rw-r--r--src/version.sh4
-rw-r--r--src/win32/Config.cs2
-rw-r--r--src/win32/anope_windows.h11
-rw-r--r--src/win32/conanfile.txt2
-rw-r--r--src/win32/dir/dir.cpp48
-rw-r--r--src/win32/dir/dir.h27
-rw-r--r--src/win32/dl/dl.cpp2
-rw-r--r--src/win32/dl/dl.h2
-rw-r--r--src/win32/pipe/pipe.cpp2
-rw-r--r--src/win32/pipe/pipe.h2
-rw-r--r--src/win32/pthread/pthread.cpp119
-rw-r--r--src/win32/pthread/pthread.h35
-rw-r--r--src/win32/resource.h2
-rw-r--r--src/win32/sigaction/sigaction.cpp2
-rw-r--r--src/win32/sigaction/sigaction.h4
-rw-r--r--src/win32/socket.cpp83
-rw-r--r--src/win32/socket.h6
-rw-r--r--src/win32/win32.rc.cmake4
-rw-r--r--src/win32/windows.cpp173
-rw-r--r--src/xline.cpp73
67 files changed, 2341 insertions, 3270 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bdec61abf..79d10e39c 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/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/epoll.cpp)
+elseif(HAVE_KQUEUE)
+ list(APPEND SRC_SRCS socketengines/kqueue.cpp)
+elseif(HAVE_POLL)
+ list(APPEND SRC_SRCS socketengines/poll.cpp)
+else()
+ list(APPEND SRC_SRCS socketengines/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,33 @@ 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} ${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})
+endif()
+
+# If being built with localisation we might need to link against libintl.
+if(HAVE_LOCALIZATION AND Intl_LIBRARY)
+ target_link_libraries(${PROGRAM_NAME} ${Intl_LIBRARY})
+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)
+if(HAVE_LOCALIZATION)
add_dependencies(${PROGRAM_NAME} language)
-endif(GETTEXT_FOUND)
+endif()
# Get the filename of the Anope executable as it is in on this system
set(SERVICES_BINARY "$<TARGET_FILE:${PROGRAM_NAME}>")
@@ -108,9 +80,10 @@ 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}
DESTINATION ${BIN_DIR}
+ RUNTIME
)
diff --git a/src/access.cpp b/src/access.cpp
index fc1d9a51c..1eb7b8930 100644
--- a/src/access.cpp
+++ b/src/access.cpp
@@ -16,55 +16,8 @@
#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
@@ -94,10 +47,10 @@ void PrivilegeManager::RemovePrivilege(Privilege &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)
+ for (const auto &[_, ci] : *RegisteredChannelList)
{
- cit->second->QueueUpdate();
- cit->second->RemoveLevel(p.name);
+ ci->QueueUpdate();
+ ci->RemoveLevel(p.name);
}
}
@@ -138,7 +91,9 @@ const std::list<AccessProvider *>& AccessProvider::GetProviders()
return Providers;
}
-ChanAccess::ChanAccess(AccessProvider *p) : Serializable("ChanAccess"), provider(p)
+ChanAccess::ChanAccess(AccessProvider *p)
+ : Serializable(CHANACCESS_TYPE)
+ , provider(p)
{
}
@@ -205,18 +160,26 @@ NickCore *ChanAccess::GetAccount() const
return nc;
}
-void ChanAccess::Serialize(Serialize::Data &data) const
+
+ChanAccess::Type::Type()
+ : Serialize::Type(CHANACCESS_TYPE)
{
- 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)
+void ChanAccess::Type::Serialize(const Serializable *obj, Serialize::Data &data) const
+{
+ const auto *access = static_cast<const ChanAccess *>(obj);
+ data.Store("provider", access->provider->name);
+ data.Store("ci", access->ci->name);
+ data.Store("mask", access->Mask());
+ data.Store("creator", access->creator);
+ data.Store("description", access->description);
+ data.Store("last_seen", access->last_seen);
+ data.Store("created", access->created);
+ data.Store("data", access->AccessSerialize());
+}
+
+Serializable *ChanAccess::Type::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string provider, chan;
@@ -238,6 +201,7 @@ Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data)
data["mask"] >> m;
access->SetMask(m, ci);
data["creator"] >> access->creator;
+ data["description"] >> access->description;
data["last_seen"] >> access->last_seen;
data["created"] >> access->created;
@@ -250,7 +214,7 @@ Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data)
return access;
}
-bool ChanAccess::Matches(const User *u, const NickCore *acc, ChannelInfo* &next) const
+bool ChanAccess::Matches(const User *u, const NickCore *acc, ChannelInfo *&next) const
{
next = NULL;
@@ -268,9 +232,8 @@ bool ChanAccess::Matches(const User *u, const NickCore *acc, ChannelInfo* &next)
if (acc)
{
- for (unsigned i = 0; i < acc->aliases->size(); ++i)
+ for (auto *na : *acc->aliases)
{
- const NickAlias *na = acc->aliases->at(i);
if (Anope::Match(na->nick, this->mask))
return true;
}
@@ -340,10 +303,8 @@ 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)
+ for (auto *access : path)
{
- ChanAccess *access = path[i];
-
EventReturn MOD_RESULT;
FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name));
@@ -390,9 +351,9 @@ 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];
+ for (auto *ca : path)
+ if (highest == NULL || *ca > *highest)
+ highest = ca;
return highest;
}
@@ -401,9 +362,9 @@ const ChanAccess *AccessGroup::Highest() const
{
ChanAccess *highest = NULL;
- for (unsigned int i = 0; i < paths.size(); ++i)
+ for (const auto &path : paths)
{
- ChanAccess *hip = HighestInPath(paths[i]);
+ ChanAccess *hip = HighestInPath(path);
if (highest == NULL || *hip > *highest)
highest = hip;
diff --git a/src/account.cpp b/src/account.cpp
index 6b69d0e3b..95bfc9698 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -18,7 +18,11 @@
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)
+IdentifyRequest::IdentifyRequest(Module *o, const Anope::string &acc, const Anope::string &pass, const Anope::string &ip)
+ : owner(o)
+ , account(acc)
+ , password(pass)
+ , address(ip)
{
Requests.insert(this);
}
diff --git a/src/base.cpp b/src/base.cpp
index 58ce2f097..3cd026bda 100644
--- a/src/base.cpp
+++ b/src/base.cpp
@@ -13,16 +13,12 @@
std::map<Anope::string, std::map<Anope::string, Service *> > Service::Services;
std::map<Anope::string, std::map<Anope::string, Anope::string> > Service::Aliases;
-Base::Base() : references(NULL)
-{
-}
-
Base::~Base()
{
if (this->references != NULL)
{
- for (std::set<ReferenceBase *>::iterator it = this->references->begin(), it_end = this->references->end(); it != it_end; ++it)
- (*it)->Invalidate();
+ for (auto *reference : *this->references)
+ reference->Invalidate();
delete this->references;
}
}
diff --git a/src/bots.cpp b/src/bots.cpp
index b4e3a2996..b01b7389f 100644
--- a/src/bots.cpp
+++ b/src/bots.cpp
@@ -18,9 +18,13 @@
#include "language.h"
#include "serialize.h"
-Serialize::Checker<botinfo_map> BotListByNick("BotInfo"), BotListByUID("BotInfo");
+Serialize::Checker<botinfo_map> BotListByNick(BOTINFO_TYPE), BotListByUID(BOTINFO_TYPE);
-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)
+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_TYPE)
+ , channels(CHANNELINFO_TYPE)
+ , botmodes(bmodes)
{
this->lastmsg = this->created = Anope::CurTime;
this->introduced = false;
@@ -35,9 +39,16 @@ BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const A
// If we're synchronised with the uplink already, send the bot.
if (Me && Me->IsSynced())
{
- Anope::string tmodes = !this->botmodes.empty() ? ("+" + this->botmodes) : IRCD->DefaultPseudoclientModes;
- if (!tmodes.empty())
- this->SetModesInternal(this, tmodes.c_str());
+ spacesepstream modesep(this->botmodes.empty() ? IRCD->DefaultPseudoclientModes : "+" + this->botmodes);
+
+ Anope::string modechars;
+ modesep.GetToken(modechars);
+
+ std::vector<Anope::string> modeparams;
+ modesep.GetTokens(modeparams);
+
+ if (!modechars.empty())
+ this->SetModesInternal(this, modechars, modeparams);
XLine x(this->nick, "Reserved for services");
IRCD->SendSQLine(NULL, &x);
@@ -55,7 +66,7 @@ BotInfo::~BotInfo()
// If we're synchronised with the uplink already, send the bot.
if (Me && Me->IsSynced())
{
- IRCD->SendQuit(this, "");
+ IRCD->SendQuit(this);
FOREACH_MOD(OnUserQuit, (this, ""));
this->introduced = false;
XLine x(this->nick);
@@ -73,19 +84,25 @@ BotInfo::~BotInfo()
BotListByUID->erase(this->uid);
}
-void BotInfo::Serialize(Serialize::Data &data) const
+BotInfo::Type::Type()
+ : Serialize::Type(BOTINFO_TYPE)
+{
+}
+
+void BotInfo::Type::Serialize(const Serializable *obj, 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);
+ const auto *bi = static_cast<const BotInfo *>(obj);
+ data.Store("nick", bi->nick);
+ data.Store("user", bi->ident);
+ data.Store("host", bi->host);
+ data.Store("realname", bi->realname);
+ data.Store("created", bi->created);
+ data.Store("oper_only", bi->oper_only);
+
+ Extensible::ExtensibleSerialize(bi, bi, data);
}
-Serializable* BotInfo::Unserialize(Serializable *obj, Serialize::Data &data)
+Serializable *BotInfo::Type::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string nick, user, host, realname, flags;
@@ -131,8 +148,8 @@ void BotInfo::OnKill()
IRCD->SendClientIntroduction(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);
+ for (const auto &[_, chan] : this->chans)
+ IRCD->SendJoin(this, chan->chan, &chan->status);
}
void BotInfo::SetNewNick(const Anope::string &newnick)
@@ -216,23 +233,28 @@ void BotInfo::Part(Channel *c, const Anope::string &reason)
FOREACH_MOD(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));
}
-void BotInfo::OnMessage(User *u, const Anope::string &message)
+void BotInfo::OnMessage(User *u, const Anope::string &message, const Anope::map<Anope::string> &tags)
{
if (this->commands.empty())
return;
- CommandSource source(u->nick, u, u->Account(), u, this);
+ Anope::string msgid;
+ auto iter = tags.find("msgid");
+ if (iter != tags.end())
+ msgid = iter->second;
+
+ CommandSource source(u->nick, u, u->Account(), u, this, msgid);
Command::Run(source, message);
}
-CommandInfo& BotInfo::SetCommand(const Anope::string &cname, const Anope::string &sname, const Anope::string &permission)
+CommandInfo &BotInfo::SetCommand(const Anope::string &cname, const Anope::string &sname, const Anope::string &permission)
{
CommandInfo ci;
ci.name = sname;
@@ -249,7 +271,14 @@ CommandInfo *BotInfo::GetCommand(const Anope::string &cname)
return NULL;
}
-BotInfo* BotInfo::Find(const Anope::string &nick, bool nick_only)
+Anope::string BotInfo::GetQueryCommand() const
+{
+ if (Config->ServiceAlias && !this->alias.empty())
+ return Anope::printf("/%s", this->alias.c_str());
+ return Anope::printf("/msg %s", this->nick.c_str());
+}
+
+BotInfo *BotInfo::Find(const Anope::string &nick, bool nick_only)
{
if (!nick_only && IRCD != NULL && IRCD->RequiresID)
{
diff --git a/src/channels.cpp b/src/channels.cpp
index b8e9f024d..3e7fb6e50 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -29,17 +29,12 @@ channel_map ChannelList;
std::vector<Channel *> Channel::deleting;
Channel::Channel(const Anope::string &nname, time_t ts)
+ : name(nname)
+ , creation_time(ts)
{
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;
@@ -71,25 +66,23 @@ void Channel::Reset()
{
this->modes.clear();
- for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it)
+ for (const auto &[_, uc] : this->users)
{
- ChanUserContainer *uc = it->second;
-
ChannelStatus f = uc->status;
uc->status.Clear();
/* reset modes for my clients */
if (uc->user->server == Me)
{
- for (size_t i = 0; i < f.Modes().length(); ++i)
- this->SetMode(NULL, ModeManager::FindChannelModeByChar(f.Modes()[i]), uc->user->GetUID(), false);
+ for (auto mode : f.Modes())
+ this->SetMode(NULL, ModeManager::FindChannelModeByChar(mode), uc->user->GetUID(), false);
/* Modes might not exist yet, so be sure the status is really reset */
uc->status = f;
}
}
- for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it)
- this->SetCorrectModes(it->second->user, true);
+ for (auto &[_, cuc] : this->users)
+ this->SetCorrectModes(cuc->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
@@ -113,7 +106,7 @@ void Channel::CheckModes()
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?";
- this->bouncy_modes = 1;
+ this->bouncy_modes = true;
return;
}
@@ -139,12 +132,12 @@ bool Channel::CheckDelete()
return MOD_RESULT != EVENT_STOP && this->users.empty();
}
-ChanUserContainer* Channel::JoinUser(User *user, const ChannelStatus *status)
+ChanUserContainer *Channel::JoinUser(User *user, const ChannelStatus *status)
{
if (user->server && user->server->IsSynced())
Log(user, this, "join");
- ChanUserContainer *cuc = new ChanUserContainer(user, this);
+ auto *cuc = new ChanUserContainer(user, this);
user->chans[this] = cuc;
this->users[user] = cuc;
if (status)
@@ -203,10 +196,12 @@ size_t Channel::HasMode(const Anope::string &mname, const Anope::string &param)
{
if (param.empty())
return modes.count(mname);
- std::vector<Anope::string> v = this->GetModeList(mname);
- for (unsigned int i = 0; i < v.size(); ++i)
- if (v[i].equals_ci(param))
+
+ for (const auto &mode : this->GetModeList(mname))
+ {
+ if (mode.equals_ci(param))
return 1;
+ }
return 0;
}
@@ -214,22 +209,22 @@ Anope::string Channel::GetModes(bool complete, bool plus)
{
Anope::string res, params;
- for (std::multimap<Anope::string, Anope::string>::const_iterator it = this->modes.begin(), it_end = this->modes.end(); it != it_end; ++it)
+ for (const auto &[mode, value] : this->modes)
{
- ChannelMode *cm = ModeManager::FindChannelModeByName(it->first);
+ ChannelMode *cm = ModeManager::FindChannelModeByName(mode);
if (!cm || cm->type == MODE_LIST)
continue;
res += cm->mchar;
- if (complete && !it->second.empty())
+ if (complete && !value.empty())
{
ChannelModeParam *cmp = NULL;
if (cm->type == MODE_PARAM)
cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
if (plus || !cmp || !cmp->minus_no_arg)
- params += " " + it->second;
+ params += " " + value;
}
}
@@ -242,7 +237,7 @@ const Channel::ModeList &Channel::GetModes() const
}
template<typename F, typename S>
-struct second
+struct second final
{
S operator()(const std::pair<F, S> &p)
{
@@ -304,7 +299,7 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Ano
else if (this->HasMode(cm->name, param))
return;
- this->modes.insert(std::make_pair(cm->name, param));
+ this->modes.emplace(cm->name, param);
if (param.empty() && cm->type != MODE_REGULAR)
{
@@ -542,15 +537,21 @@ void Channel::SetModes(BotInfo *bi, bool enforce_mlock, const char *cmodes, ...)
{
char buf[BUFSIZE] = "";
va_list args;
- Anope::string modebuf, sbuf;
- int add = -1;
va_start(args, cmodes);
vsnprintf(buf, BUFSIZE - 1, cmodes, args);
va_end(args);
+ SetModes(bi, enforce_mlock, Anope::string(buf));
+}
+
+
+void Channel::SetModes(BotInfo *bi, bool enforce_mlock, const Anope::string &cmodes)
+{
+ Anope::string modebuf, sbuf;
+ int add = -1;
Reference<Channel> this_reference(this);
- spacesepstream sep(buf);
+ spacesepstream sep(cmodes);
sep.GetToken(modebuf);
for (unsigned i = 0, end = modebuf.length(); this_reference && i < end; ++i)
{
@@ -605,13 +606,13 @@ void Channel::SetModes(BotInfo *bi, bool enforce_mlock, const char *cmodes, ...)
}
}
-void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode, time_t ts, bool enforce_mlock)
+void Channel::SetModesInternal(MessageSource &source, const Anope::string &modes, const std::vector<Anope::string> &params, time_t ts, bool enforce_mlock)
{
if (!ts)
;
else if (ts > this->creation_time)
{
- Log(LOG_DEBUG) << "Dropping mode " << mode << " on " << this->name << ", " << ts << " > " << this->creation_time;
+ Log(LOG_DEBUG) << "Dropping mode " << modes << " on " << this->name << ", " << ts << " > " << this->creation_time;
return;
}
else if (ts < this->creation_time)
@@ -625,20 +626,18 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode,
/* Removing channel modes *may* delete this channel */
Reference<Channel> this_reference(this);
- spacesepstream sep_modes(mode);
- Anope::string m;
-
- sep_modes.GetToken(m);
-
Anope::string modestring;
Anope::string paramstring;
int add = -1;
bool changed = false;
- for (unsigned int i = 0, end = m.length(); i < end && this_reference; ++i)
+ auto paramit = params.begin();
+ for (const auto mchar : modes)
{
- ChannelMode *cm;
+ if (!this_reference)
+ break;
- switch (m[i])
+ ChannelMode *cm;
+ switch (mchar)
{
case '+':
modestring += '+';
@@ -651,10 +650,10 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode,
default:
if (add == -1)
continue;
- cm = ModeManager::FindChannelModeByChar(m[i]);
+ cm = ModeManager::FindChannelModeByChar(mchar);
if (!cm)
{
- Log(LOG_DEBUG) << "Channel::SetModeInternal: Unknown mode char " << m[i];
+ Log(LOG_DEBUG) << "Channel::SetModeInternal: Unknown mode char " << mchar;
continue;
}
modestring += cm->mchar;
@@ -680,9 +679,9 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode,
continue;
}
}
- Anope::string token;
- if (sep_modes.GetToken(token))
+ if (paramit != params.end())
{
+ auto token = *paramit++;
User *u = NULL;
if (cm->type == MODE_STATUS && (u = User::Find(token)))
paramstring += " " + u->nick;
@@ -697,7 +696,7 @@ 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;
+ Log() << "warning: Channel::SetModesInternal() received more modes requiring params than params, modes: " << modes;
}
if (!this_reference)
@@ -728,10 +727,9 @@ bool Channel::MatchesList(User *u, const Anope::string &mode)
if (!this->HasMode(mode))
return false;
- std::vector<Anope::string> v = this->GetModeList(mode);
- for (unsigned i = 0; i < v.size(); ++i)
+ for (const auto &entry : this->GetModeList(mode))
{
- Entry e(mode, v[i]);
+ Entry e(mode, entry);
if (e.Matches(u))
return true;
}
@@ -778,6 +776,11 @@ bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...)
vsnprintf(buf, BUFSIZE - 1, reason, args);
va_end(args);
+ return Kick(bi, u, Anope::string(buf));
+}
+
+bool Channel::Kick(BotInfo *bi, User *u, const Anope::string &reason)
+{
/* Do not kick protected clients or Ulines */
if (u->IsProtected())
return false;
@@ -786,11 +789,11 @@ bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...)
bi = this->WhoSends();
EventReturn MOD_RESULT;
- FOREACH_RESULT(OnBotKick, MOD_RESULT, (bi, this, u, buf));
+ FOREACH_RESULT(OnBotKick, MOD_RESULT, (bi, this, u, reason));
if (MOD_RESULT == EVENT_STOP)
return false;
- IRCD->SendKick(bi, this, u, "%s", buf);
- this->KickInternal(bi, u->nick, buf);
+ IRCD->SendKick(bi, this, u, reason);
+ this->KickInternal(bi, u->nick, reason);
return true;
}
@@ -845,9 +848,8 @@ void Channel::SetCorrectModes(User *user, bool give_modes)
bool giving = give_modes;
/* whether or not we have given a mode */
bool given = false;
- for (unsigned i = 0; i < ModeManager::GetStatusChannelModesByRank().size(); ++i)
+ for (auto *cm : ModeManager::GetStatusChannelModesByRank())
{
- ChannelModeStatus *cm = ModeManager::GetStatusChannelModesByRank()[i];
bool has_priv = u_access.HasPriv("AUTO" + cm->name);
if (give_modes && has_priv)
@@ -880,10 +882,9 @@ bool Channel::Unban(User *u, const Anope::string &mode, bool full)
bool ret = false;
- std::vector<Anope::string> v = this->GetModeList(mode);
- for (unsigned int i = 0; i < v.size(); ++i)
+ for (const auto &entry : this->GetModeList(mode))
{
- Entry ban(mode, v[i]);
+ Entry ban(mode, entry);
if (ban.Matches(u, full))
{
this->RemoveMode(NULL, mode, ban.GetMask());
@@ -921,12 +922,12 @@ bool Channel::CheckKick(User *user)
Log(LOG_DEBUG) << "Autokicking " << user->nick << " (" << mask << ") from " << this->name;
this->SetMode(NULL, "BAN", mask);
- this->Kick(NULL, user, "%s", reason.c_str());
+ this->Kick(NULL, user, reason);
return true;
}
-BotInfo* Channel::WhoSends() const
+BotInfo *Channel::WhoSends() const
{
if (ci)
return ci->WhoSends();
@@ -941,7 +942,7 @@ BotInfo* Channel::WhoSends() const
return NULL;
}
-Channel* Channel::Find(const Anope::string &name)
+Channel *Channel::Find(const Anope::string &name)
{
channel_map::const_iterator it = ChannelList.find(name);
@@ -952,7 +953,7 @@ Channel* Channel::Find(const Anope::string &name)
Channel *Channel::FindOrCreate(const Anope::string &name, bool &created, time_t ts)
{
- Channel* &chan = ChannelList[name];
+ Channel *&chan = ChannelList[name];
created = chan == NULL;
if (!chan)
chan = new Channel(name, ts);
@@ -967,10 +968,8 @@ void Channel::QueueForDeletion()
void Channel::DeleteChannels()
{
- for (unsigned int i = 0; i < deleting.size(); ++i)
+ for (auto *c : deleting)
{
- Channel *c = deleting[i];
-
if (c->CheckDelete())
delete c;
}
diff --git a/src/command.cpp b/src/command.cpp
index eb5c89753..6df28aa9f 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -17,8 +17,19 @@
#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)
+void CommandReply::SendMessage(CommandSource &source, const Anope::string &msg)
+{
+ SendMessage(source.service, msg);
+}
+
+CommandSource::CommandSource(const Anope::string &n, User *user, NickCore *core, CommandReply *r, BotInfo *bi, const Anope::string &m)
+ : nick(n)
+ , u(user)
+ , nc(core)
+ , ip(user ? user->ip.addr() : "")
+ , reply(r)
+ , service(bi)
+ , msgid(m)
{
}
@@ -107,6 +118,21 @@ void CommandSource::Reply(const char *message, ...)
va_end(args);
}
+void CommandSource::Reply(int count, const char *single, const char *plural, ...)
+{
+ va_list args;
+ char buf[4096]; // Messages can be really big.
+
+ const char *translated_message = Language::Translate(this->nc, count, single, plural);
+
+ va_start(args, plural);
+ vsnprintf(buf, sizeof(buf), translated_message, args);
+
+ this->Reply(Anope::string(buf));
+
+ va_end(args);
+}
+
void CommandSource::Reply(const Anope::string &message)
{
const char *translated_message = Language::Translate(this->nc, message.c_str());
@@ -114,7 +140,7 @@ 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, 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)
@@ -122,10 +148,6 @@ Command::Command(Module *o, const Anope::string &sname, size_t minparams, size_t
allow_unregistered = require_user = false;
}
-Command::~Command()
-{
-}
-
void Command::SetDesc(const Anope::string &d)
{
this->desc = d;
@@ -192,14 +214,56 @@ 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(MORE_INFO, source.service->GetQueryCommand().c_str(), source.command.c_str());
+}
+
+namespace
+{
+ void HandleUnknownCommand(CommandSource& source, const Anope::string &message)
+ {
+ // Try to find a similar command.
+ size_t distance = Config->GetBlock("options").Get<size_t>("didyoumeandifference", "4");
+ Anope::string similar;
+ auto umessage = message.upper();
+ for (const auto &[command, info] : source.service->commands)
+ {
+ if (info.hide || command == message)
+ continue; // Don't suggest a hidden alias or a missing command.
+
+ size_t dist = Anope::Distance(umessage, command);
+ if (dist < distance)
+ {
+ distance = dist;
+ similar = command;
+ }
+ }
+
+ bool has_help = source.service->commands.find("HELP") != source.service->commands.end();
+ if (has_help && similar.empty())
+ {
+ source.Reply(_("Unknown command \002%s\002. \"%s HELP\" for help."), message.c_str(),
+ source.service->GetQueryCommand().c_str());
+ }
+ else if (has_help)
+ {
+ source.Reply(_("Unknown command \002%s\002. Did you mean \002%s\002? \"%s HELP\" for help."),
+ message.c_str(), similar.c_str(), source.service->GetQueryCommand().c_str());
+ }
+ else if (similar.empty())
+ {
+ source.Reply(_("Unknown command \002%s\002. Did you mean \002%s\002?"), message.c_str(), similar.c_str());
+ }
+ else
+ {
+ source.Reply(_("Unknown command \002%s\002."), message.c_str());
+ }
+ }
}
void Command::Run(CommandSource &source, const Anope::string &message)
{
std::vector<Anope::string> params;
spacesepstream(message).GetTokens(params);
- bool has_help = source.service->commands.find("HELP") != source.service->commands.end();
CommandInfo::map::const_iterator it = source.service->commands.end();
unsigned count = 0;
@@ -216,10 +280,7 @@ 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());
- else
- source.Reply(_("Unknown command \002%s\002."), message.c_str());
+ HandleUnknownCommand(source, message);
return;
}
@@ -227,10 +288,7 @@ void Command::Run(CommandSource &source, const Anope::string &message)
ServiceReference<Command> c("Command", 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());
- else
- source.Reply(_("Unknown command \002%s\002."), message.c_str());
+ HandleUnknownCommand(source, message);
Log(source.service) << "Command " << it->first << " exists on me, but its service " << info.name << " was not found!";
return;
}
@@ -288,19 +346,14 @@ void Command::Run(CommandSource &source, const Anope::string &cmdname, const Com
FOREACH_MOD(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, BotInfo *&bot, Anope::string &name)
{
bot = NULL;
- for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
+ for (const auto &[_, bi] : *BotListByNick)
{
- BotInfo *bi = it->second;
-
- for (CommandInfo::map::const_iterator cit = bi->commands.begin(), cit_end = bi->commands.end(); cit != cit_end; ++cit)
+ for (const auto &[c_name, info] : bi->commands)
{
- const Anope::string &c_name = cit->first;
- const CommandInfo &info = cit->second;
-
if (info.name != command_service)
continue;
diff --git a/src/config.cpp b/src/config.cpp
index 73820b77d..94dd8d222 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -17,11 +17,15 @@
#include "channels.h"
#include "hashcomp.h"
+#include <stack>
+#include <stdexcept>
+
using Configuration::File;
using Configuration::Conf;
using Configuration::Internal::Block;
+using Configuration::Uplink;
-File ServicesConf("services.conf", false); // Services configuration file name
+File ServicesConf("anope.conf", false); // Configuration file name
Conf *Config = NULL;
Block Block::EmptyBlock("");
@@ -40,17 +44,17 @@ int Block::CountBlock(const Anope::string &bname) const
return blocks.count(bname);
}
-const Block* Block::GetBlock(const Anope::string &bname, int num) const
+const Block &Block::GetBlock(const Anope::string &bname, int num) const
{
std::pair<block_map::const_iterator, block_map::const_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 &EmptyBlock;
+ return it.first->second;
+ return EmptyBlock;
}
-Block* Block::GetMutableBlock(const Anope::string &bname, int num)
+Block *Block::GetMutableBlock(const Anope::string &bname, int num)
{
std::pair<block_map::iterator, block_map::iterator> it = blocks.equal_range(bname);
@@ -66,12 +70,12 @@ bool Block::Set(const Anope::string &tag, const Anope::string &value)
return true;
}
-const Block::item_map* Block::GetItems() const
+const Block::item_map &Block::GetItems() const
{
- return &items;
+ return items;
}
-template<> const Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const
+template<> const Anope::string Block::Get(const Anope::string &tag, const Anope::string &def) const
{
Anope::map<Anope::string>::const_iterator it = items.find(tag);
if (it != items.end())
@@ -118,22 +122,22 @@ template<typename T> static void ValidateNotZero(const Anope::string &block, con
Conf::Conf() : Block("")
{
ReadTimeout = 0;
- UsePrivmsg = DefPrivmsg = false;
+ DefPrivmsg = false;
this->LoadConf(ServicesConf);
for (int i = 0; i < this->CountBlock("include"); ++i)
{
- const Block *include = this->GetBlock("include", i);
+ const 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<const Anope::string>("type"),
+ &file = include.Get<const Anope::string>("name");
File f(file, type == "executable");
this->LoadConf(f);
}
- FOREACH_MOD(OnReload, (this));
+ FOREACH_MOD(OnReload, (*this));
/* Check for modified values that aren't allowed to be modified */
if (Config)
@@ -154,78 +158,92 @@ Conf::Conf() : Block("")
{"networkinfo", "chanlen"},
};
- 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))
- throw ConfigException("<" + noreload[i].block + ":" + noreload[i].name + "> can not be modified once set");
+ for (const auto &tag : noreload)
+ {
+ if (this->GetBlock(tag.block).Get<const Anope::string>(tag.name) != Config->GetBlock(tag.block).Get<const Anope::string>(tag.name))
+ throw ConfigException("<" + tag.block + ":" + tag.name + "> can not be modified once set");
+ }
}
- const Block *serverinfo = this->GetBlock("serverinfo"), *options = this->GetBlock("options"),
- *mail = this->GetBlock("mail"), *networkinfo = this->GetBlock("networkinfo");
+ const Block &serverinfo = this->GetBlock("serverinfo"), &options = this->GetBlock("options"),
+ &mail = this->GetBlock("mail"), &networkinfo = this->GetBlock("networkinfo");
- const Anope::string &servername = serverinfo->Get<Anope::string>("name");
+ const Anope::string &servername = serverinfo.Get<Anope::string>("name");
ValidateNotEmptyOrSpaces("serverinfo", "name", servername);
if (servername.find(' ') != Anope::string::npos || servername.find('.') == Anope::string::npos)
throw ConfigException("serverinfo:name is not a valid server 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", "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"));
- ValidateNotZero("options", "readtimeout", options->Get<time_t>("readtimeout"));
+ ValidateNotZero("options", "readtimeout", options.Get<time_t>("readtimeout"));
- ValidateNotZero("networkinfo", "nicklen", networkinfo->Get<unsigned>("nicklen"));
- ValidateNotZero("networkinfo", "userlen", networkinfo->Get<unsigned>("userlen"));
- ValidateNotZero("networkinfo", "hostlen", networkinfo->Get<unsigned>("hostlen"));
- ValidateNotZero("networkinfo", "chanlen", networkinfo->Get<unsigned>("chanlen"));
+ ValidateNotZero("networkinfo", "nicklen", networkinfo.Get<unsigned>("nicklen", "1"));
+ ValidateNotZero("networkinfo", "userlen", networkinfo.Get<unsigned>("userlen", "1"));
+ ValidateNotZero("networkinfo", "hostlen", networkinfo.Get<unsigned>("hostlen", "1"));
+ ValidateNotZero("networkinfo", "chanlen", networkinfo.Get<unsigned>("chanlen", "1"));
- spacesepstream(options->Get<const Anope::string>("ulineservers")).GetTokens(this->Ulines);
+ spacesepstream(options.Get<const Anope::string>("ulineservers")).GetTokens(this->Ulines);
- if (mail->Get<bool>("usemail"))
+ 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]));
+ Anope::string check[] = { "sendfrom", "registration_subject", "registration_message", "emailchange_subject", "emailchange_message", "memo_subject", "memo_message" };
+ for (const auto &field : check)
+ ValidateNotEmpty("mail", field, mail.Get<const Anope::string>(field));
}
- this->ReadTimeout = options->Get<time_t>("readtimeout");
- this->UsePrivmsg = options->Get<bool>("useprivmsg");
- this->UseStrictPrivmsg = options->Get<bool>("usestrictprivmsg");
- this->StrictPrivmsg = !UseStrictPrivmsg ? "/msg " : "/";
+ this->ReadTimeout = options.Get<time_t>("readtimeout");
+ this->ServiceAlias = options.Get<bool>("servicealias");
{
std::vector<Anope::string> defaults;
- spacesepstream(this->GetModule("nickserv")->Get<const Anope::string>("defaults")).GetTokens(defaults);
+ spacesepstream(this->GetModule("nickserv").Get<const 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->TimeoutCheck = options->Get<time_t>("timeoutcheck");
- this->NickChars = networkinfo->Get<Anope::string>("nick_chars");
+ this->DefLanguage = options.Get<const Anope::string>("defaultlanguage");
+ this->TimeoutCheck = options.Get<time_t>("timeoutcheck");
+ this->NickChars = networkinfo.Get<Anope::string>("nick_chars");
for (int i = 0; i < this->CountBlock("uplink"); ++i)
{
- const Block *uplink = this->GetBlock("uplink", i);
-
- const Anope::string &host = uplink->Get<const 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 Block &uplink = this->GetBlock("uplink", i);
+
+ int protocol;
+ const Anope::string &protocolstr = uplink.Get<const Anope::string>("protocol", "ipv4");
+ if (protocolstr == "ipv4")
+ protocol = AF_INET;
+ else if (protocolstr == "ipv6")
+ protocol = AF_INET6;
+ else if (protocolstr == "unix")
+ protocol = AF_UNIX;
+ else
+ throw ConfigException("uplink:protocol must be set to ipv4, ipv6, or unix");
+ const Anope::string &host = uplink.Get<const Anope::string>("host");
ValidateNotEmptyOrSpaces("uplink", "host", host);
- ValidateNotZero("uplink", "port", port);
- ValidateNotEmptyOrSpaces("uplink", "password", password);
- if (password.find(' ') != Anope::string::npos || password[0] == ':')
+ int port = 0;
+ if (protocol != AF_UNIX)
+ {
+ port = uplink.Get<int>("port");
+ ValidateNotZero("uplink", "port", port);
+ }
+
+ const Anope::string &password = uplink.Get<const Anope::string>("password");
+ ValidateNotEmptyOrSpaces("uplink", "password", password);
+ if (password[0] == ':')
throw ConfigException("uplink:password is not valid");
- this->Uplinks.push_back(Uplink(host, port, password, ipv6));
+ this->Uplinks.emplace_back(host, port, password, protocol);
}
for (int i = 0; i < this->CountBlock("module"); ++i)
{
- const Block *module = this->GetBlock("module", i);
+ const Block &module = this->GetBlock("module", i);
- const Anope::string &modname = module->Get<const Anope::string>("name");
+ const Anope::string &modname = module.Get<const Anope::string>("name");
ValidateNotEmptyOrSpaces("module", "name", modname);
@@ -234,17 +252,17 @@ Conf::Conf() : Block("")
for (int i = 0; i < this->CountBlock("opertype"); ++i)
{
- const Block *opertype = this->GetBlock("opertype", i);
+ const 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<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");
ValidateNotEmpty("opertype", "name", oname);
- OperType *ot = new OperType(oname);
+ auto *ot = new OperType(oname);
ot->modes = modes;
spacesepstream cmdstr(commands);
@@ -261,10 +279,8 @@ Conf::Conf() : Block("")
/* Strip leading ' ' after , */
if (str.length() > 1 && str[0] == ' ')
str.erase(str.begin());
- for (unsigned j = 0; j < this->MyOperTypes.size(); ++j)
+ for (auto *ot2 : this->MyOperTypes)
{
- OperType *ot2 = this->MyOperTypes[j];
-
if (ot2->GetName().equals_ci(str))
{
Log() << "Inheriting commands and privs from " << ot2->GetName() << " to " << ot->GetName();
@@ -279,48 +295,51 @@ Conf::Conf() : Block("")
for (int i = 0; i < this->CountBlock("oper"); ++i)
{
- const Block *oper = this->GetBlock("oper", i);
+ const 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");
+ 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");
ValidateNotEmptyOrSpaces("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];
+ for (auto *opertype : this->MyOperTypes)
+ {
+ if (opertype->GetName() == type)
+ ot = opertype;
+ }
if (ot == NULL)
throw ConfigException("Oper block for " + nname + " has invalid oper type " + type);
- Oper *o = new Oper(nname, ot);
+ auto *o = new Oper(nname, ot);
o->require_oper = require_oper;
o->password = password;
- o->certfp = certfp;
+ spacesepstream(certfp).GetTokens(o->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 (const auto &[_, bi] : *BotListByNick)
+ bi->conf = false;
for (int i = 0; i < this->CountBlock("service"); ++i)
{
- const Block *service = this->GetBlock("service", i);
+ const 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");
+ 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"),
+ &alias = service.Get<const Anope::string>("alias", nick.upper());
ValidateNotEmptyOrSpaces("service", "nick", nick);
ValidateNotEmptyOrSpaces("service", "user", user);
@@ -331,6 +350,8 @@ Conf::Conf() : Block("")
BotInfo *bi = BotInfo::Find(nick, true);
if (!bi)
bi = new BotInfo(nick, user, host, gecos, modes);
+
+ bi->alias = alias;
bi->conf = true;
std::vector<Anope::string> oldchannels = bi->botchannels;
@@ -358,28 +379,29 @@ Conf::Conf() : Block("")
/* 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());
+ {
+ for (auto mode : cu->status.Modes())
+ c->RemoveMode(bi, ModeManager::FindChannelModeByChar(mode), bi->GetUID());
+ }
/* Set the new modes */
- for (unsigned j = 0; j < want_modes.length(); ++j)
+ for (char want_mode : want_modes)
{
- ChannelMode *cm = ModeManager::FindChannelModeByChar(want_modes[j]);
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(want_mode);
if (cm == NULL)
- cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_modes[j]));
+ cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_mode));
if (cm && cm->type == MODE_STATUS)
c->SetMode(bi, cm, bi->GetUID());
}
}
- for (unsigned k = 0; k < oldchannels.size(); ++k)
+ for (const auto &oldchannel : oldchannels)
{
- size_t ch = oldchannels[k].find('#');
- Anope::string chname = oldchannels[k].substr(ch != Anope::string::npos ? ch : 0);
-
+ size_t ch = oldchannel.find('#');
+ Anope::string chname = oldchannel.substr(ch != Anope::string::npos ? ch : 0);
bool found = false;
- for (unsigned j = 0; j < bi->botchannels.size(); ++j)
+ for (const auto &botchannel : bi->botchannels)
{
- ch = bi->botchannels[j].find('#');
- Anope::string ochname = bi->botchannels[j].substr(ch != Anope::string::npos ? ch : 0);
+ ch = botchannel.find('#');
+ Anope::string ochname = botchannel.substr(ch != Anope::string::npos ? ch : 0);
if (chname.equals_ci(ochname))
found = true;
@@ -399,40 +421,40 @@ Conf::Conf() : Block("")
for (int i = 0; i < this->CountBlock("log"); ++i)
{
- const Block *log = this->GetBlock("log", i);
+ const Block &log = this->GetBlock("log", i);
- int logage = log->Get<int>("logage");
- bool rawio = log->Get<bool>("rawio");
- bool debug = log->Get<bool>("debug");
+ int logage = log.Get<int>("logage");
+ bool rawio = log.Get<bool>("rawio");
+ bool debug = log.Get<bool>("debug");
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 = 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);
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 (const auto &[_, bi] : *BotListByNick)
+ bi->commands.clear();
for (int i = 0; i < this->CountBlock("command"); ++i)
{
- const Block *command = this->GetBlock("command", i);
+ const 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");
- bool hide = command->Get<bool>("hide");
+ 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");
+ bool hide = command.Get<bool>("hide");
ValidateNotEmptyOrSpaces("command", "service", service);
ValidateNotEmpty("command", "name", nname);
@@ -450,25 +472,25 @@ Conf::Conf() : Block("")
PrivilegeManager::ClearPrivileges();
for (int i = 0; i < this->CountBlock("privilege"); ++i)
{
- const Block *privilege = this->GetBlock("privilege", i);
+ const 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");
+ 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)
{
- const Block *fantasy = this->GetBlock("fantasy", i);
+ const 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");
- bool hide = fantasy->Get<bool>("hide"),
- prepend_channel = fantasy->Get<bool>("prepend_channel", "yes");
+ 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");
+ bool hide = fantasy.Get<bool>("hide"),
+ prepend_channel = fantasy.Get<bool>("prepend_channel", "yes");
ValidateNotEmpty("fantasy", "name", nname);
ValidateNotEmptyOrSpaces("fantasy", "command", service);
@@ -483,10 +505,10 @@ Conf::Conf() : Block("")
for (int i = 0; i < this->CountBlock("command_group"); ++i)
{
- const Block *command_group = this->GetBlock("command_group", i);
+ const 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<const Anope::string>("name"),
+ &description = command_group.Get<const Anope::string>("description");
CommandGroup gr;
gr.name = nname;
@@ -499,17 +521,14 @@ Conf::Conf() : Block("")
if (Config)
/* Clear existing conf opers */
- for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it)
+ for (const auto &[_, nc] : *NickCoreList)
{
- 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)
+ for (auto *o : this->Opers)
{
- Oper *o = this->Opers[i];
-
NickAlias *na = NickAlias::Find(o->name);
if (!na)
continue;
@@ -525,45 +544,47 @@ Conf::Conf() : Block("")
Log() << "Tied oper " << na->nc->display << " to type " << o->ot->GetName();
}
- if (options->Get<const Anope::string>("casemap", "ascii") == "ascii")
+ 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")
+ else if (options.Get<const Anope::string>("casemap") == "rfc1459")
Anope::casemap = std::locale(std::locale(), new Anope::rfc1459_ctype<char>());
else
{
try
{
- Anope::casemap = std::locale(options->Get<const Anope::string>("casemap").c_str());
+ Anope::casemap = std::locale(options.Get<const Anope::string>("casemap").c_str());
}
catch (const std::runtime_error &)
{
- Log() << "Unknown casemap " << options->Get<const Anope::string>("casemap") << " - casemap not changed";
+ Log() << "Unknown casemap " << options.Get<const Anope::string>("casemap") << " - casemap not changed";
}
}
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!";
}
Conf::~Conf()
{
- for (unsigned i = 0; i < MyOperTypes.size(); ++i)
- delete MyOperTypes[i];
- for (unsigned i = 0; i < Opers.size(); ++i)
- delete Opers[i];
+ for (const auto *opertype : MyOperTypes)
+ delete opertype;
+
+ for (const auto *oper : Opers)
+ delete oper;
}
void Conf::Post(Conf *old)
{
/* Apply module changes */
- for (unsigned i = 0; i < old->ModulesAutoLoad.size(); ++i)
- if (std::find(this->ModulesAutoLoad.begin(), this->ModulesAutoLoad.end(), old->ModulesAutoLoad[i]) == this->ModulesAutoLoad.end())
- ModuleManager::UnloadModule(ModuleManager::FindModule(old->ModulesAutoLoad[i]), NULL);
- for (unsigned i = 0; i < this->ModulesAutoLoad.size(); ++i)
- if (std::find(old->ModulesAutoLoad.begin(), old->ModulesAutoLoad.end(), this->ModulesAutoLoad[i]) == old->ModulesAutoLoad.end())
- ModuleManager::LoadModule(this->ModulesAutoLoad[i], NULL);
+ for (const auto &mod : old->ModulesAutoLoad)
+ {
+ if (std::find(this->ModulesAutoLoad.begin(), this->ModulesAutoLoad.end(), mod) == this->ModulesAutoLoad.end())
+ ModuleManager::UnloadModule(ModuleManager::FindModule(mod), NULL);
+ }
+
+ for (const auto &mod : this->ModulesAutoLoad)
+ {
+ if (std::find(old->ModulesAutoLoad.begin(), old->ModulesAutoLoad.end(), mod) == old->ModulesAutoLoad.end())
+ ModuleManager::LoadModule(mod, NULL);
+ }
/* Apply opertype changes, as non-conf opers still point to the old oper types */
for (unsigned i = Oper::opers.size(); i > 0; --i)
@@ -576,9 +597,11 @@ void Conf::Post(Conf *old)
OperType *ot = o->ot;
o->ot = NULL;
- for (unsigned j = 0; j < MyOperTypes.size(); ++j)
- if (ot->GetName() == MyOperTypes[j]->GetName())
- o->ot = MyOperTypes[j];
+ for (auto *opertype : MyOperTypes)
+ {
+ if (ot->GetName() == opertype->GetName())
+ o->ot = opertype;
+ }
if (o->ot == NULL)
{
@@ -597,30 +620,47 @@ void Conf::Post(Conf *old)
}
}
-Block *Conf::GetModule(Module *m)
+Anope::string Uplink::str() const
+{
+ switch (protocol)
+ {
+ case AF_INET:
+ return Anope::printf("%s:%u", this->host.c_str(), this->port);
+ case AF_INET6:
+ return Anope::printf("[%s]:%u", this->host.c_str(), this->port);
+ case AF_UNIX:
+ return this->host;
+ }
+
+ // Should never be reached.
+ return "";
+}
+
+
+Block &Conf::GetModule(const Module *m)
{
if (!m)
- return NULL;
+ return Block::EmptyBlock;
return GetModule(m->name);
}
-Block *Conf::GetModule(const Anope::string &mname)
+Block &Conf::GetModule(const Anope::string &mname)
{
std::map<Anope::string, Block *>::iterator it = modules.find(mname);
if (it != modules.end())
- return it->second;
+ return *it->second;
- Block* &block = modules[mname];
+ 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;
+ Block &b = iters.first->second;
- if (b->Get<const Anope::string>("name") == mname)
+ if (b.Get<const Anope::string>("name") == mname)
{
- block = b;
+ block = &b;
break;
}
}
@@ -637,28 +677,28 @@ BotInfo *Conf::GetClient(const Anope::string &cname)
if (it != bots.end())
return BotInfo::Find(!it->second.empty() ? it->second : cname, true);
- Block *block = GetModule(cname.lower());
- const Anope::string &client = block->Get<const Anope::string>("client");
+ Block &block = GetModule(cname.lower());
+ const Anope::string &client = block.Get<const Anope::string>("client");
bots[cname] = client;
return GetClient(cname);
}
-const Block *Conf::GetCommand(CommandSource &source)
+const Block &Conf::GetCommand(CommandSource &source)
{
const Anope::string &block_name = source.c ? "fantasy" : "command";
for (std::pair<block_map::iterator, block_map::iterator> iters = blocks.equal_range(block_name); iters.first != iters.second; ++iters.first)
{
- Block *b = &iters.first->second;
+ Block &b = iters.first->second;
- if (b->Get<Anope::string>("name") == source.command)
+ if (b.Get<Anope::string>("name") == source.command)
return b;
}
- return &Block::EmptyBlock;
+ return Block::EmptyBlock;
}
-File::File(const Anope::string &n, bool e) : name(n), executable(e), fp(NULL)
+File::File(const Anope::string &n, bool e) : name(n), executable(e)
{
}
@@ -674,7 +714,7 @@ const Anope::string &File::GetName() const
Anope::string File::GetPath() const
{
- return (this->executable ? "" : Anope::ConfigDir + "/") + this->name;
+ return this->executable ? this->name : Anope::ExpandConfig(this->name);
}
bool File::IsOpen() const
@@ -685,7 +725,7 @@ bool File::IsOpen() const
bool File::Open()
{
this->Close();
- this->fp = (this->executable ? popen(this->name.c_str(), "r") : fopen((Anope::ConfigDir + "/" + this->name).c_str(), "r"));
+ this->fp = (this->executable ? popen(GetPath().c_str(), "r") : fopen(GetPath().c_str(), "r"));
return this->fp != NULL;
}
@@ -801,12 +841,12 @@ void Conf::LoadConf(File &file)
if (block_stack.empty() || itemname.empty())
{
file.Close();
- throw ConfigException("Unexpected quoted string: " + file.GetName() + ":" + stringify(linenumber));
+ throw ConfigException("Unexpected quoted string: " + file.GetName() + ":" + Anope::ToString(linenumber));
}
if (in_word || !wordbuffer.empty())
{
file.Close();
- throw ConfigException("Unexpected quoted string (prior unhandled words): " + file.GetName() + ":" + stringify(linenumber));
+ throw ConfigException("Unexpected quoted string (prior unhandled words): " + file.GetName() + ":" + Anope::ToString(linenumber));
}
in_quote = in_word = true;
}
@@ -815,13 +855,13 @@ void Conf::LoadConf(File &file)
if (block_stack.empty())
{
file.Close();
- throw ConfigException("Config item outside of section (or stray '='): " + file.GetName() + ":" + stringify(linenumber));
+ throw ConfigException("Config item outside of section (or stray '='): " + file.GetName() + ":" + Anope::ToString(linenumber));
}
if (!itemname.empty() || wordbuffer.empty())
{
file.Close();
- throw ConfigException("Stray '=' sign or item without value: " + file.GetName() + ":" + stringify(linenumber));
+ throw ConfigException("Stray '=' sign or item without value: " + file.GetName() + ":" + Anope::ToString(linenumber));
}
in_word = false;
@@ -847,7 +887,7 @@ void Conf::LoadConf(File &file)
}
Block *b = block_stack.empty() ? this : block_stack.top();
- block_map::iterator it = b->blocks.insert(std::make_pair(wordbuffer, Configuration::Block(wordbuffer)));
+ block_map::iterator it = b->blocks.emplace(wordbuffer, Configuration::Block(wordbuffer));
b = &it->second;
b->linenum = linenumber;
block_stack.push(b);
@@ -868,7 +908,7 @@ void Conf::LoadConf(File &file)
if (!in_word && !wordbuffer.empty())
{
file.Close();
- throw ConfigException("Unexpected word: " + file.GetName() + ":" + stringify(linenumber));
+ throw ConfigException("Unexpected word: " + file.GetName() + ":" + Anope::ToString(linenumber));
}
wordbuffer += ch;
in_word = true;
@@ -895,28 +935,16 @@ void Conf::LoadConf(File &file)
if (block_stack.empty())
{
file.Close();
- throw ConfigException("Stray ';' outside of block: " + file.GetName() + ":" + stringify(linenumber));
+ throw ConfigException("Stray ';' outside of block: " + file.GetName() + ":" + Anope::ToString(linenumber));
}
Block *b = block_stack.top();
-
if (b)
- Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << b->name << "' '" << itemname << "' set to '" << wordbuffer << "'";
-
- /* Check defines */
- for (int i = 0; i < this->CountBlock("define"); ++i)
{
- const Block *define = this->GetBlock("define", i);
-
- const Anope::string &dname = define->Get<const Anope::string>("name");
-
- if (dname == wordbuffer && define != b)
- wordbuffer = define->Get<const Anope::string>("value");
+ Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << b->name << "' '" << itemname << "' set to '" << wordbuffer << "'";
+ b->items[itemname] = ReplaceVars(wordbuffer, file, linenumber);
}
- if (b)
- b->items[itemname] = wordbuffer;
-
wordbuffer.clear();
itemname.clear();
}
@@ -926,7 +954,7 @@ void Conf::LoadConf(File &file)
if (block_stack.empty())
{
file.Close();
- throw ConfigException("Stray '}': " + file.GetName() + ":" + stringify(linenumber));
+ throw ConfigException("Stray '}': " + file.GetName() + ":" + Anope::ToString(linenumber));
}
block_stack.pop();
@@ -946,8 +974,57 @@ void Conf::LoadConf(File &file)
if (!block_stack.empty())
{
if (block_stack.top())
- throw ConfigException("Unterminated block at end of file: " + file.GetName() + ". Block was opened on line " + stringify(block_stack.top()->linenum));
+ throw ConfigException("Unterminated block at end of file: " + file.GetName() + ". Block was opened on line " + Anope::ToString(block_stack.top()->linenum));
else
throw ConfigException("Unterminated commented block at end of file: " + file.GetName());
}
}
+
+Anope::string Conf::ReplaceVars(const Anope::string &str, const File &file, int linenumber)
+{
+ Anope::string ret;
+ for (auto it = str.begin(); it != str.end(); )
+ {
+ if (*it != '$')
+ {
+ ret.push_back(*it++);
+ continue;
+ }
+
+ if (++it == str.end() || *it != '{')
+ continue;
+
+ it++;
+ Anope::string var;
+ while (it != str.end() && *it != '}')
+ var.push_back(*it++);
+
+ if (it == str.end())
+ throw ConfigException("Unterminated variable: " + file.GetName() + ":" + Anope::ToString(linenumber));
+
+ it++;
+ if (var.compare(0, 4, "env.", 4) == 0)
+ {
+ // This is an environment variable rather than a defined variable
+ const char* envstr = getenv(var.c_str() + 4);
+ if (envstr && envstr)
+ ret.append(envstr);
+ continue;
+ }
+
+ for (int i = 0; i < this->CountBlock("define"); ++i)
+ {
+ const auto &define = this->GetBlock("define", i);
+ const auto defname = define.Get<const Anope::string>("name");
+ if (defname == var)
+ {
+ ret.append(define.Get<const Anope::string>("value"));
+ break;
+ }
+ }
+ }
+
+ if (!str.equals_cs(ret))
+ Log(LOG_DEBUG) << "Expanded \"" << str << "\" to \"" << ret << "\"";
+ return ret;
+}
diff --git a/src/extensible.cpp b/src/extensible.cpp
index 844130f30..f2d7ff872 100644
--- a/src/extensible.cpp
+++ b/src/extensible.cpp
@@ -52,15 +52,14 @@ void Extensible::ExtensibleSerialize(const Extensible *e, const Serializable *s,
void Extensible::ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data)
{
- for (std::set<ExtensibleBase *>::iterator it = extensible_items.begin(); it != extensible_items.end(); ++it)
+ for (auto *extensible_item : extensible_items)
{
- ExtensibleBase *eb = *it;
- eb->ExtensibleUnserialize(e, s, data);
+ extensible_item->ExtensibleUnserialize(e, s, data);
}
}
template<>
-bool* Extensible::Extend(const Anope::string &name, const bool &what)
+bool *Extensible::Extend(const Anope::string &name, const bool &what)
{
ExtensibleRef<bool> ref(name);
if (ref)
diff --git a/src/hashcomp.cpp b/src/hashcomp.cpp
index 3abaa388e..da12be638 100644
--- a/src/hashcomp.cpp
+++ b/src/hashcomp.cpp
@@ -91,7 +91,7 @@ bool ci::less::operator()(const Anope::string &s1, const Anope::string &s2) cons
return s1.ci_str().compare(s2.ci_str()) < 0;
}
-sepstream::sepstream(const Anope::string &source, char separator, bool ae) : tokens(source), sep(separator), pos(0), allow_empty(ae)
+sepstream::sepstream(const Anope::string &source, char separator, bool ae) : tokens(source), sep(separator), allow_empty(ae)
{
}
@@ -106,7 +106,7 @@ bool sepstream::GetToken(Anope::string &token)
if (!this->allow_empty)
{
this->pos = this->tokens.find_first_not_of(this->sep, this->pos);
- if (this->pos == std::string::npos)
+ if (this->pos == Anope::string::npos)
{
this->pos = this->tokens.length() + 1;
token.clear();
@@ -115,7 +115,7 @@ bool sepstream::GetToken(Anope::string &token)
}
size_t p = this->tokens.find(this->sep, this->pos);
- if (p == std::string::npos)
+ if (p == Anope::string::npos)
p = this->tokens.length();
token = this->tokens.substr(this->pos, p - this->pos);
@@ -152,7 +152,7 @@ bool sepstream::GetTokenRemainder(Anope::string &token, int num)
return false;
}
-const Anope::string sepstream::GetRemaining()
+Anope::string sepstream::GetRemaining()
{
return !this->StreamEnd() ? this->tokens.substr(this->pos) : "";
}
diff --git a/src/init.cpp b/src/init.cpp
index df229ce72..757346e0d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -23,13 +23,18 @@
#include <sys/wait.h>
#include <sys/stat.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <pwd.h>
+#include <cerrno>
#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
#endif
+#include <thread>
-Anope::string Anope::ConfigDir = "conf", Anope::DataDir = "data", Anope::ModuleDir = "lib", Anope::LocaleDir = "locale", Anope::LogDir = "logs";
+Anope::string Anope::ConfigDir = DEFAULT_CONF_DIR;
+Anope::string Anope::DataDir = DEFAULT_DATA_DIR;
+Anope::string Anope::LocaleDir = DEFAULT_LOCALE_DIR;
+Anope::string Anope::LogDir = DEFAULT_LOG_DIR;
+Anope::string Anope::ModuleDir = DEFAULT_MODULE_DIR;
/* Vector of pairs of command line arguments and their params */
static std::vector<std::pair<Anope::string, Anope::string> > CommandLineArguments;
@@ -57,7 +62,7 @@ static void ParseCommandLineArguments(int ac, char **av)
if (option.empty())
continue;
- CommandLineArguments.push_back(std::make_pair(option, param));
+ CommandLineArguments.emplace_back(option, param);
}
}
@@ -71,11 +76,11 @@ static bool GetCommandLineArgument(const Anope::string &name, char shortname, An
{
param.clear();
- for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = CommandLineArguments.begin(), it_end = CommandLineArguments.end(); it != it_end; ++it)
+ for (const auto &[argument, value] : CommandLineArguments)
{
- if (it->first.equals_ci(name) || (it->first.length() == 1 && it->first[0] == shortname))
+ if (argument.equals_ci(name) || (argument.length() == 1 && argument[0] == shortname))
{
- param = it->second;
+ param = value;
return true;
}
}
@@ -131,7 +136,7 @@ void Anope::HandleSignal()
try
{
- Configuration::Conf *new_config = new Configuration::Conf();
+ auto *new_config = new Configuration::Conf();
Configuration::Conf *old = Config;
Config = new_config;
Config->Post(old);
@@ -147,14 +152,19 @@ void Anope::HandleSignal()
case SIGINT:
#ifndef _WIN32
Log() << "Received " << strsignal(Signal) << " signal (" << Signal << "), exiting.";
- Anope::QuitReason = Anope::string("Services terminating via signal ") + strsignal(Signal) + " (" + stringify(Signal) + ")";
+ Anope::QuitReason = Anope::string("Services terminating via signal ") + strsignal(Signal) + " (" + Anope::ToString(Signal) + ")";
#else
Log() << "Received signal " << Signal << ", exiting.";
- Anope::QuitReason = Anope::string("Services terminating via signal ") + stringify(Signal);
+ Anope::QuitReason = Anope::string("Services terminating via signal ") + Anope::ToString(Signal);
#endif
Anope::Quitting = true;
Anope::SaveDatabases();
break;
+#ifndef _WIN32
+ case SIGUSR1:
+ Anope::SaveDatabases();
+ break;
+#endif
}
Signal = 0;
@@ -193,8 +203,10 @@ static void InitSignals()
sa.sa_handler = SignalHandler;
+#ifndef _WIN32
+ sigaction(SIGUSR1, &sa, NULL);
+#endif
sigaction(SIGHUP, &sa, NULL);
-
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
@@ -210,62 +222,60 @@ static void InitSignals()
static void remove_pidfile()
{
- remove(Config->GetBlock("serverinfo")->Get<const Anope::string>("pid").c_str());
+ auto pidfile = Anope::ExpandData(Config->GetBlock("serverinfo").Get<const Anope::string>("pid"));
+ if (!pidfile.empty())
+ remove(pidfile.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");
- if (pidfile)
- {
+ auto pidfile = Anope::ExpandData(Config->GetBlock("serverinfo").Get<const Anope::string>("pid"));
+ if (Anope::NoPID || pidfile.empty())
+ return;
+
+ std::ofstream stream(pidfile.str());
+ if (!stream.is_open())
+ throw CoreException("Can not write to PID file " + pidfile);
#ifdef _WIN32
- fprintf(pidfile, "%d\n", static_cast<int>(GetCurrentProcessId()));
+ stream << GetCurrentProcessId() << std::endl;
#else
- fprintf(pidfile, "%d\n", static_cast<int>(getpid()));
+ stream << getpid() << std::endl;
#endif
- fclose(pidfile);
- atexit(remove_pidfile);
- }
- else
- throw CoreException("Can not write to PID file " + Config->GetBlock("serverinfo")->Get<const Anope::string>("pid"));
+ atexit(remove_pidfile);
}
static void setuidgid()
{
#ifndef _WIN32
- Configuration::Block *options = Config->GetBlock("options");
+ Configuration::Block &options = Config->GetBlock("options");
uid_t uid = -1;
gid_t gid = -1;
- if (!options->Get<const Anope::string>("user").empty())
+ if (!options.Get<const Anope::string>("user").empty())
{
errno = 0;
- struct passwd *u = getpwnam(options->Get<const Anope::string>("user").c_str());
+ struct passwd *u = getpwnam(options.Get<const Anope::string>("user").c_str());
if (u == NULL)
- Log() << "Unable to setuid to " << options->Get<const Anope::string>("user") << ": " << Anope::LastError();
+ Log() << "Unable to setuid to " << options.Get<const Anope::string>("user") << ": " << Anope::LastError();
else
uid = u->pw_uid;
}
- if (!options->Get<const Anope::string>("group").empty())
+ if (!options.Get<const Anope::string>("group").empty())
{
errno = 0;
- struct group *g = getgrnam(options->Get<const Anope::string>("group").c_str());
+ struct group *g = getgrnam(options.Get<const Anope::string>("group").c_str());
if (g == NULL)
- Log() << "Unable to setgid to " << options->Get<const Anope::string>("group") << ": " << Anope::LastError();
+ Log() << "Unable to setgid to " << options.Get<const Anope::string>("group") << ": " << Anope::LastError();
else
gid = g->gr_gid;
}
- for (unsigned i = 0; i < Config->LogInfos.size(); ++i)
+ for (const auto &li : Config->LogInfos)
{
- LogInfo& li = Config->LogInfos[i];
-
- for (unsigned j = 0; j < li.logfiles.size(); ++j)
+ for (const auto *lf : li.logfiles)
{
- LogFile* lf = li.logfiles[j];
-
errno = 0;
if (chown(lf->filename.c_str(), uid, gid) != 0)
Log() << "Unable to change the ownership of " << lf->filename << " to " << uid << "/" << gid << ": " << Anope::LastError();
@@ -275,27 +285,30 @@ 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();
+ Log() << "Unable to setgid to " << options.Get<const Anope::string>("group") << ": " << Anope::LastError();
else
- Log() << "Successfully set group to " << options->Get<const Anope::string>("group");
+ Log() << "Successfully set group to " << options.Get<const 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();
+ Log() << "Unable to setuid to " << options.Get<const Anope::string>("user") << ": " << Anope::LastError();
else
- Log() << "Successfully set user to " << options->Get<const Anope::string>("user");
+ Log() << "Successfully set user to " << options.Get<const Anope::string>("user");
}
#endif
}
-void Anope::Init(int ac, char **av)
+bool Anope::Init(int ac, char **av)
{
/* Set file creation mask and group ID. */
#if defined(DEFUMASK) && HAVE_UMASK
umask(DEFUMASK);
#endif
+ Anope::UpdateTime();
+ Anope::StartTime = Anope::CurTime;
+
Serialize::RegisterTypes();
/* Parse command line arguments */
@@ -304,7 +317,8 @@ void Anope::Init(int ac, char **av)
if (GetCommandLineArgument("version", 'v'))
{
Log(LOG_TERMINAL) << "Anope-" << Anope::Version() << " -- " << Anope::VersionBuildString();
- throw CoreException();
+ Anope::ReturnValue = EXIT_SUCCESS;
+ return false;
}
if (GetCommandLineArgument("help", 'h'))
@@ -318,10 +332,11 @@ void Anope::Init(int ac, char **av)
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) << " --logdir=log directory";
+ Log(LOG_TERMINAL) << " --moduledir=module directory";
Log(LOG_TERMINAL) << "-e, --noexpire";
Log(LOG_TERMINAL) << "-n, --nofork";
+ Log(LOG_TERMINAL) << "-p, --nopid";
Log(LOG_TERMINAL) << " --nothird";
Log(LOG_TERMINAL) << " --protocoldebug";
Log(LOG_TERMINAL) << "-r, --readonly";
@@ -330,7 +345,8 @@ void Anope::Init(int ac, char **av)
Log(LOG_TERMINAL) << "";
Log(LOG_TERMINAL) << "Further support is available from https://www.anope.org/";
Log(LOG_TERMINAL) << "Or visit us on IRC at irc.teranova.net #anope";
- throw CoreException();
+ Anope::ReturnValue = EXIT_SUCCESS;
+ return false;
}
if (GetCommandLineArgument("nofork", 'n'))
@@ -348,6 +364,9 @@ void Anope::Init(int ac, char **av)
if (GetCommandLineArgument("nothird"))
Anope::NoThird = true;
+ if (GetCommandLineArgument("nopid", 'p'))
+ Anope::NoPID = true;
+
if (GetCommandLineArgument("noexpire", 'e'))
Anope::NoExpire = true;
@@ -359,7 +378,7 @@ void Anope::Init(int ac, char **av)
{
if (!arg.empty())
{
- int level = arg.is_number_only() ? convertTo<int>(arg) : -1;
+ auto level = Anope::Convert<int>(arg, -1);
if (level > 0)
Anope::Debug = level;
else
@@ -397,10 +416,10 @@ void Anope::Init(int ac, char **av)
Anope::LocaleDir = arg;
}
- if (GetCommandLineArgument("modulesdir", 0, arg))
+ if (GetCommandLineArgument("moduledir", 0, arg))
{
if (arg.empty())
- throw CoreException("The --modulesdir option requires a path");
+ throw CoreException("The --moduledir option requires a path");
Anope::ModuleDir = arg;
}
@@ -411,24 +430,18 @@ void Anope::Init(int ac, char **av)
Anope::LogDir = arg;
}
- /* Chdir to Services data directory. */
- if (chdir(Anope::ServicesDir.c_str()) < 0)
+ Log(LOG_TERMINAL) << "Anope " << Anope::Version() << ", " << Anope::VersionBuildString();
+
+ /* Chdir to Anope data directory. */
+ Log() << "Moving to " << Anope::ServicesDir;
+ if (chdir(Anope::ServicesDir.c_str()) != 0)
{
throw CoreException("Unable to chdir to " + Anope::ServicesDir + ": " + Anope::LastError());
}
- Log(LOG_TERMINAL) << "Anope " << Anope::Version() << ", " << Anope::VersionBuildString();
-
-#ifdef _WIN32
- if (!SupportedWindowsVersion())
- throw CoreException(GetWindowsVersion() + " is not a supported version of Windows");
-#endif
-
-#ifdef _WIN32
- Log(LOG_TERMINAL) << "Using configuration file " << Anope::ConfigDir << "\\" << ServicesConf.GetName();
-#else
- Log(LOG_TERMINAL) << "Using configuration file " << Anope::ConfigDir << "/" << ServicesConf.GetName();
+ Log(LOG_TERMINAL) << "Using configuration file " << Anope::ExpandConfig(ServicesConf.GetName());
+#ifndef _WIN32
/* Fork to background */
if (!Anope::NoFork)
{
@@ -453,7 +466,7 @@ void Anope::Init(int ac, char **av)
sigemptyset(&mask);
sigsuspend(&mask);
- exit(Anope::ReturnValue);
+ return false;
}
else if (i == -1)
{
@@ -479,7 +492,7 @@ 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) << "*** Support resources: Read through the anope.conf self-contained";
Log(LOG_TERMINAL) << "*** documentation. Read the documentation files found in the 'docs'";
Log(LOG_TERMINAL) << "*** folder. Visit our portal located at https://www.anope.org/. Join";
Log(LOG_TERMINAL) << "*** our support channel on /server irc.teranova.net channel #anope.";
@@ -487,11 +500,11 @@ void Anope::Init(int ac, char **av)
}
/* 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)
+ 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 (const auto &[_, bi] : *BotListByNick)
{
- it->second->server = Me;
+ bi->server = Me;
++Me->users;
}
@@ -503,27 +516,23 @@ void Anope::Init(int ac, char **av)
/* Initialize multi-language support */
Language::InitLanguages();
- /* Initialize random number generator */
- block = Config->GetBlock("options");
- srand(block->Get<unsigned>("seed") ^ time(NULL));
-
/* load modules */
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<const Anope::string>("name"), NULL);
#ifndef _WIN32
/* If we're root, issue a warning now */
if (!getuid() && !getgid())
{
/* 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())
+ Configuration::Block &options = Config->GetBlock("options");
+ if (options.Get<const 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;
std::cerr << " as the root superuser." << std::endl;
- sleep(3);
+ std::this_thread::sleep_for(std::chrono::seconds(3));
}
}
@@ -532,14 +541,17 @@ void Anope::Init(int ac, char **av)
setuidgid();
#endif
- Module *protocol = ModuleManager::FindFirstOf(PROTOCOL);
- if (protocol == NULL)
+ auto *encryption = ModuleManager::FindFirstOf(ENCRYPTION);
+ if (!encryption)
+ throw CoreException("You must load a non-deprecated encryption module!");
+
+ if (!IRCD)
throw CoreException("You must load a protocol module!");
/* Write our PID to the PID file. */
write_pidfile();
- Log() << "Using IRCd protocol " << protocol->name;
+ Log(LOG_TERMINAL) << "Using IRCd protocol " << IRCD->GetProtocolName() << " (" << IRCD->owner->name << ")";
/* Auto assign sid if applicable */
if (IRCD->RequiresID)
@@ -547,8 +559,8 @@ 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 (const auto &[_, bi] : *BotListByNick)
+ bi->GenerateUID();
}
/* Load up databases */
@@ -560,8 +572,9 @@ void Anope::Init(int ac, char **av)
FOREACH_MOD(OnPostInit, ());
- for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
- it->second->Sync();
+ for (const auto &[_, ci] : ChannelList)
+ ci->Sync();
Serialize::CheckTypes();
+ return true;
}
diff --git a/src/language.cpp b/src/language.cpp
index cdcf4afa0..440461133 100644
--- a/src/language.cpp
+++ b/src/language.cpp
@@ -15,7 +15,7 @@
#include "config.h"
#include "language.h"
-#if GETTEXT_FOUND
+#if HAVE_LOCALIZATION
# include <libintl.h>
#endif
@@ -24,7 +24,7 @@ std::vector<Anope::string> Language::Domains;
void Language::InitLanguages()
{
-#if GETTEXT_FOUND
+#if HAVE_LOCALIZATION
Log(LOG_DEBUG) << "Initializing Languages...";
Languages.clear();
@@ -36,7 +36,7 @@ void Language::InitLanguages()
setlocale(LC_ALL, "");
- spacesepstream sep(Config->GetBlock("options")->Get<const Anope::string>("languages"));
+ spacesepstream sep(Config->GetBlock("options").Get<const Anope::string>("languages"));
Anope::string language;
while (sep.GetToken(language))
{
@@ -73,12 +73,67 @@ const char *Language::Translate(const NickCore *nc, const char *string)
return Translate(nc ? nc->language.c_str() : "", string);
}
-#if GETTEXT_FOUND
+const char *Language::Translate(int count, const char *singular, const char *plural)
+{
+ return Translate("", count, singular, plural);
+}
+
+const char *Language::Translate(User *u, int count, const char *singular, const char *plural)
+{
+ if (u && u->IsIdentified())
+ return Translate(u->Account(), count, singular, plural);
+ else
+ return Translate("", count, singular, plural);
+}
+
+const char *Language::Translate(const NickCore *nc, int count, const char *singular, const char *plural)
+{
+ return Translate(nc ? nc->language.c_str() : "", count, singular, plural);
+}
+
+#if HAVE_LOCALIZATION
#if defined(__GLIBC__) && defined(__USE_GNU_GETTEXT)
extern "C" int _nl_msg_cat_cntr;
#endif
+namespace
+{
+ void PreTranslate(const char* lang)
+ {
+#if defined(__GLIBC__) && defined(__USE_GNU_GETTEXT)
+ ++_nl_msg_cat_cntr;
+#endif
+
+#ifdef _WIN32
+ SetThreadLocale(MAKELCID(MAKELANGID(WindowsGetLanguage(lang), SUBLANG_DEFAULT), SORT_DEFAULT));
+#else
+ /* First, set LANG and LANGUAGE env variables.
+ * Some systems (Debian) don't care about this, so we must setlocale LC_ALL as well.
+ * BUT if this call fails because the LANGUAGE env variable is set, setlocale resets
+ * the locale to "C", which short circuits gettext and causes it to fail on systems that
+ * use the LANGUAGE env variable. We must reset the locale to en_US (or, anything not
+ * C or POSIX) then.
+ */
+ setenv("LANG", lang, 1);
+ setenv("LANGUAGE", lang, 1);
+ if (setlocale(LC_ALL, lang) == NULL)
+ setlocale(LC_ALL, "en_US");
+#endif
+ }
+
+ void PostTranslate()
+ {
+#ifdef _WIN32
+ SetThreadLocale(MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT));
+#else
+ unsetenv("LANGUAGE");
+ unsetenv("LANG");
+ setlocale(LC_ALL, "");
+#endif
+ }
+}
+
const char *Language::Translate(const char *lang, const char *string)
{
if (!string || !*string)
@@ -87,36 +142,31 @@ const char *Language::Translate(const char *lang, const char *string)
if (!lang || !*lang)
lang = Config->DefLanguage.c_str();
-#if defined(__GLIBC__) && defined(__USE_GNU_GETTEXT)
- ++_nl_msg_cat_cntr;
-#endif
+ PreTranslate(lang);
-#ifdef _WIN32
- SetThreadLocale(MAKELCID(MAKELANGID(WindowsGetLanguage(lang), SUBLANG_DEFAULT), SORT_DEFAULT));
-#else
- /* First, set LANG and LANGUAGE env variables.
- * Some systems (Debian) don't care about this, so we must setlocale LC_ALL as well.
- * BUT if this call fails because the LANGUAGE env variable is set, setlocale resets
- * the locale to "C", which short circuits gettext and causes it to fail on systems that
- * use the LANGUAGE env variable. We must reset the locale to en_US (or, anything not
- * C or POSIX) then.
- */
- setenv("LANG", lang, 1);
- setenv("LANGUAGE", lang, 1);
- if (setlocale(LC_ALL, lang) == NULL)
- setlocale(LC_ALL, "en_US");
-#endif
const char *translated_string = dgettext("anope", string);
for (unsigned i = 0; translated_string == string && i < Domains.size(); ++i)
translated_string = dgettext(Domains[i].c_str(), string);
-#ifdef _WIN32
- SetThreadLocale(MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT));
-#else
- unsetenv("LANGUAGE");
- unsetenv("LANG");
- setlocale(LC_ALL, "");
-#endif
+ PostTranslate();
+ return translated_string;
+}
+
+const char *Language::Translate(const char *lang, int count, const char *singular, const char *plural)
+{
+ if (!singular || !*singular || !plural || !*plural)
+ return "";
+
+ if (!lang || !*lang)
+ lang = Config->DefLanguage.c_str();
+
+ PreTranslate(lang);
+
+ const char *translated_string = dngettext("anope", singular, plural, count);
+ for (unsigned i = 0; (translated_string == singular || translated_string == plural) && i < Domains.size(); ++i)
+ translated_string = dngettext(Domains[i].c_str(), singular, plural, count);
+
+ PostTranslate();
return translated_string;
}
#else
@@ -124,4 +174,10 @@ const char *Language::Translate(const char *lang, const char *string)
{
return string != NULL ? string : "";
}
+const char *Language::Translate(const char *lang, int count, const char *singular, const char *plural)
+{
+ return Language::Translate("", count == 1 ? singular : plural);
+}
#endif
+
+
diff --git a/src/logger.cpp b/src/logger.cpp
index c2e250831..28614d9f1 100644
--- a/src/logger.cpp
+++ b/src/logger.cpp
@@ -29,20 +29,15 @@
static Anope::string GetTimeStamp()
{
char tbuf[256];
- time_t t;
- if (time(&t) < 0)
- t = Anope::CurTime;
-
- tm tm = *localtime(&t);
+ Anope::UpdateTime();
+ auto tm = *localtime(&Anope::CurTime);
if (Anope::Debug)
{
char *s;
- struct timeval tv;
- gettimeofday(&tv, NULL);
strftime(tbuf, sizeof(tbuf) - 1, "[%b %d %H:%M:%S", &tm);
s = tbuf + strlen(tbuf);
- s += snprintf(s, sizeof(tbuf) - (s - tbuf), ".%06d", static_cast<int>(tv.tv_usec));
+ s += snprintf(s, sizeof(tbuf) - (s - tbuf), ".%06lld", static_cast<long long>(Anope::CurTimeNs / 1000));
strftime(s, sizeof(tbuf) - (s - tbuf) - 1, " %Y]", &tm);
}
else
@@ -57,7 +52,7 @@ static inline Anope::string CreateLogName(const Anope::string &file, time_t t =
tm *tm = localtime(&t);
strftime(timestamp, sizeof(timestamp), "%Y%m%d", tm);
- return Anope::LogDir + "/" + file + "." + timestamp;
+ return Anope::ExpandLog(file + "." + timestamp);
}
LogFile::LogFile(const Anope::string &name) : filename(name), stream(name.c_str(), std::ios_base::out | std::ios_base::app)
@@ -74,11 +69,11 @@ 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, const Anope::string &cat, BotInfo *b) : bi(b), 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)
+Log::Log(LogType t, CommandSource &src, Command *_c, ChannelInfo *_ci) : u(src.GetUser()), nc(src.nc), c(_c), source(&src), ci(_ci), type(t)
{
if (!c)
throw CoreException("Invalid pointers passed to Log::Log");
@@ -87,35 +82,34 @@ Log::Log(LogType t, CommandSource &src, Command *_c, ChannelInfo *_ci) : u(src.G
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 = Config->GetClient(c->name.substr(0, sl));
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)
+Log::Log(User *_u, Channel *ch, const Anope::string &cat) : u(_u), chan(ch), ci(chan ? *chan->ci : nullptr), 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)
+Log::Log(User *_u, const Anope::string &cat, BotInfo *_bi) : bi(_bi), u(_u), 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)
+Log::Log(Server *serv, const Anope::string &cat, BotInfo *_bi) : bi(_bi), s(serv), 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(BotInfo *b, const Anope::string &cat) : bi(b), 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(Module *mod, const Anope::string &cat, BotInfo *_bi) : bi(_bi), m(mod), type(LOG_MODULE), category(cat)
{
}
@@ -131,9 +125,13 @@ Log::~Log()
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);
+ {
+ for (auto &li : Config->LogInfos)
+ {
+ if (li.HasType(this->type, this->category))
+ li.ProcessMessage(this);
+ }
+ }
}
Anope::string Log::FormatSource() const
@@ -227,14 +225,14 @@ Anope::string Log::BuildPrefix() const
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)
{
}
LogInfo::~LogInfo()
{
- for (unsigned i = 0; i < this->logfiles.size(); ++i)
- delete this->logfiles[i];
+ for (const auto *logfile : this->logfiles)
+ delete logfile;
this->logfiles.clear();
}
@@ -281,16 +279,15 @@ bool LogInfo::HasType(LogType ltype, const Anope::string &type) const
if (list == NULL)
return false;
- for (unsigned i = 0; i < list->size(); ++i)
+ for (auto value : *list)
{
- Anope::string cat = list->at(i);
bool inverse = false;
- if (cat[0] == '~')
+ if (value[0] == '~')
{
- cat.erase(cat.begin());
+ value.erase(value.begin());
inverse = true;
}
- if (Anope::Match(type, cat))
+ if (Anope::Match(type, value))
{
return !inverse;
}
@@ -301,18 +298,16 @@ bool LogInfo::HasType(LogType ltype, const Anope::string &type) const
void LogInfo::OpenLogFiles()
{
- for (unsigned i = 0; i < this->logfiles.size(); ++i)
- delete this->logfiles[i];
+ for (const auto *logfile : this->logfiles)
+ delete logfile;
this->logfiles.clear();
- for (unsigned i = 0; i < this->targets.size(); ++i)
+ for (const auto &target : this->targets)
{
- const Anope::string &target = this->targets[i];
-
if (target.empty() || target[0] == '#' || target == "globops" || target.find(":") != Anope::string::npos)
continue;
- LogFile *lf = new LogFile(CreateLogName(target));
+ auto *lf = new LogFile(CreateLogName(target));
if (!lf->stream.is_open())
{
Log() << "Unable to open logfile " << lf->GetName();
@@ -353,10 +348,8 @@ void LogInfo::ProcessMessage(const Log *l)
FOREACH_MOD(OnLogMessage, (this, l, buffer));
- for (unsigned i = 0; i < this->targets.size(); ++i)
+ for (const auto &target : this->targets)
{
- const Anope::string &target = this->targets[i];
-
if (!target.empty() && target[0] == '#')
{
if (UplinkSock && l->type <= LOG_NORMAL && Me && Me->IsSynced())
@@ -371,7 +364,7 @@ void LogInfo::ProcessMessage(const Log *l)
if (!bi)
bi = c->WhoSends();
if (bi)
- IRCD->SendPrivmsg(bi, c->name, "%s", buffer.c_str());
+ IRCD->SendPrivmsg(bi, c->name, buffer);
}
}
else if (target == "globops")
@@ -382,7 +375,7 @@ void LogInfo::ProcessMessage(const Log *l)
if (!bi)
bi = this->bot;
if (bi)
- IRCD->SendGlobops(bi, "%s", buffer.c_str());
+ IRCD->SendGlobops(bi, buffer);
}
}
}
@@ -394,11 +387,10 @@ void LogInfo::ProcessMessage(const Log *l)
this->OpenLogFiles();
if (this->log_age)
- for (unsigned i = 0; i < this->targets.size(); ++i)
+ {
+ for (const auto &target : this->targets)
{
- 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 == "globops" || target.find(":") != Anope::string::npos)
continue;
Anope::string oldlog = CreateLogName(target, Anope::CurTime - 86400 * this->log_age);
@@ -408,11 +400,11 @@ void LogInfo::ProcessMessage(const Log *l)
Log(LOG_DEBUG) << "Deleted old logfile " << oldlog;
}
}
+ }
}
- for (unsigned i = 0; i < this->logfiles.size(); ++i)
+ for (auto *lf : this->logfiles)
{
- LogFile *lf = this->logfiles[i];
lf->stream << GetTimeStamp() << " " << buffer << std::endl;
}
}
diff --git a/src/mail.cpp b/src/mail.cpp
index bdad2447f..3aa15c99f 100644
--- a/src/mail.cpp
+++ b/src/mail.cpp
@@ -17,13 +17,14 @@
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)
+ , sendmail_path(Config->GetBlock("mail").Get<const Anope::string>("sendmailpath", "/usr/sbin/sendmail -it"))
+ , send_from(sf)
+ , mail_to(mailto)
, addr(a)
, subject(s)
, message(m)
- , content_type(Config->GetBlock("mail")->Get<const Anope::string>("content_type", "text/plain; charset=UTF-8"))
- , dont_quote_addresses(Config->GetBlock("mail")->Get<bool>("dontquoteaddresses"))
+ , content_type(Config->GetBlock("mail").Get<const Anope::string>("content_type", "text/plain; charset=UTF-8"))
+ , dont_quote_addresses(Config->GetBlock("mail").Get<bool>("dontquoteaddresses"))
{
}
@@ -38,8 +39,7 @@ Mail::Message::~Message()
void Mail::Message::Run()
{
errno = 0;
- FILE *pipe = popen(sendmail_path.c_str(), "w");
-
+ auto *pipe = popen(sendmail_path.c_str(), "w");
if (!pipe)
{
error = strerror(errno);
@@ -56,13 +56,16 @@ void Mail::Message::Run()
fprintf(pipe, "Content-Type: %s\r\n", content_type.c_str());
fprintf(pipe, "Content-Transfer-Encoding: 8bit\r\n");
fprintf(pipe, "\r\n");
- fprintf(pipe, "%s", message.c_str());
- fprintf(pipe, "\r\n.\r\n");
- int result = pclose(pipe);
+ std::stringstream stream(message.str());
+ for (Anope::string line; std::getline(stream, line.str()); )
+ fprintf(pipe, "%s\r\n", line.c_str());
+ fprintf(pipe, "\r\n");
+ auto result = pclose(pipe);
if (result > 0)
- error = "Sendmail exited with code " + stringify(result);
+ error = "Sendmail exited with code " + Anope::ToString(result);
+
SetExitState();
}
@@ -71,32 +74,32 @@ bool Mail::Send(User *u, NickCore *nc, BotInfo *service, const Anope::string &su
if (!nc || !service || subject.empty() || message.empty())
return false;
- Configuration::Block *b = Config->GetBlock("mail");
+ 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<const Anope::string>("sendfrom").empty())
return false;
else if (nc->email.empty())
return false;
nc->lastmail = Anope::CurTime;
- Thread *t = new Mail::Message(b->Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message);
+ Thread *t = new Mail::Message(b.Get<const Anope::string>("sendfrom"), nc->display, nc->email, 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<const 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 (Anope::CurTime - u->lastmail < b.Get<time_t>("delay"))
+ u->SendMessage(service, _("Please wait \002%lu\002 seconds and retry."), (unsigned long)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());
+ u->SendMessage(service, _("Email for \002%s\002 is invalid."), nc->display.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);
+ Thread *t = new Mail::Message(b.Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message);
t->Start();
return true;
}
@@ -107,21 +110,21 @@ 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)
{
- 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())
+ 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())
return false;
nc->lastmail = Anope::CurTime;
- Thread *t = new Mail::Message(b->Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message);
+ Thread *t = new Mail::Message(b.Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message);
t->Start();
return true;
}
/**
- * Checks whether we have a valid, common e-mail address.
+ * Checks whether we have a valid, common email address.
* This is NOT entirely RFC compliant, and won't be so, because I said
- * *common* cases. ;) It is very unlikely that e-mail addresses that
+ * *common* cases. ;) It is very unlikely that email addresses that
* are really being used will fail the check.
*
* @param email Email to Validate
@@ -148,13 +151,15 @@ bool Mail::Validate(const Anope::string &email)
return false;
/* Check for forbidden characters in the name */
- for (unsigned i = 0, end = copy.length(); i < end; ++i)
+ for (auto chr : copy)
{
- if (copy[i] <= 31 || copy[i] >= 127)
+ if (chr <= 31 || chr >= 127)
return false;
- for (unsigned int j = 0; j < 13; ++j)
- if (copy[i] == specials[j])
+ for (auto special : specials)
+ {
+ if (chr == special)
return false;
+ }
}
/* Check for forbidden characters in the domain */
@@ -162,9 +167,11 @@ bool Mail::Validate(const Anope::string &email)
{
if (domain[i] <= 31 || domain[i] >= 127)
return false;
- for (unsigned int j = 0; j < 13; ++j)
- if (domain[i] == specials[j])
+ for (auto special : specials)
+ {
+ if (domain[i] == special)
return false;
+ }
if (domain[i] == '.')
{
if (!i || i == end - 1)
diff --git a/src/main.cpp b/src/main.cpp
index 37e039fd2..ad4a72443 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,4 +1,4 @@
-/* Services -- main source file.
+/* Anope -- main source file.
*
* (C) 2003-2025 Anope Team
* Contact us at team@anope.org
@@ -17,14 +17,14 @@
#include "uplink.h"
#ifndef _WIN32
-#include <limits.h>
+#include <climits>
#else
#include <process.h>
#endif
/* Command-line options: */
int Anope::Debug = 0;
-bool Anope::ReadOnly = false, Anope::NoFork = false, Anope::NoThird = false, Anope::NoExpire = false, Anope::ProtocolDebug = false;
+bool Anope::ReadOnly = false, Anope::NoFork = false, Anope::NoThird = false, Anope::NoPID = false, Anope::NoExpire = false, Anope::ProtocolDebug = false;
Anope::string Anope::ServicesDir;
Anope::string Anope::ServicesBin;
@@ -36,28 +36,37 @@ Anope::string Anope::QuitReason;
static Anope::string BinaryDir; /* Full path to services bin directory */
-time_t Anope::StartTime = time(NULL);
-time_t Anope::CurTime = time(NULL);
+time_t Anope::StartTime = 0;
+time_t Anope::CurTime = 0;
+long long Anope::CurTimeNs = 0;
-int Anope::CurrentUplink = -1;
+size_t Anope::CurrentUplink = -1;
-class UpdateTimer : public Timer
+class UpdateTimer final
+ : public Timer
{
- public:
- UpdateTimer(time_t timeout) : Timer(timeout, Anope::CurTime, true) { }
+public:
+ UpdateTimer(time_t timeout)
+ : Timer(timeout, true)
+ {
+ }
- void Tick(time_t) anope_override
+ void Tick() override
{
Anope::SaveDatabases();
}
};
-class ExpireTimer : public Timer
+class ExpireTimer final
+ : public Timer
{
- public:
- ExpireTimer(time_t timeout) : Timer(timeout, Anope::CurTime, true) { }
+public:
+ ExpireTimer(time_t timeout)
+ : Timer(timeout, true)
+ {
+ }
- void Tick(time_t) anope_override
+ void Tick() override
{
FOREACH_MOD(OnExpireTick, ());
}
@@ -76,13 +85,13 @@ void Anope::SaveDatabases()
*/
static Anope::string GetFullProgDir(const Anope::string &argv0)
{
- char buffer[PATH_MAX];
#ifdef _WIN32
/* Windows has specific API calls to get the EXE path that never fail.
* For once, Windows has something of use, compared to the POSIX code
* for this, this is positively neato.
*/
- if (GetModuleFileName(NULL, buffer, PATH_MAX))
+ char buffer[MAX_PATH];
+ if (GetModuleFileName(NULL, buffer, MAX_PATH))
{
Anope::string fullpath = buffer;
Anope::string::size_type n = fullpath.rfind("\\");
@@ -91,6 +100,7 @@ static Anope::string GetFullProgDir(const Anope::string &argv0)
}
#else
// Get the current working directory
+ char buffer[PATH_MAX];
if (getcwd(buffer, PATH_MAX))
{
Anope::string remainder = argv0;
@@ -137,12 +147,13 @@ int main(int ac, char **av, char **envp)
try
{
/* General initialization first */
- Anope::Init(ac, av);
+ if (!Anope::Init(ac, av))
+ return Anope::ReturnValue;
}
catch (const CoreException &ex)
{
Log() << ex.GetReason();
- return -1;
+ return EXIT_FAILURE;
}
try
@@ -151,13 +162,13 @@ 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();
+ Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].str() << "): " << 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"));
+ UpdateTimer updateTimer(Config->GetBlock("options").Get<time_t>("updatetimeout", "2m"));
+ ExpireTimer expireTimer(Config->GetBlock("options").Get<time_t>("expiretimeout", "30m"));
/*** Main loop. ***/
while (!Anope::Quitting)
@@ -167,7 +178,7 @@ int main(int ac, char **av, char **envp)
/* Process timers */
if (Anope::CurTime - last_check >= Config->TimeoutCheck)
{
- TimerManager::TickTimers(Anope::CurTime);
+ TimerManager::TickTimers();
last_check = Anope::CurTime;
}
@@ -206,11 +217,13 @@ int main(int ac, char **av, char **envp)
if (Anope::Restarting)
{
- chdir(BinaryDir.c_str());
- Anope::string sbin = "./" + Anope::ServicesBin;
- av[0] = const_cast<char *>(sbin.c_str());
- execve(Anope::ServicesBin.c_str(), av, envp);
- Log() << "Restart failed";
+ if (chdir(BinaryDir.c_str()) == 0)
+ {
+ Anope::string sbin = "./" + Anope::ServicesBin;
+ av[0] = const_cast<char *>(sbin.c_str());
+ execve(Anope::ServicesBin.c_str(), av, envp);
+ }
+ Log() << "Restart failed: " << strerror(errno);
Anope::ReturnValue = -1;
}
diff --git a/src/memos.cpp b/src/memos.cpp
index 53177135d..809f895db 100644
--- a/src/memos.cpp
+++ b/src/memos.cpp
@@ -17,7 +17,8 @@
#include "account.h"
#include "regchannel.h"
-Memo::Memo() : Serializable("Memo")
+Memo::Memo()
+ : Serializable(MEMO_TYPE)
{
mi = NULL;
unread = receipt = false;
@@ -34,17 +35,23 @@ Memo::~Memo()
}
}
-void Memo::Serialize(Serialize::Data &data) const
+Memo::Type::Type()
+ : Serialize::Type(MEMO_TYPE)
{
- 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)
+void Memo::Type::Serialize(const Serializable *obj, Serialize::Data &data) const
+{
+ const auto *m = static_cast<const Memo *>(obj);
+ data.Store("owner", m->owner);
+ data.Store("time", m->time);
+ data.Store("sender", m->sender);
+ data.Store("text", m->text);
+ data.Store("unread", m->unread);
+ data.Store("receipt", m->receipt);
+}
+
+Serializable *Memo::Type::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string owner;
@@ -76,7 +83,8 @@ Serializable* Memo::Unserialize(Serializable *obj, Serialize::Data &data)
return m;
}
-MemoInfo::MemoInfo() : memomax(0), memos("Memo")
+MemoInfo::MemoInfo()
+ : memos(MEMO_TYPE)
{
}
@@ -113,9 +121,11 @@ void MemoInfo::Del(unsigned index)
bool MemoInfo::HasIgnore(User *u)
{
- for (unsigned i = 0; i < this->ignores.size(); ++i)
- if (u->nick.equals_ci(this->ignores[i]) || (u->IsIdentified() && u->Account()->display.equals_ci(this->ignores[i])) || Anope::Match(u->GetMask(), Anope::string(this->ignores[i])))
+ for (const auto &ignore : this->ignores)
+ {
+ if (u->nick.equals_ci(ignore) || (u->IsIdentified() && u->Account()->display.equals_ci(ignore)) || Anope::Match(u->GetMask(), Anope::string(ignore)))
return true;
+ }
return false;
}
diff --git a/src/messages.cpp b/src/messages.cpp
index b2f65a5c2..273ab827b 100644
--- a/src/messages.cpp
+++ b/src/messages.cpp
@@ -19,10 +19,11 @@
#include "messages.h"
#include "servers.h"
#include "channels.h"
+#include "numeric.h"
using namespace Message;
-void Away::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Away::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
const Anope::string &msg = !params.empty() ? params[0] : "";
@@ -33,7 +34,7 @@ void Away::Run(MessageSource &source, const std::vector<Anope::string> &params)
Log(source.GetUser(), "away") << "is no longer away";
}
-void Capab::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Capab::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
if (params.size() == 1)
{
@@ -43,18 +44,20 @@ void Capab::Run(MessageSource &source, const std::vector<Anope::string> &params)
Servers::Capab.insert(token);
}
else
- for (unsigned i = 0; i < params.size(); ++i)
- Servers::Capab.insert(params[i]);
+ {
+ for (const auto &param : params)
+ Servers::Capab.insert(param);
+ }
}
-void Error::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Error::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
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> &params)
+void Invite::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *targ = User::Find(params[0]);
Channel *c = Channel::Find(params[1]);
@@ -65,7 +68,7 @@ void Invite::Run(MessageSource &source, const std::vector<Anope::string> &params
FOREACH_MOD(OnInvite, (source.GetUser(), c, targ));
}
-void Join::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Join::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *user = source.GetUser();
const Anope::string &channels = params[0];
@@ -92,14 +95,14 @@ void Join::Run(MessageSource &source, const std::vector<Anope::string> &params)
}
std::list<SJoinUser> users;
- users.push_back(std::make_pair(ChannelStatus(), user));
+ users.emplace_back(ChannelStatus(), user);
Channel *chan = Channel::Find(channel);
- SJoin(source, channel, chan ? chan->creation_time : Anope::CurTime, "", users);
+ 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)
+void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, const Anope::string &modes, const std::vector<Anope::string> &modeparams, const std::list<SJoinUser> &users)
{
bool created;
Channel *c = Channel::FindOrCreate(chan, created, ts ? ts : Anope::CurTime);
@@ -125,12 +128,10 @@ void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, co
/* 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);
+ c->SetModesInternal(source, modes, modeparams, ts, !c->syncing);
- for (std::list<SJoinUser>::const_iterator it = users.begin(), it_end = users.end(); it != it_end; ++it)
+ for (const auto &[status, u] : users)
{
- 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))
@@ -167,7 +168,7 @@ void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, co
}
}
-void Kick::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Kick::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
const Anope::string &channel = params[0];
const Anope::string &users = params[1];
@@ -184,7 +185,7 @@ void Kick::Run(MessageSource &source, const std::vector<Anope::string> &params)
c->KickInternal(source, user, reason);
}
-void Kill::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Kill::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *u = User::Find(params[0]);
BotInfo *bi;
@@ -199,7 +200,7 @@ void Kill::Run(MessageSource &source, const std::vector<Anope::string> &params)
if (last_time == Anope::CurTime)
{
- Anope::QuitReason = "Kill loop detected. Are Services U:Lined?";
+ Anope::QuitReason = "Kill loop detected. Is Anope U:Lined?";
Anope::Quitting = true;
return;
}
@@ -211,53 +212,46 @@ void Kill::Run(MessageSource &source, const std::vector<Anope::string> &params)
u->KillInternal(source, params[1]);
}
-void Message::Mode::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Message::Mode::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
- 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);
+ c->SetModesInternal(source, params[1], { params.begin() + 2, params.end() });
}
else
{
User *u = User::Find(params[0]);
if (u)
- u->SetModesInternal(source, "%s", buf.substr(1).c_str());
+ u->SetModesInternal(source, params[1], { params.begin() + 2, params.end() });
}
}
/* 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> &params)
+void MOTD::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
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)
+ auto motdfile = Anope::ExpandConfig(Config->GetBlock("serverinfo").Get<const Anope::string>("motd"));
+ std::ifstream stream(motdfile.str());
+ if (!stream.is_open())
{
- 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.");
+ IRCD->SendNumeric(ERR_NOSUCHNICK, source.GetSource(), "- MOTD file not readable! Please contact your IRC administrator.");
+ return;
}
- else
- IRCD->SendNumeric(422, source.GetSource(), ":- MOTD file not found! Please contact your IRC administrator.");
+
+ IRCD->SendNumeric(RPL_MOTDSTART, source.GetSource(), "- " + s->GetName() + " Message of the Day");
+ for (Anope::string line; std::getline(stream, line.str()); )
+ IRCD->SendNumeric(RPL_MOTD, source.GetSource(), Anope::printf("- %s", line.c_str()));
+ IRCD->SendNumeric(RPL_ENDOFMOTD, source.GetSource(), "End of /MOTD command.");
}
-void Notice::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Notice::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Anope::string message = params[1];
@@ -269,11 +263,11 @@ void Notice::Run(MessageSource &source, const std::vector<Anope::string> &params
BotInfo *bi = BotInfo::Find(params[0]);
if (!bi)
return;
- FOREACH_MOD(OnBotNotice, (u, bi, message));
+ FOREACH_MOD(OnBotNotice, (u, bi, message, tags));
}
}
-void Part::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Part::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *u = source.GetUser();
const Anope::string &reason = params.size() > 1 ? params[1] : "";
@@ -295,12 +289,12 @@ void Part::Run(MessageSource &source, const std::vector<Anope::string> &params)
}
}
-void Ping::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Ping::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
IRCD->SendPong(params.size() > 1 ? params[1] : Me->GetSID(), params[0]);
}
-void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
const Anope::string &receiver = params[0];
Anope::string message = params[1];
@@ -312,7 +306,7 @@ void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> &param
Channel *c = Channel::Find(receiver);
if (c)
{
- FOREACH_MOD(OnPrivmsg, (u, c, message));
+ FOREACH_MOD(OnPrivmsg, (u, c, message, tags));
}
}
else
@@ -330,50 +324,39 @@ void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> &param
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')
+ Anope::string ctcpname, ctcpbody;
+ if (Anope::ParseCTCP(message, ctcpname, ctcpbody))
{
- if (message.substr(0, 6).equals_ci("\1PING "))
+ if (ctcpname.equals_ci("PING"))
{
- Anope::string buf = message;
- buf.erase(buf.begin());
- buf.erase(buf.end() - 1);
- IRCD->SendCTCP(bi, u->nick, "%s", buf.c_str());
+ IRCD->SendNotice(bi, u->nick, Anope::FormatCTCP("PING", ctcpbody));
}
- else if (message.substr(0, 9).equals_ci("\1VERSION\1"))
+ else if (ctcpname.equals_ci("VERSION"))
{
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());
+ IRCD->SendNotice(bi, u->nick, Anope::FormatCTCP("VERSION", Anope::printf("Anope-%s %s -- %s -- %s", Anope::Version().c_str(),
+ Anope::VersionBuildString().c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)")));
}
return;
}
EventReturn MOD_RESULT;
- FOREACH_RESULT(OnBotPrivmsg, MOD_RESULT, (u, bi, message));
+ FOREACH_RESULT(OnBotPrivmsg, MOD_RESULT, (u, bi, message, tags));
if (MOD_RESULT == EVENT_STOP)
return;
- bi->OnMessage(u, message);
+ bi->OnMessage(u, message, tags);
}
}
return;
}
-void Quit::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Quit::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
const Anope::string &reason = params[0];
User *user = source.GetUser();
@@ -383,7 +366,7 @@ void Quit::Run(MessageSource &source, const std::vector<Anope::string> &params)
user->Quit(reason);
}
-void SQuit::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void SQuit::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Server *s = Server::Find(params[0]);
@@ -404,7 +387,7 @@ void SQuit::Run(MessageSource &source, const std::vector<Anope::string> &params)
s->Delete(s->GetName() + " " + s->GetUplink()->GetName());
}
-void Stats::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Stats::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *u = source.GetUser();
@@ -413,60 +396,56 @@ void Stats::Run(MessageSource &source, const std::vector<Anope::string> &params)
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(RPL_STATSLINKINFO, source.GetSource(), "Server SendBuf SentBytes SentMsgs RecvBuf RecvBytes RecvMsgs ConnTime");
+ IRCD->SendNumeric(RPL_STATSLINKINFO, source.GetSource(), Config->Uplinks[Anope::CurrentUplink].host, UplinkSock->WriteBufferLen(), TotalWritten, -1, UplinkSock->ReadBufferLen(), TotalRead, -1, Anope::CurTime - Anope::StartTime);
}
- IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]);
+ IRCD->SendNumeric(RPL_STATSLINKINFO, source.GetSource(), params[0][0], "End of /STATS report.");
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]);
+ if (!u->HasMode("OPER") && Config->GetBlock("options").Get<bool>("hidestatso"))
+ IRCD->SendNumeric(RPL_STATSLINKINFO, source.GetSource(), params[0][0], "End of /STATS report.");
else
{
- for (unsigned i = 0; i < Oper::opers.size(); ++i)
+ for (auto *o : Oper::opers)
{
- 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(RPL_STATSOLINE, source.GetSource(), 'O', '*', '*', o->name, o->ot->GetName().replace_all_cs(" ", "_"), '0');
}
- IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]);
+ IRCD->SendNumeric(RPL_STATSLINKINFO, source.GetSource(), params[0][0], "End of /STATS report.");
}
break;
case 'u':
{
long uptime = static_cast<long>(Anope::CurTime - Anope::StartTime);
- IRCD->SendNumeric(242, source.GetSource(), ":Services up %ld day%s, %02ld:%02ld:%02ld", uptime / 86400, uptime / 86400 == 1 ? "" : "s", (uptime / 3600) % 24, (uptime / 60) % 60, uptime % 60);
- IRCD->SendNumeric(250, source.GetSource(), ":Current users: %lu (%d ops); maximum %u", static_cast<unsigned long>(UserListByNick.size()), OperCount, MaxUserCount);
- IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]);
+ IRCD->SendNumeric(RPL_STATSUPTIME, source.GetSource(), Anope::printf("Services up %ld day%s, %02ld:%02ld:%02ld", uptime / 86400, uptime / 86400 == 1 ? "" : "s", (uptime / 3600) % 24, (uptime / 60) % 60, uptime % 60));
+ IRCD->SendNumeric(RPL_STATSCONN, source.GetSource(), Anope::printf("Current users: %zu (%d ops); maximum %u", UserListByNick.size(), OperCount, MaxUserCount));
+ IRCD->SendNumeric(RPL_STATSLINKINFO, source.GetSource(), params[0][0], "End of /STATS report.");
break;
} /* case 'u' */
default:
- IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]);
+ IRCD->SendNumeric(RPL_STATSLINKINFO, source.GetSource(), params[0][0], "End of /STATS report.");
}
return;
}
-void Time::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Time::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
- 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;
+ const auto *tm = localtime(&Anope::CurTime);
+ char timebuf[64];
+ strftime(timebuf, sizeof(timebuf), "%A, %d %B %Y @ %H:%M:%S %Z", tm);
+ const auto timestr = Anope::printf("%s (%lu)", timebuf, Anope::CurTime);
+ IRCD->SendNumeric(RPL_TIME, source.GetSource(), Me->GetName(), timestr);
}
-void Topic::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Topic::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Channel *c = Channel::Find(params[0]);
if (c)
@@ -475,28 +454,29 @@ void Topic::Run(MessageSource &source, const std::vector<Anope::string> &params)
return;
}
-void Version::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Version::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
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());
+ IRCD->SendNumeric(RPL_VERSION, source.GetSource(), "Anope-" + Anope::Version(), Me->GetName(), Anope::printf("%s -(%s) -- %s",
+ IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()));
}
-void Whois::Run(MessageSource &source, const std::vector<Anope::string> &params)
+void Whois::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
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());
+ IRCD->SendNumeric(RPL_WHOISUSER, source.GetSource(), u->nick, u->GetIdent(), u->host, '*', u->realname);
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());
+ IRCD->SendNumeric(RPL_WHOISREGNICK, source.GetSource(), bi->nick, "is a registered nick");
+ IRCD->SendNumeric(RPL_WHOISSERVER, source.GetSource(), u->nick, Me->GetName(), Config->GetBlock("serverinfo").Get<const Anope::string>("description"));
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(313, source.GetSource(), "%s :is a Network Service", u->nick.c_str());
- IRCD->SendNumeric(318, source.GetSource(), "%s :End of /WHOIS list.", u->nick.c_str());
+ IRCD->SendNumeric(RPL_WHOISIDLE, source.GetSource(), bi->nick, Anope::CurTime - bi->lastmsg, bi->signon, "seconds idle, signon time");
+ IRCD->SendNumeric(RPL_WHOISOPERATOR, source.GetSource(), u->nick, "is a Network Service");
+ IRCD->SendNumeric(RPL_ENDOFWHOIS, source.GetSource(), u->nick, "End of /WHOIS list.");
}
else
- IRCD->SendNumeric(401, source.GetSource(), "%s :No such user.", params[0].c_str());
+ IRCD->SendNumeric(ERR_NOSUCHNICK, source.GetSource(), params[0], "No such user.");
}
diff --git a/src/misc.cpp b/src/misc.cpp
index 3ffab7199..a472f5b15 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -19,15 +19,19 @@
#include "regexpr.h"
#include "sockets.h"
-#include <errno.h>
-#include <sys/types.h>
+#include <cerrno>
+#include <climits>
+#include <numeric>
+#include <random>
+#include <filesystem>
#include <sys/stat.h>
+#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
#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) : desc(descending)
{
Anope::string error;
commasepstream sep(list);
@@ -42,13 +46,12 @@ NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(tr
if (t == Anope::string::npos)
{
- try
+ if (auto num = Anope::TryConvert<unsigned>(token, &error))
{
- unsigned num = convertTo<unsigned>(token, error, false);
if (error.empty())
- numbers.insert(num);
+ numbers.insert(num.value());
}
- catch (const ConvertException &)
+ else
{
error = "1";
}
@@ -65,15 +68,17 @@ NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(tr
else
{
Anope::string error2;
- try
+ auto n1 = Anope::TryConvert<unsigned>(token.substr(0, t), &error);
+ auto n2 = Anope::TryConvert<unsigned>(token.substr(t + 1), &error);
+ if (n1.has_value() && n2.has_value())
{
- unsigned num1 = convertTo<unsigned>(token.substr(0, t), error, false);
- unsigned num2 = convertTo<unsigned>(token.substr(t + 1), error2, false);
+ auto num1 = n1.value();
+ auto num2 = n2.value();
if (error.empty() && error2.empty())
for (unsigned i = num1; i <= num2; ++i)
numbers.insert(i);
}
- catch (const ConvertException &)
+ else
{
error = "1";
}
@@ -90,10 +95,6 @@ NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(tr
} while (sep.GetToken(token));
}
-NumberList::~NumberList()
-{
-}
-
void NumberList::Process()
{
if (!is_valid)
@@ -106,8 +107,8 @@ void NumberList::Process()
}
else
{
- for (std::set<unsigned>::iterator it = numbers.begin(), it_end = numbers.end(); it != it_end; ++it)
- this->HandleNumber(*it);
+ for (unsigned int number : numbers)
+ this->HandleNumber(number);
}
}
@@ -145,29 +146,31 @@ void ListFormatter::Process(std::vector<Anope::string> &buffer)
std::vector<Anope::string> tcolumns;
std::map<Anope::string, size_t> lengths;
std::set<Anope::string> breaks;
- for (unsigned i = 0; i < this->columns.size(); ++i)
+ for (const auto &column : this->columns)
{
- tcolumns.push_back(Language::Translate(this->nc, this->columns[i].c_str()));
- lengths[this->columns[i]] = tcolumns[i].length();
+ tcolumns.emplace_back(Language::Translate(this->nc, column.c_str()));
+ lengths[column] = column.length();
}
- for (unsigned i = 0; i < this->entries.size(); ++i)
+ for (auto &entry : this->entries)
{
- ListEntry &e = this->entries[i];
- for (unsigned j = 0; j < this->columns.size(); ++j)
- if (e[this->columns[j]].length() > lengths[this->columns[j]])
- lengths[this->columns[j]] = e[this->columns[j]].length();
+ for (const auto &column : this->columns)
+ {
+ if (entry[column].length() > lengths[column])
+ lengths[column] = entry[column].length();
+ }
}
- unsigned length = 0;
- for (std::map<Anope::string, size_t>::iterator it = lengths.begin(), it_end = lengths.end(); it != it_end; ++it)
+ const auto max_length = Config->GetBlock("options").Get<size_t>("linelength", "120");
+ unsigned total_length = 0;
+ for (const auto &[column, length] : lengths)
{
- /* Break lines at 80 chars */
- if (length > 80)
+ // Break lines that are getting too long.
+ if (total_length > max_length)
{
- breaks.insert(it->first);
- length = 0;
+ breaks.insert(column);
+ total_length = 0;
}
else
- length += it->second;
+ total_length += length;
}
/* Only put a list header if more than 1 column */
@@ -191,10 +194,8 @@ void ListFormatter::Process(std::vector<Anope::string> &buffer)
buffer.push_back(s);
}
- for (unsigned i = 0; i < this->entries.size(); ++i)
+ for (auto &entry : this->entries)
{
- ListEntry &e = this->entries[i];
-
Anope::string s;
for (unsigned j = 0; j < this->columns.size(); ++j)
{
@@ -205,16 +206,16 @@ void ListFormatter::Process(std::vector<Anope::string> &buffer)
}
else if (!s.empty())
s += " ";
- s += e[this->columns[j]];
+ s += entry[this->columns[j]];
if (j + 1 != this->columns.size())
- for (unsigned k = e[this->columns[j]].length(); k < lengths[this->columns[j]]; ++k)
+ for (unsigned k = entry[this->columns[j]].length(); k < lengths[this->columns[j]]; ++k)
s += " ";
}
buffer.push_back(s);
}
}
-InfoFormatter::InfoFormatter(NickCore *acc) : nc(acc), longest(0)
+InfoFormatter::InfoFormatter(NickCore *acc) : nc(acc)
{
}
@@ -222,23 +223,23 @@ void InfoFormatter::Process(std::vector<Anope::string> &buffer)
{
buffer.clear();
- for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = this->replies.begin(), it_end = this->replies.end(); it != it_end; ++it)
+ for (const auto &[key, value] : this->replies)
{
Anope::string s;
- for (unsigned i = it->first.length(); i < this->longest; ++i)
+ for (unsigned i = key.length(); i < this->longest; ++i)
s += " ";
- s += it->first + ": " + Language::Translate(this->nc, it->second.c_str());
+ s += key + ": " + Language::Translate(this->nc, value.c_str());
buffer.push_back(s);
}
}
-Anope::string& InfoFormatter::operator[](const Anope::string &key)
+Anope::string &InfoFormatter::operator[](const Anope::string &key)
{
Anope::string tkey = Language::Translate(this->nc, key.c_str());
if (tkey.length() > this->longest)
this->longest = tkey.length();
- this->replies.push_back(std::make_pair(tkey, ""));
+ this->replies.emplace_back(tkey, "");
return this->replies.back().second;
}
@@ -246,11 +247,11 @@ void InfoFormatter::AddOption(const Anope::string &opt)
{
Anope::string options = Language::Translate(this->nc, "Options");
Anope::string *optstr = NULL;
- for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = this->replies.begin(), it_end = this->replies.end(); it != it_end; ++it)
+ for (auto &[option, value] : this->replies)
{
- if (it->first == options)
+ if (option == options)
{
- optstr = &it->second;
+ optstr = &value;
break;
}
}
@@ -265,10 +266,7 @@ void InfoFormatter::AddOption(const Anope::string &opt)
bool Anope::IsFile(const Anope::string &filename)
{
struct stat fileinfo;
- if (!stat(filename.c_str(), &fileinfo))
- return true;
-
- return false;
+ return stat(filename.c_str(), &fileinfo) == 0;
}
time_t Anope::DoTime(const Anope::string &s)
@@ -276,37 +274,28 @@ time_t Anope::DoTime(const Anope::string &s)
if (s.empty())
return 0;
- int amount = 0;
Anope::string end;
-
- try
+ auto amount = Anope::Convert<int>(s, -1, &end);
+ if (!end.empty())
{
- amount = convertTo<int>(s, end, false);
- if (!end.empty())
+ switch (end[0])
{
- switch (end[0])
- {
- case 's':
- return amount;
- case 'm':
- return amount * 60;
- case 'h':
- return amount * 3600;
- case 'd':
- return amount * 86400;
- case 'w':
- return amount * 86400 * 7;
- case 'y':
- return amount * 86400 * 365;
- default:
- break;
- }
+ case 's':
+ return amount;
+ case 'm':
+ return amount * 60;
+ case 'h':
+ return amount * 3600;
+ case 'd':
+ return amount * 86400;
+ case 'w':
+ return amount * 86400 * 7;
+ case 'y':
+ return amount * 86400 * 365;
+ default:
+ break;
}
}
- catch (const ConvertException &)
- {
- amount = -1;
- }
return amount;
}
@@ -320,43 +309,39 @@ Anope::string Anope::Duration(time_t t, const NickCore *nc)
time_t minutes = (t / 60) % 60;
time_t seconds = (t) % 60;
- if (!years && !days && !hours && !minutes)
- return stringify(seconds) + " " + (seconds != 1 ? Language::Translate(nc, _("seconds")) : Language::Translate(nc, _("second")));
- else
+ Anope::string buffer;
+ if (years)
{
- bool need_comma = false;
- Anope::string buffer;
- if (years)
- {
- buffer = stringify(years) + " " + (years != 1 ? Language::Translate(nc, _("years")) : Language::Translate(nc, _("year")));
- need_comma = true;
- }
- if (days)
- {
- buffer += need_comma ? ", " : "";
- buffer += stringify(days) + " " + (days != 1 ? Language::Translate(nc, _("days")) : Language::Translate(nc, _("day")));
- need_comma = true;
- }
- if (hours)
- {
- buffer += need_comma ? ", " : "";
- buffer += stringify(hours) + " " + (hours != 1 ? Language::Translate(nc, _("hours")) : Language::Translate(nc, _("hour")));
- need_comma = true;
- }
- if (minutes)
- {
- buffer += need_comma ? ", " : "";
- buffer += stringify(minutes) + " " + (minutes != 1 ? Language::Translate(nc, _("minutes")) : Language::Translate(nc, _("minute")));
- }
- return buffer;
+ buffer = Anope::printf(Language::Translate(nc, years, N_("%lld year", "%lld years")), (long long)years);
+ }
+ if (days)
+ {
+ buffer += buffer.empty() ? "" : ", ";
+ buffer += Anope::printf(Language::Translate(nc, days, N_("%lld day", "%lld days")), (long long)days);
+ }
+ if (hours)
+ {
+ buffer += buffer.empty() ? "" : ", ";
+ buffer += Anope::printf(Language::Translate(nc, hours, N_("%lld hour", "%lld hours")), (long long)hours);
+ }
+ if (minutes)
+ {
+ buffer += buffer.empty() ? "" : ", ";
+ buffer += Anope::printf(Language::Translate(nc, minutes, N_("%lld minute", "%lld minutes")), (long long)minutes);
+ }
+ if (seconds || buffer.empty())
+ {
+ buffer += buffer.empty() ? "" : ", ";
+ buffer += Anope::printf(Language::Translate(nc, seconds, N_("%lld second", "%lld seconds")), (long long)seconds);
}
+ return buffer;
}
Anope::string Anope::strftime(time_t t, const NickCore *nc, bool short_output)
{
tm tm = *localtime(&t);
char buf[BUFSIZE];
- strftime(buf, sizeof(buf), Language::Translate(nc, _("%b %d %H:%M:%S %Y %Z")), &tm);
+ strftime(buf, sizeof(buf), Language::Translate(nc, _("%b %d %Y %H:%M:%S %Z")), &tm);
if (short_output)
return buf;
if (t < Anope::CurTime)
@@ -371,36 +356,28 @@ Anope::string Anope::Expires(time_t expires, const NickCore *nc)
{
if (!expires)
return Language::Translate(nc, NO_EXPIRE);
- else if (expires <= Anope::CurTime)
+
+ if (expires <= Anope::CurTime)
return Language::Translate(nc, _("expires momentarily"));
- else
- {
- char buf[256];
- time_t diff = expires - Anope::CurTime + 59;
- if (diff >= 86400)
- {
- int days = diff / 86400;
- snprintf(buf, sizeof(buf), Language::Translate(nc, days == 1 ? _("expires in %d day") : _("expires in %d days")), days);
- }
- else
- {
- if (diff <= 3600)
- {
- int minutes = diff / 60;
- snprintf(buf, sizeof(buf), Language::Translate(nc, minutes == 1 ? _("expires in %d minute") : _("expires in %d minutes")), minutes);
- }
- else
- {
- int hours = diff / 3600, minutes;
- diff -= hours * 3600;
- minutes = diff / 60;
- snprintf(buf, sizeof(buf), Language::Translate(nc, hours == 1 && minutes == 1 ? _("expires in %d hour, %d minute") : (hours == 1 && minutes != 1 ? _("expires in %d hour, %d minutes") : (hours != 1 && minutes == 1 ? _("expires in %d hours, %d minute") : _("expires in %d hours, %d minutes")))), hours, minutes);
- }
- }
+ // This will get inlined when compiled with optimisations.
+ auto nearest = [](auto timeleft, auto roundto) {
+ if ((timeleft % roundto) <= (roundto / 2))
+ return timeleft - (timeleft % roundto);
+ return timeleft - (timeleft % roundto) + roundto;
+ };
- return buf;
- }
+ // In order to get a shorter result we round to the nearest period.
+ auto timeleft = expires - Anope::CurTime;
+ if (timeleft >= 31536000)
+ timeleft = nearest(timeleft, 86400); // Nearest day if its more than a year
+ else if (timeleft >= 86400)
+ timeleft = nearest(timeleft, 3600); // Nearest hour if its more than a day
+ else if (timeleft >= 3600)
+ timeleft = nearest(timeleft, 60); // Nearest minute if its more than an hour
+
+ auto duration = Anope::Duration(timeleft, nc);
+ return Anope::printf(Language::Translate(nc, _("expires in %s")), duration.c_str());
}
bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case_sensitive, bool use_regex)
@@ -415,7 +392,7 @@ bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case
if (r == NULL || r->GetExpression() != stripped_mask)
{
- ServiceReference<RegexProvider> provider("Regex", Config->GetBlock("options")->Get<const Anope::string>("regexengine"));
+ ServiceReference<RegexProvider> provider("Regex", Config->GetBlock("options").Get<const Anope::string>("regexengine"));
if (provider)
{
try
@@ -507,29 +484,11 @@ bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case
return m == mask_len;
}
-void Anope::Encrypt(const Anope::string &src, Anope::string &dest)
+bool Anope::Encrypt(const Anope::string &src, Anope::string &dest)
{
EventReturn MOD_RESULT;
FOREACH_RESULT(OnEncrypt, MOD_RESULT, (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;
+ return MOD_RESULT == EVENT_ALLOW &&!dest.empty();
}
Anope::string Anope::printf(const char *fmt, ...)
@@ -602,7 +561,7 @@ int Anope::LastErrorCode()
#endif
}
-const Anope::string Anope::LastError()
+Anope::string Anope::LastError()
{
#ifndef _WIN32
return strerror(errno);
@@ -619,32 +578,35 @@ 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::ToString(VERSION_MAJOR) + "." + Anope::ToString(VERSION_MINOR) + "." + Anope::ToString(VERSION_PATCH) + VERSION_EXTRA + " (" + VERSION_GIT + ")";
#else
- return stringify(VERSION_MAJOR) + "." + stringify(VERSION_MINOR) + "." + stringify(VERSION_PATCH) + VERSION_EXTRA;
+ return Anope::ToString(VERSION_MAJOR) + "." + Anope::ToString(VERSION_MINOR) + "." + Anope::ToString(VERSION_PATCH) + VERSION_EXTRA;
#endif
}
Anope::string Anope::VersionShort()
{
- return stringify(VERSION_MAJOR) + "." + stringify(VERSION_MINOR) + "." + stringify(VERSION_PATCH);
+ return Anope::ToString(VERSION_MAJOR) + "." + Anope::ToString(VERSION_MINOR) + "." + Anope::ToString(VERSION_PATCH);
}
Anope::string Anope::VersionBuildString()
{
-#ifdef REPRODUCIBLE_BUILD
- Anope::string s = "build #" + stringify(BUILD);
+#if REPRODUCIBLE_BUILD
+ Anope::string s = "build #" + Anope::ToString(BUILD);
#else
- Anope::string s = "build #" + stringify(BUILD) + ", compiled " + Anope::compiled;
+ Anope::string s = "build #" + Anope::ToString(BUILD) + ", compiled " + Anope::compiled;
#endif
Anope::string flags;
-#ifdef DEBUG_BUILD
+#if DEBUG_BUILD
flags += "D";
#endif
#ifdef VERSION_GIT
flags += "G";
#endif
+#if REPRODUCIBLE_BUILD
+ flags += "R"
+#endif
#ifdef _WIN32
flags += "W";
#endif
@@ -770,6 +732,145 @@ Anope::string Anope::Random(size_t len)
};
Anope::string buf;
for (size_t i = 0; i < len; ++i)
- buf.append(chars[rand() % sizeof(chars)]);
+ buf.append(chars[Anope::RandomNumber() % sizeof(chars)]);
return buf;
}
+
+int Anope::RandomNumber()
+{
+ static std::random_device device;
+ static std::mt19937 engine(device());
+ static std::uniform_int_distribution<int> dist(INT_MIN, INT_MAX);
+ return dist(engine);
+}
+
+// Implementation of https://en.wikipedia.org/wiki/Levenshtein_distance
+size_t Anope::Distance(const Anope::string &s1, const Anope::string &s2)
+{
+ if (s1.empty())
+ return s2.length();
+ if (s2.empty())
+ return s1.length();
+
+ std::vector<size_t> costs(s2.length() + 1);
+ std::iota(costs.begin(), costs.end(), 0);
+
+ size_t i = 0;
+ for (const auto c1 : s1)
+ {
+ costs[0] = i + 1;
+ size_t corner = i;
+ size_t j = 0;
+ for (const auto &c2 : s2)
+ {
+ size_t upper = costs[j + 1];
+ if (c1 == c2)
+ costs[j + 1] = corner;
+ else
+ {
+ size_t t = upper < corner ? upper : corner;
+ costs[j + 1] = (costs[j] < t ? costs[j] : t) + 1;
+ }
+ corner = upper;
+ j++;
+ }
+ i++;
+ }
+ return costs[s2.length()];
+}
+
+void Anope::UpdateTime()
+{
+#ifdef _WIN32
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+
+ CurTime = time(nullptr);
+ CurTimeNs = st.wMilliseconds;
+#elif HAVE_CLOCK_GETTIME
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+
+ CurTime = ts.tv_sec;
+ CurTimeNs = ts.tv_nsec;
+#else
+ struct timeval tv;
+ gettimeofday(&tv, nullptr);
+
+ CurTime = tv.tv_sec;
+ CurTimeNs = tv.tv_usec * 1000;
+#endif
+}
+
+Anope::string Anope::Expand(const Anope::string &base, const Anope::string &fragment)
+{
+ if (fragment.empty())
+ return ""; // We can't expand an empty fragment.
+
+ // The fragment is an absolute path, don't modify it.
+ if (std::filesystem::path(fragment.str()).is_absolute())
+ return fragment;
+
+#ifdef _WIN32
+ static constexpr const char separator = '\\';
+#else
+ static constexpr const char separator = '/';
+#endif
+
+ // The fragment is relative to a home directory, expand that.
+ if (!fragment.compare(0, 2, "~/", 2))
+ {
+ const auto *homedir = getenv("HOME");
+ if (homedir && *homedir)
+ return Anope::printf("%s%c%s", homedir, separator, fragment.c_str() + 2);
+ }
+
+ return Anope::printf("%s%c%s", base.c_str(), separator, fragment.c_str());
+}
+
+Anope::string Anope::FormatCTCP(const Anope::string &name, const Anope::string &value)
+{
+ if (value.empty())
+ return Anope::printf("\1%s\1", name.c_str());
+
+ return Anope::printf("\1%s %s\1", name.c_str(), value.c_str());
+}
+
+bool Anope::ParseCTCP(const Anope::string &text, Anope::string &name, Anope::string &body)
+{
+ // According to draft-oakley-irc-ctcp-02 a valid CTCP must begin with SOH and
+ // contain at least one octet which is not NUL, SOH, CR, LF, or SPACE. As most
+ // of these are restricted at the protocol level we only need to check for SOH
+ // and SPACE.
+ if (text.length() < 2 || text[0] != '\x1' || text[1] == '\x1' || text[1] == ' ')
+ {
+ name.clear();
+ body.clear();
+ return false;
+ }
+
+ auto end_of_name = text.find(' ', 2);
+ auto end_of_ctcp = *text.rbegin() == '\x1' ? 1 : 0;
+ if (end_of_name == std::string::npos)
+ {
+ // The CTCP only contains a name.
+ name = text.substr(1, text.length() - 1 - end_of_ctcp);
+ body.clear();
+ return true;
+ }
+
+ // The CTCP contains a name and a body.
+ name = text.substr(1, end_of_name - 1);
+
+ auto start_of_body = text.find_first_not_of(' ', end_of_name + 1);
+ if (start_of_body == std::string::npos)
+ {
+ // The CTCP body is provided but empty.
+ body.clear();
+ return true;
+ }
+
+ // The CTCP body provided was non-empty.
+ body = text.substr(start_of_body, text.length() - start_of_body - end_of_ctcp);
+ return true;
+}
diff --git a/src/modes.cpp b/src/modes.cpp
index 0bd2019c7..fdaae7716 100644
--- a/src/modes.cpp
+++ b/src/modes.cpp
@@ -39,16 +39,14 @@ static std::vector<ChannelModeStatus *> ChannelModesByStatus;
/* Number of generic modes we support */
unsigned ModeManager::GenericChannelModes = 0, ModeManager::GenericUserModes = 0;
-struct StackerInfo
+struct StackerInfo final
{
/* Modes to be added */
std::list<std::pair<Mode *, Anope::string> > AddModes;
/* Modes to be deleted */
std::list<std::pair<Mode *, Anope::string> > DelModes;
/* Bot this is sent from */
- BotInfo *bi;
-
- StackerInfo() : bi(NULL) { }
+ BotInfo *bi = nullptr;
/** Add a mode to this object
* @param mode The mode
@@ -58,10 +56,6 @@ struct StackerInfo
void AddMode(Mode *mode, bool set, const Anope::string &param);
};
-ChannelStatus::ChannelStatus()
-{
-}
-
ChannelStatus::ChannelStatus(const Anope::string &m) : modes(m)
{
}
@@ -101,9 +95,9 @@ Anope::string ChannelStatus::BuildModePrefixList() const
{
Anope::string ret;
- for (size_t i = 0; i < modes.length(); ++i)
+ for (auto mode : modes)
{
- ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]);
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(mode);
if (cm != NULL && cm->type == MODE_STATUS)
{
ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
@@ -118,10 +112,6 @@ Mode::Mode(const Anope::string &mname, ModeClass mcl, char mch, ModeType mt) : n
{
}
-Mode::~Mode()
-{
-}
-
bool Mode::CanSet(User *u) const
{
return true;
@@ -154,9 +144,9 @@ ChannelMode *ChannelMode::Wrap(Anope::string &param)
ChannelMode *ChannelMode::Unwrap(Anope::string &param)
{
- for (unsigned i = 0; i < listeners.size(); ++i)
+ for (auto *listener : listeners)
{
- ChannelMode *cm = listeners[i]->Unwrap(this, param);
+ ChannelMode *cm = listener->Unwrap(this, param);
if (cm != this)
return cm;
}
@@ -243,10 +233,7 @@ bool UserModeNoone::CanSet(User *u) const
bool ChannelModeKey::IsValid(Anope::string &value) const
{
- if (!value.empty() && value.find(':') == Anope::string::npos && value.find(',') == Anope::string::npos)
- return true;
-
- return false;
+ return !value.empty() && value.find(':') == Anope::string::npos && value.find(',') == Anope::string::npos;
}
bool ChannelModeOperOnly::CanSet(User *u) const
@@ -307,13 +294,14 @@ void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string &param)
}
/* Add this mode and its param to our list */
- list->push_back(std::make_pair(mode, param));
+ list->emplace_back(mode, param);
}
-static class ModePipe : public Pipe
+static class ModePipe final
+ : public Pipe
{
- public:
- void OnNotify()
+public:
+ void OnNotify() override
{
ModeManager::ProcessModes();
}
@@ -330,7 +318,7 @@ static StackerInfo *GetInfo(List &l, Object *o)
if (it != l.end())
return it->second;
- StackerInfo *s = new StackerInfo();
+ auto *s = new StackerInfo();
l[o] = s;
return s;
}
@@ -339,27 +327,33 @@ static StackerInfo *GetInfo(List &l, Object *o)
* @param info The stacker info for a channel or user
* @return a list of strings
*/
-static std::list<Anope::string> BuildModeStrings(StackerInfo *info)
+static auto BuildModeStrings(StackerInfo *info)
{
- std::list<Anope::string> ret;
+ std::list<std::pair<Anope::string, std::vector<Anope::string>>> ret;
std::list<std::pair<Mode *, Anope::string> >::iterator it, it_end;
- Anope::string buf = "+", parambuf;
+ Anope::string buf = "+";
+ std::vector<Anope::string> parambuf;
unsigned NModes = 0;
+ size_t paramlen = 0;
for (it = info->AddModes.begin(), it_end = info->AddModes.end(); it != it_end; ++it)
{
- if (++NModes > IRCD->MaxModes || (buf.length() + parambuf.length() > IRCD->MaxLine - 100)) // Leave room for command, channel, etc
+ if ((IRCD->MaxModes && ++NModes > IRCD->MaxModes) || (IRCD->MaxLine && buf.length() + paramlen > IRCD->MaxLine - 100)) // Leave room for command, channel, etc
{
- ret.push_back(buf + parambuf);
+ ret.push_back({buf, parambuf});
buf = "+";
parambuf.clear();
+ paramlen = 0;
NModes = 1;
}
buf += it->first->mchar;
if (!it->second.empty())
- parambuf += " " + it->second;
+ {
+ parambuf.push_back(it->second);
+ paramlen += it->second.length() + 1;
+ }
}
if (buf[buf.length() - 1] == '+')
@@ -368,25 +362,29 @@ static std::list<Anope::string> BuildModeStrings(StackerInfo *info)
buf += "-";
for (it = info->DelModes.begin(), it_end = info->DelModes.end(); it != it_end; ++it)
{
- if (++NModes > IRCD->MaxModes || (buf.length() + parambuf.length() > IRCD->MaxLine - 100)) // Leave room for command, channel, etc
+ if ((IRCD->MaxModes && ++NModes > IRCD->MaxModes) || (IRCD->MaxLine && buf.length() + paramlen > IRCD->MaxLine - 100)) // Leave room for command, channel, etc
{
- ret.push_back(buf + parambuf);
+ ret.push_back({buf, parambuf});
buf = "-";
parambuf.clear();
+ paramlen = 0;
NModes = 1;
}
buf += it->first->mchar;
if (!it->second.empty())
- parambuf += " " + it->second;
+ {
+ parambuf.push_back(it->second);
+ paramlen += it->second.length() + 1;
+ }
}
if (buf[buf.length() - 1] == '-')
buf.erase(buf.length() - 1);
if (!buf.empty())
- ret.push_back(buf + parambuf);
+ ret.push_back({buf, parambuf});
return ret;
}
@@ -400,7 +398,7 @@ bool ModeManager::AddUserMode(UserMode *um)
if (um->name.empty())
{
- um->name = stringify(++GenericUserModes);
+ um->name = Anope::ToString(++GenericUserModes);
Log() << "ModeManager: Added generic support for user mode " << um->mchar;
}
@@ -427,7 +425,7 @@ bool ModeManager::AddChannelMode(ChannelMode *cm)
if (cm->name.empty())
{
- cm->name = stringify(++GenericChannelModes);
+ cm->name = Anope::ToString(++GenericChannelModes);
Log() << "ModeManager: Added generic support for channel mode " << cm->mchar;
}
@@ -456,8 +454,8 @@ bool ModeManager::AddChannelMode(ChannelMode *cm)
FOREACH_MOD(OnChannelModeAdd, (cm));
- for (unsigned int i = 0; i < ChannelModes.size(); ++i)
- ChannelModes[i]->Check();
+ for (auto *cmode : ChannelModes)
+ cmode->Check();
return true;
}
@@ -589,7 +587,7 @@ const std::vector<ChannelModeStatus *> &ModeManager::GetStatusChannelModesByRank
return ChannelModesByStatus;
}
-static struct StatusSort
+static struct StatusSort final
{
bool operator()(ChannelModeStatus *cm1, ChannelModeStatus *cm2) const
{
@@ -600,10 +598,8 @@ static struct StatusSort
void ModeManager::RebuildStatusModes()
{
ChannelModesByStatus.clear();
- for (unsigned j = 0; j < ChannelModesIdx.size(); ++j)
+ for (auto *cm : ChannelModesIdx)
{
- ChannelMode *cm = ChannelModesIdx[j];
-
if (cm && cm->type == MODE_STATUS && std::find(ChannelModesByStatus.begin(), ChannelModesByStatus.end(), cm) == ChannelModesByStatus.end())
ChannelModesByStatus.push_back(anope_dynamic_static_cast<ChannelModeStatus *>(cm));
}
@@ -640,30 +636,22 @@ void ModeManager::ProcessModes()
{
if (!UserStackerObjects.empty())
{
- for (std::map<User *, StackerInfo *>::const_iterator it = UserStackerObjects.begin(), it_end = UserStackerObjects.end(); it != it_end; ++it)
+ for (const auto &[u, s] : UserStackerObjects)
{
- User *u = it->first;
- StackerInfo *s = it->second;
-
- 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, "%s", lit->c_str());
- delete it->second;
+ for (const auto &modestr : BuildModeStrings(s))
+ IRCD->SendModeInternal(s->bi, u, modestr.first, modestr.second);
+ delete s;
}
UserStackerObjects.clear();
}
if (!ChannelStackerObjects.empty())
{
- for (std::map<Channel *, StackerInfo *>::const_iterator it = ChannelStackerObjects.begin(), it_end = ChannelStackerObjects.end(); it != it_end; ++it)
+ for (const auto &[c, s] : ChannelStackerObjects)
{
- Channel *c = it->first;
- StackerInfo *s = it->second;
-
- 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, "%s", lit->c_str());
- delete it->second;
+ for (const auto &modestr : BuildModeStrings(s))
+ IRCD->SendModeInternal(s->bi, c, modestr.first, modestr.second);
+ delete s;
}
ChannelStackerObjects.clear();
}
@@ -676,9 +664,8 @@ static void StackerDel(std::map<T *, StackerInfo *> &map, T *obj)
if (it != map.end())
{
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, "%s", lit->c_str());
+ for (const auto &modestr : BuildModeStrings(si))
+ IRCD->SendModeInternal(si->bi, obj, modestr.first, modestr.second);
delete si;
map.erase(it);
@@ -742,7 +729,7 @@ void ModeManager::StackerDel(Mode *m)
}
}
-Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0), family(0)
+Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh)
{
Anope::string n, u, h;
@@ -796,22 +783,15 @@ Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh
&cidr_range = this->host.substr(sl + 1);
sockaddrs addr(cidr_ip);
-
- try
+ auto range = Anope::TryConvert<unsigned short>(cidr_range);
+ if (addr.valid() && range.has_value())
{
- if (addr.valid() && cidr_range.is_pos_number_only())
- {
- 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();
+ this->cidr_len = range.value();
+ this->host = cidr_ip;
+ this->family = addr.family();
- Log(LOG_DEBUG) << "Ban " << mask << " has cidr " << this->cidr_len;
- }
+ Log(LOG_DEBUG) << "Ban " << mask << " has cidr " << this->cidr_len;
}
- catch (const ConvertException &) { }
}
}
@@ -819,12 +799,12 @@ Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh
this->real.clear();
}
-const Anope::string Entry::GetMask() const
+Anope::string Entry::GetMask() const
{
return this->mask;
}
-const Anope::string Entry::GetNUHMask() const
+Anope::string Entry::GetNUHMask() const
{
Anope::string n = nick.empty() ? "*" : nick,
u = user.empty() ? "*" : user,
@@ -835,11 +815,11 @@ const Anope::string Entry::GetNUHMask() const
{
case AF_INET:
if (cidr_len <= 32)
- c = "/" + stringify(cidr_len);
+ c = "/" + Anope::ToString(cidr_len);
break;
case AF_INET6:
if (cidr_len <= 128)
- c = "/" + stringify(cidr_len);
+ c = "/" + Anope::ToString(cidr_len);
break;
}
@@ -855,8 +835,7 @@ bool Entry::Matches(User *u, bool full) const
if (cm != NULL && cm->type == MODE_LIST)
{
ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
- if (cml->Matches(u, this))
- return true;
+ return cml->Matches(u, this);
}
}
diff --git a/src/module.cpp b/src/module.cpp
index ba4076306..6b6a4e36c 100644
--- a/src/module.cpp
+++ b/src/module.cpp
@@ -11,7 +11,7 @@
#include "language.h"
#include "account.h"
-#ifdef GETTEXT_FOUND
+#if HAVE_LOCALIZATION
# include <libintl.h>
#endif
@@ -39,14 +39,14 @@ Module::Module(const Anope::string &modname, const Anope::string &, ModType modt
ModuleManager::Modules.push_back(this);
-#if GETTEXT_FOUND
- for (unsigned i = 0; i < Language::Languages.size(); ++i)
+#if HAVE_LOCALIZATION
+ for (const auto &language : Language::Languages)
{
/* Remove .UTF-8 or any other suffix */
Anope::string lang;
- sepstream(Language::Languages[i], '.').GetToken(lang);
+ sepstream(language, '.').GetToken(lang);
- if (Anope::IsFile(Anope::LocaleDir + "/" + lang + "/LC_MESSAGES/" + modname + ".mo"))
+ if (Anope::IsFile(Anope::ExpandLocale(lang + "/LC_MESSAGES/" + modname + ".mo")))
{
if (!bindtextdomain(this->name.c_str(), Anope::LocaleDir.c_str()))
Log() << "Error calling bindtextdomain, " << Anope::LastError();
@@ -75,7 +75,7 @@ Module::~Module()
if (it != ModuleManager::Modules.end())
ModuleManager::Modules.erase(it);
-#if GETTEXT_FOUND
+#if HAVE_LOCALIZATION
std::vector<Anope::string>::iterator dit = std::find(Language::Domains.begin(), Language::Domains.end(), this->name);
if (dit != Language::Domains.end())
Language::Domains.erase(dit);
diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp
index 3ea0b2fa4..11a00e363 100644
--- a/src/modulemanager.cpp
+++ b/src/modulemanager.cpp
@@ -15,39 +15,33 @@
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
-#include <dirent.h>
#include <sys/types.h>
#include <dlfcn.h>
#endif
+#include <filesystem>
+
std::list<Module *> ModuleManager::Modules;
std::vector<Module *> ModuleManager::EventHandlers[I_SIZE];
#ifdef _WIN32
void ModuleManager::CleanupRuntimeDirectory()
{
- Anope::string dirbuf = Anope::DataDir + "/runtime";
+ Anope::string dirbuf = Anope::ExpandData("runtime");
Log(LOG_DEBUG) << "Cleaning out Module run time directory (" << dirbuf << ") - this may take a moment, please wait";
-
- DIR *dirp = opendir(dirbuf.c_str());
- if (!dirp)
+ try
{
- Log(LOG_DEBUG) << "Cannot open directory (" << dirbuf << ")";
- return;
+ for (const auto &entry : std::filesystem::directory_iterator(dirbuf.str()))
+ {
+ if (entry.is_regular_file())
+ std::filesystem::remove(entry);
+ }
}
-
- for (dirent *dp; (dp = readdir(dirp));)
+ catch (const std::filesystem::filesystem_error &err)
{
- if (!dp->d_ino)
- continue;
- if (Anope::string(dp->d_name).equals_cs(".") || Anope::string(dp->d_name).equals_cs(".."))
- continue;
- Anope::string filebuf = dirbuf + "/" + dp->d_name;
- unlink(filebuf.c_str());
+ Log(LOG_DEBUG) << "Cannot open directory (" << dirbuf << "): " << err.what();
}
-
- closedir(dirp);
}
/**
@@ -61,7 +55,7 @@ void ModuleManager::CleanupRuntimeDirectory()
*/
static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &output)
{
- Anope::string input = Anope::ModuleDir + "/modules/" + name + ".so";
+ const auto input = Anope::ExpandModule(name + DLL_EXT);
struct stat s;
if (stat(input.c_str(), &s) == -1)
@@ -139,7 +133,7 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
#ifdef _WIN32
/* Generate the filename for the temporary copy of the module */
- Anope::string pbuf = Anope::DataDir + "/runtime/" + modname + ".so.XXXXXX";
+ auto pbuf = Anope::ExpandData("runtime/" + modname + DLL_EXT ".XXXXXX");
/* Don't skip return value checking! -GD */
ModuleReturn ret = moduleCopyFile(modname, pbuf);
@@ -152,7 +146,7 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
return ret;
}
#else
- Anope::string pbuf = Anope::ModuleDir + "/modules/" + modname + ".so";
+ const auto pbuf = Anope::ExpandModule(modname + DLL_EXT);
#endif
dlerror();
@@ -248,7 +242,7 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
/* Initialize config */
try
{
- m->OnReload(Config);
+ m->OnReload(*Config);
}
catch (const ModuleException &ex)
{
@@ -273,8 +267,8 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
Log(LOG_DEBUG) << "Module " << modname << " loaded.";
/* Attach module to all events */
- for (unsigned i = 0; i < I_SIZE; ++i)
- EventHandlers[i].push_back(m);
+ for (auto &mods : EventHandlers)
+ mods.push_back(m);
m->Prioritize();
@@ -313,10 +307,8 @@ ModuleReturn ModuleManager::UnloadModule(Module *m, User *u)
Module *ModuleManager::FindModule(const Anope::string &name)
{
- for (std::list<Module *>::const_iterator it = Modules.begin(), it_end = Modules.end(); it != it_end; ++it)
+ for (auto *m : Modules)
{
- Module *m = *it;
-
if (m->name.equals_ci(name))
return m;
}
@@ -326,10 +318,8 @@ Module *ModuleManager::FindModule(const Anope::string &name)
Module *ModuleManager::FindFirstOf(ModType type)
{
- for (std::list<Module *>::const_iterator it = Modules.begin(), it_end = Modules.end(); it != it_end; ++it)
+ for (auto *m : Modules)
{
- Module *m = *it;
-
if (m->type & type)
return m;
}
@@ -358,7 +348,7 @@ void ModuleManager::RequireVersion(int major, int minor, int patch)
}
}
- throw ModuleException("This module requires version " + stringify(major) + "." + stringify(minor) + "." + stringify(patch) + " - this is " + Anope::VersionShort());
+ throw ModuleException("This module requires version " + Anope::ToString(major) + "." + Anope::ToString(minor) + "." + Anope::ToString(patch) + " - this is " + Anope::VersionShort());
}
ModuleReturn ModuleManager::DeleteModule(Module *m)
@@ -395,9 +385,8 @@ ModuleReturn ModuleManager::DeleteModule(Module *m)
void ModuleManager::DetachAll(Module *mod)
{
- for (unsigned i = 0; i < I_SIZE; ++i)
+ for (auto &mods : EventHandlers)
{
- 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);
@@ -446,43 +435,62 @@ bool ModuleManager::SetPriority(Module *mod, Implementation i, Priority s, Modul
{
/* 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;
}
+ }
+ }
+ break;
+ }
}
/* Do we need to swap? */
@@ -510,16 +518,17 @@ void ModuleManager::UnloadAll()
{
std::vector<Anope::string> modules;
for (size_t i = 1, j = 0; i != MT_END; j |= i, i <<= 1)
- for (std::list<Module *>::iterator it = Modules.begin(), it_end = Modules.end(); it != it_end; ++it)
+ {
+ for (auto *m : Modules)
{
- Module *m = *it;
if ((m->type & j) == m->type)
modules.push_back(m->name);
}
+ }
- for (unsigned i = 0; i < modules.size(); ++i)
+ for (auto &module : modules)
{
- Module *m = FindModule(modules[i]);
+ Module *m = FindModule(module);
if (m != NULL)
UnloadModule(m, NULL);
}
diff --git a/src/nickalias.cpp b/src/nickalias.cpp
index 68cf165e6..ac33e836a 100644
--- a/src/nickalias.cpp
+++ b/src/nickalias.cpp
@@ -18,24 +18,24 @@
#include "servers.h"
#include "config.h"
-Serialize::Checker<nickalias_map> NickAliasList("NickAlias");
+Serialize::Checker<nickalias_map> NickAliasList(NICKALIAS_TYPE);
-NickAlias::NickAlias(const Anope::string &nickname, NickCore* nickcore) : Serializable("NickAlias")
+NickAlias::NickAlias(const Anope::string &nickname, NickCore *nickcore)
+ : Serializable(NICKALIAS_TYPE)
+ , nick(nickname)
+ , nc(nickcore)
{
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);
+ if (this->nick.equals_ci(nickcore->display))
+ nickcore->na = this;
- size_t old = NickAliasList->size();
- (*NickAliasList)[this->nick] = this;
- if (old == NickAliasList->size())
- Log(LOG_DEBUG) << "Duplicate nick " << nickname << " in nickalias table";
+ if (!NickAliasList->insert_or_assign(this->nick, this).second)
+ Log(LOG_DEBUG) << "Duplicate nick " << this->nick << " in NickAlias table";
if (this->nc->o == NULL)
{
@@ -78,7 +78,7 @@ NickAlias::~NickAlias()
NickAliasList->erase(this->nick);
}
-void NickAlias::SetVhost(const Anope::string &ident, const Anope::string &host, const Anope::string &creator, time_t created)
+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;
@@ -86,7 +86,7 @@ void NickAlias::SetVhost(const Anope::string &ident, const Anope::string &host,
this->vhost_created = created;
}
-void NickAlias::RemoveVhost()
+void NickAlias::RemoveVHost()
{
this->vhost_ident.clear();
this->vhost_host.clear();
@@ -94,27 +94,35 @@ void NickAlias::RemoveVhost()
this->vhost_created = 0;
}
-bool NickAlias::HasVhost() const
+bool NickAlias::HasVHost() const
{
return !this->vhost_host.empty();
}
-const Anope::string &NickAlias::GetVhostIdent() const
+const Anope::string &NickAlias::GetVHostIdent() const
{
return this->vhost_ident;
}
-const Anope::string &NickAlias::GetVhostHost() const
+const Anope::string &NickAlias::GetVHostHost() const
{
return this->vhost_host;
}
-const Anope::string &NickAlias::GetVhostCreator() const
+Anope::string NickAlias::GetVHostMask() const
+{
+ if (this->GetVHostIdent().empty())
+ return this->GetVHostHost();
+
+ return this->GetVHostIdent() + "@" + this->GetVHostHost();
+}
+
+const Anope::string &NickAlias::GetVHostCreator() const
{
return this->vhost_creator;
}
-time_t NickAlias::GetVhostCreated() const
+time_t NickAlias::GetVHostCreated() const
{
return this->vhost_created;
}
@@ -131,36 +139,50 @@ NickAlias *NickAlias::Find(const Anope::string &nick)
return NULL;
}
-void NickAlias::Serialize(Serialize::Data &data) const
+NickAlias *NickAlias::FindId(uint64_t id)
{
- 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())
+ const auto *nc = NickCore::FindId(id);
+ return nc ? nc->na : nullptr;
+}
+
+NickAlias::Type::Type()
+ : Serialize::Type(NICKALIAS_TYPE)
+{
+}
+
+void NickAlias::Type::Serialize(const Serializable *obj, Serialize::Data &data) const
+{
+ const auto *na = static_cast<const NickAlias *>(obj);
+ data.Store("nick", na->nick);
+ data.Store("last_quit", na->last_quit);
+ data.Store("last_realname", na->last_realname);
+ data.Store("last_usermask", na->last_usermask);
+ data.Store("last_realhost", na->last_realhost);
+ data.Store("time_registered", na->time_registered);
+ data.Store("last_seen", na->last_seen);
+ data.Store("ncid", na->nc->GetId());
+
+ if (na->HasVHost())
{
- data["vhost_ident"] << this->GetVhostIdent();
- data["vhost_host"] << this->GetVhostHost();
- data["vhost_creator"] << this->GetVhostCreator();
- data["vhost_time"] << this->GetVhostCreated();
+ data.Store("vhost_ident", na->GetVHostIdent());
+ data.Store("vhost_host", na->GetVHostHost());
+ data.Store("vhost_creator", na->GetVHostCreator());
+ data.Store("vhost_time", na->GetVHostCreated());
}
- Extensible::ExtensibleSerialize(this, this, data);
+ Extensible::ExtensibleSerialize(na, na, data);
}
-Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data)
+Serializable *NickAlias::Type::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string snc, snick;
+ uint64_t sncid = 0;
- data["nc"] >> snc;
+ data["nc"] >> snc; // Deprecated 2.0 field
+ data["ncid"] >> sncid;
data["nick"] >> snick;
- NickCore *core = NickCore::Find(snc);
+ auto *core = sncid ? NickCore::FindId(sncid) : NickCore::Find(snc);
if (core == NULL)
return NULL;
@@ -200,7 +222,7 @@ Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data)
data["vhost_creator"] >> vhost_creator;
data["vhost_time"] >> vhost_time;
- na->SetVhost(vhost_ident, vhost_host, vhost_creator, vhost_time);
+ na->SetVHost(vhost_ident, vhost_host, vhost_creator, vhost_time);
Extensible::ExtensibleUnserialize(na, na, data);
@@ -210,6 +232,9 @@ Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data)
data["extensible:NO_EXPIRE"] >> b;
if (b)
na->Extend<bool>("NS_NO_EXPIRE");
+
+ if (na->time_registered < na->nc->time_registered)
+ na->nc->time_registered = na->time_registered;
/* end compat */
return na;
diff --git a/src/nickcore.cpp b/src/nickcore.cpp
index 5bc15cf50..7ca338aff 100644
--- a/src/nickcore.cpp
+++ b/src/nickcore.cpp
@@ -15,28 +15,25 @@
#include "config.h"
#include <climits>
-Serialize::Checker<nickcore_map> NickCoreList("NickCore");
-nickcoreid_map NickCoreIdList;
-
-NickCore::NickCore(const Anope::string &coredisplay, uint64_t coreid) : Serializable("NickCore"), chanaccess("ChannelInfo"), aliases("NickAlias")
+Serialize::Checker<nickcore_map> NickCoreList(NICKCORE_TYPE);
+Serialize::Checker<nickcoreid_map> NickCoreIdList(NICKCORE_TYPE);
+
+NickCore::NickCore(const Anope::string &coredisplay, uint64_t coreid)
+ : Serializable(NICKCORE_TYPE)
+ , chanaccess(CHANNELINFO_TYPE)
+ , id(coreid)
+ , display(coredisplay)
+ , aliases(NICKALIAS_TYPE)
{
if (coredisplay.empty())
throw CoreException("Empty display passed to NickCore constructor");
- this->o = NULL;
- this->channelcount = 0;
- this->lastmail = 0;
-
- this->display = coredisplay;
- this->id = coreid;
+ if (!NickCoreList->insert_or_assign(this->display, this).second)
+ Log(LOG_DEBUG) << "Duplicate account " << this->display << " in NickCore table";
- size_t old = NickCoreList->size();
- (*NickCoreList)[this->display] = this;
- if (old == NickCoreList->size())
- Log(LOG_DEBUG) << "Duplicate account " << coredisplay << " in nickcore table?";
-
- if (this->id)
- NickCoreIdList[this->id] = this;
+ // Upgrading users may not have an account identifier.
+ if (this->id && !NickCoreIdList->insert_or_assign(this->id, this).second)
+ Log(LOG_DEBUG) << "Duplicate account id " << this->id << " in NickCore table";
FOREACH_MOD(OnNickCoreCreate, (this));
}
@@ -59,9 +56,7 @@ NickCore::~NickCore()
NickCoreList->erase(this->display);
if (this->id)
- NickCoreIdList.erase(this->id);
-
- this->ClearAccess();
+ NickCoreIdList->erase(this->id);
if (!this->memos.memos->empty())
{
@@ -71,22 +66,32 @@ NickCore::~NickCore()
}
}
-void NickCore::Serialize(Serialize::Data &data) const
+NickCore::Type::Type()
+ : Serialize::Type(NICKCORE_TYPE)
+{
+}
+
+void NickCore::Type::Serialize(const Serializable *obj, Serialize::Data &data) const
{
- data["display"] << this->display;
- data["uniqueid"] << this->id;
- 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);
+ const auto *nc = static_cast<const NickCore *>(obj);
+ data.Store("display", nc->display);
+ data.Store("uniqueid", nc->id);
+ data.Store("pass", nc->pass);
+ data.Store("email", nc->email);
+ data.Store("language", nc->language);
+ data.Store("lastmail", nc->lastmail);
+ data.Store("time_registered", nc->time_registered);
+ data.Store("memomax", nc->memos.memomax);
+
+ std::ostringstream oss;
+ for (const auto &ignore : nc->memos.ignores)
+ oss << ignore << " ";
+ data.Store("memoignores", oss.str());
+
+ Extensible::ExtensibleSerialize(nc, nc, data);
}
-Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data)
+Serializable *NickCore::Type::Unserialize(Serializable *obj, Serialize::Data &data) const
{
NickCore *nc;
@@ -104,14 +109,8 @@ Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data)
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["lastmail"] >> nc->lastmail;
+ data["time_registered"] >> nc->time_registered;
data["memomax"] >> nc->memos.memomax;
{
Anope::string buf;
@@ -119,7 +118,7 @@ Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data)
spacesepstream sep(buf);
nc->memos.ignores.clear();
while (sep.GetToken(buf))
- nc->memos.ignores.push_back(buf);
+ nc->memos.ignores.insert(buf);
}
Extensible::ExtensibleUnserialize(nc, nc, data);
@@ -127,10 +126,6 @@ Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &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");
@@ -157,13 +152,35 @@ Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data)
b = false;
data["extensible:KILLPROTECT"] >> b;
if (b)
- nc->Extend<bool>("KILLPROTECT");
+ nc->Extend<bool>("PROTECT");
+
+ b = false;
+ data["KILLPROTECT"] >> b;
+ if (b)
+ {
+ nc->Extend<bool>("PROTECT");
+ nc->Extend("PROTECT_AFTER", Config->GetModule("nickserv").Get<time_t>("kill", "60s"));
+ }
+ b = false;
+ data["KILL_QUICK"] >> b;
+ if (b)
+ {
+ nc->Extend<bool>("PROTECT");
+ nc->Extend("PROTECT_AFTER", Config->GetModule("nickserv").Get<time_t>("killquick", "20s"));
+ }
+ b = false;
+ data["KILL_IMMED"] >> b;
+ if (b)
+ {
+ nc->Extend<bool>("PROTECT");
+ nc->Extend("PROTECT_AFTER", 0);
+ }
/* end compat */
return nc;
}
-void NickCore::SetDisplay(const NickAlias *na)
+void NickCore::SetDisplay(NickAlias *na)
{
if (na->nc != this || na->nick == this->display)
return;
@@ -171,13 +188,14 @@ void NickCore::SetDisplay(const NickAlias *na)
FOREACH_MOD(OnChangeCoreDisplay, (this, na->nick));
/* this affects the serialized aliases */
- for (unsigned i = 0; i < aliases->size(); ++i)
- aliases->at(i)->QueueUpdate();
+ for (auto *alias : *aliases)
+ alias->QueueUpdate();
/* Remove the core from the list */
NickCoreList->erase(this->display);
this->display = na->nick;
+ this->na = na;
(*NickCoreList)[this->display] = this;
}
@@ -187,67 +205,6 @@ 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];
@@ -255,7 +212,7 @@ void NickCore::AddChannelReference(ChannelInfo *ci)
void NickCore::RemoveChannelReference(ChannelInfo *ci)
{
- int& i = (*this->chanaccess)[ci];
+ int &i = (*this->chanaccess)[ci];
if (--i <= 0)
this->chanaccess->erase(ci);
}
@@ -263,11 +220,11 @@ void NickCore::RemoveChannelReference(ChannelInfo *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);
+ for (const auto &[ci, _] : *this->chanaccess)
+ queue.push_back(ci);
}
-NickCore* NickCore::Find(const Anope::string &nick)
+NickCore *NickCore::Find(const Anope::string &nick)
{
nickcore_map::const_iterator it = NickCoreList->find(nick);
if (it != NickCoreList->end())
@@ -279,36 +236,34 @@ NickCore* NickCore::Find(const Anope::string &nick)
return NULL;
}
-uint64_t NickCore::GetId()
+NickCore *NickCore::FindId(uint64_t id)
{
- if (this->id)
- return this->id;
-
- NickAlias *na = NickAlias::Find(this->display);
- if (!na)
+ auto it = NickCoreIdList->find(id);
+ if (it != NickCoreIdList->end())
{
- Log(LOG_DEBUG) << "Unable to find the display NickAlias for NickCore: " << this->display;
- return 0;
+ it->second->QueueUpdate();
+ return it->second;
}
+ return nullptr;
+}
- Anope::string secretid = this->display + "\0" + stringify(na->time_registered);
+uint64_t NickCore::GetId()
+{
+ if (this->id)
+ return this->id;
- // Generate the account id. This should almost always only have one
- // iteration but in the rare case that we generate a duplicate id we try
- // again with a new key.
+ // We base the account identifier on the account display at registration and
+ // when the account was first registered. This should be unique enough that
+ // it never collides. In the extremely rare case that it does generate a
+ // duplicate id we try with a new suffix.
+ uint64_t attempt = 0;
while (!this->id)
{
- // Generate a random key for SipHash.
- char key[16];
- for (size_t i = 0; i < sizeof(key); ++i)
- key[i] = rand() % CHAR_MAX;
-
- uint64_t newid = Anope::SipHash24(secretid.c_str(), secretid.length(), key);
- nickcoreid_map::const_iterator it = NickCoreIdList.find(newid);
- if (it == NickCoreIdList.end())
+ const auto newidstr = this->display + "\0" + Anope::ToString(this->time_registered) + "\0" + Anope::ToString(attempt++);
+ const auto newid = Anope::hash_cs()(newidstr);
+ if (NickCoreIdList->emplace(newid, this).second)
{
this->id = newid;
- NickCoreIdList[this->id] = this;
this->QueueUpdate();
break;
}
diff --git a/src/opertype.cpp b/src/opertype.cpp
index 026e5ae3d..d1a1256b3 100644
--- a/src/opertype.cpp
+++ b/src/opertype.cpp
@@ -13,7 +13,7 @@
std::vector<Oper *> Oper::opers;
-Oper::Oper(const Anope::string &n, OperType *o) : name(n), ot(o), require_oper(true)
+Oper::Oper(const Anope::string &n, OperType *o) : name(n), ot(o)
{
opers.push_back(this);
}
@@ -27,10 +27,8 @@ Oper::~Oper()
Oper *Oper::Find(const Anope::string &name)
{
- for (unsigned i = 0; i < opers.size(); ++i)
+ for (auto *o : opers)
{
- Oper *o = opers[i];
-
if (o->name.equals_ci(name))
return o;
}
@@ -40,10 +38,8 @@ Oper *Oper::Find(const Anope::string &name)
OperType *OperType::Find(const Anope::string &name)
{
- for (unsigned i = 0; i < Config->MyOperTypes.size(); ++i)
+ for (auto *ot : Config->MyOperTypes)
{
- OperType *ot = Config->MyOperTypes[i];
-
if (ot->GetName() == name)
return ot;
}
@@ -57,19 +53,15 @@ OperType::OperType(const Anope::string &nname) : name(nname)
bool OperType::HasCommand(const Anope::string &cmdstr) const
{
- for (std::list<Anope::string>::const_iterator it = this->commands.begin(), it_end = this->commands.end(); it != it_end; ++it)
+ for (const auto &command : this->commands)
{
- const Anope::string &s = *it;
-
- if (!s.find('~') && Anope::Match(cmdstr, s.substr(1)))
+ if (!command.find('~') && Anope::Match(cmdstr, command.substr(1)))
return false;
- else if (Anope::Match(cmdstr, s))
+ else if (Anope::Match(cmdstr, command))
return true;
}
- for (std::set<OperType *>::const_iterator iit = this->inheritances.begin(), iit_end = this->inheritances.end(); iit != iit_end; ++iit)
+ for (auto *ot : this->inheritances)
{
- OperType *ot = *iit;
-
if (ot->HasCommand(cmdstr))
return true;
}
@@ -79,19 +71,15 @@ bool OperType::HasCommand(const Anope::string &cmdstr) const
bool OperType::HasPriv(const Anope::string &privstr) const
{
- for (std::list<Anope::string>::const_iterator it = this->privs.begin(), it_end = this->privs.end(); it != it_end; ++it)
+ for (const auto &priv : this->privs)
{
- const Anope::string &s = *it;
-
- if (!s.find('~') && Anope::Match(privstr, s.substr(1)))
+ if (!priv.find('~') && Anope::Match(privstr, priv.substr(1)))
return false;
- else if (Anope::Match(privstr, s))
+ else if (Anope::Match(privstr, priv))
return true;
}
- for (std::set<OperType *>::const_iterator iit = this->inheritances.begin(), iit_end = this->inheritances.end(); iit != iit_end; ++iit)
+ for (auto *ot : this->inheritances)
{
- OperType *ot = *iit;
-
if (ot->HasPriv(privstr))
return true;
}
@@ -120,28 +108,24 @@ void OperType::Inherits(OperType *ot)
this->inheritances.insert(ot);
}
-const std::list<Anope::string> OperType::GetCommands() const
+std::list<Anope::string> OperType::GetCommands() const
{
std::list<Anope::string> cmd_list = this->commands;
- for (std::set<OperType *>::const_iterator it = this->inheritances.begin(), it_end = this->inheritances.end(); it != it_end; ++it)
+ for (auto *ot : this->inheritances)
{
- OperType *ot = *it;
- std::list<Anope::string> cmds = ot->GetCommands();
- for (std::list<Anope::string>::const_iterator it2 = cmds.begin(), it2_end = cmds.end(); it2 != it2_end; ++it2)
- cmd_list.push_back(*it2);
+ for (const auto &cmd : ot->GetCommands())
+ cmd_list.push_back(cmd);
}
return cmd_list;
}
-const std::list<Anope::string> OperType::GetPrivs() const
+std::list<Anope::string> OperType::GetPrivs() const
{
std::list<Anope::string> priv_list = this->privs;
- for (std::set<OperType *>::const_iterator it = this->inheritances.begin(), it_end = this->inheritances.end(); it != it_end; ++it)
+ for (auto *ot : this->inheritances)
{
- OperType *ot = *it;
- std::list<Anope::string> priv = ot->GetPrivs();
- for (std::list<Anope::string>::const_iterator it2 = priv.begin(), it2_end = priv.end(); it2 != it2_end; ++it2)
- priv_list.push_back(*it2);
+ for (const auto &priv : ot->GetPrivs())
+ priv_list.push_back(priv);
}
return priv_list;
}
diff --git a/src/pipeengine.cpp b/src/pipeengine.cpp
index 4072b6df0..5bca3d1ab 100644
--- a/src/pipeengine.cpp
+++ b/src/pipeengine.cpp
@@ -60,7 +60,7 @@ void Pipe::Write(const char *data, size_t sz)
write(this->write_pipe, data, sz);
}
-int Pipe::Read(char *data, size_t sz)
+ssize_t Pipe::Read(char *data, size_t sz)
{
return read(this->GetFD(), data, sz);
}
diff --git a/src/process.cpp b/src/process.cpp
index fdc854f47..9f2794ad6 100644
--- a/src/process.cpp
+++ b/src/process.cpp
@@ -18,61 +18,81 @@
void Anope::Process(const Anope::string &buffer)
{
- /* If debugging, log the buffer */
- Log(LOG_RAWIO) << "Received: " << buffer;
-
if (buffer.empty())
return;
Anope::map<Anope::string> tags;
Anope::string source, command;
std::vector<Anope::string> params;
-
if (!IRCD->Parse(buffer, tags, source, command, params))
return;
+ Log(LOG_RAWIO) << "Received " << buffer;
if (Anope::ProtocolDebug)
{
if (tags.empty())
- Log() << "No tags";
+ Log() << "\tNo tags";
else
- for (Anope::map<Anope::string>::const_iterator it = tags.begin(); it != tags.end(); ++it)
- Log() << "tags " << it->first << ": " << it->second;
+ {
+ for (const auto &[tname, tvalue] : tags)
+ Log() << "\tTag " << tname << ": " << tvalue;
+ }
- Log() << "Source : " << (source.empty() ? "No source" : source);
- Log() << "Command: " << command;
+ if (source.empty())
+ Log() << "\tNo source";
+ else
+ Log() << "\tSource: " << source;
+
+ Log() << "\tCommand: " << command;
if (params.empty())
- Log() << "No params";
+ Log() << "\tNo params";
else
- for (unsigned i = 0; i < params.size(); ++i)
- Log() << "params " << i << ": " << params[i];
+ {
+ for (size_t i = 0; i < params.size(); ++i)
+ Log() << "\tParam " << i << ": " << params[i];
+ }
}
- 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));
+ FOREACH_RESULT(OnMessage, MOD_RESULT, (src, command, params, tags));
if (MOD_RESULT == EVENT_STOP)
return;
+ ProcessInternal(src, command, params, tags);
+}
+
+void Anope::ProcessInternal(MessageSource &src, const Anope::string &command, const std::vector<Anope::string> &params, const Anope::map<Anope::string> & tags)
+{
+ static const Anope::string proto_name = ModuleManager::FindFirstOf(PROTOCOL) ? ModuleManager::FindFirstOf(PROTOCOL)->name : "";
ServiceReference<IRCDMessage> m("IRCDMessage", proto_name + "/" + command.lower());
if (!m)
{
- Log(LOG_DEBUG) << "unknown message from server (" << buffer << ")";
+ Log(LOG_DEBUG) << "unknown message from server: " << command;
return;
}
- if (m->HasFlag(IRCDMESSAGE_SOFT_LIMIT) ? (params.size() < m->GetParamCount()) : (params.size() != m->GetParamCount()))
+ if (m->HasFlag(IRCDMessage::FLAG_SOFT_LIMIT) ? (params.size() < m->GetParamCount()) : (params.size() != m->GetParamCount()))
Log(LOG_DEBUG) << "invalid parameters for " << 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;
+ else if (m->HasFlag(IRCDMessage::FLAG_REQUIRE_USER) && !src.GetUser())
+ Log(LOG_DEBUG) << "unexpected non-user source " << src.GetSource() << " for " << command;
+ else if (m->HasFlag(IRCDMessage::FLAG_REQUIRE_SERVER) && !src.GetSource().empty() && !src.GetServer())
+ Log(LOG_DEBUG) << "unexpected non-server source " << src.GetSource() << " for " << command;
else
- m->Run(src, params, tags);
+ {
+ try
+ {
+ m->Run(src, params, tags);
+ }
+ catch (const ProtocolException &err)
+ {
+ IRCD->SendError(err.GetReason());
+ Anope::QuitReason = "Protocol error: " + err.GetReason();
+ Anope::Quitting = true;
+ Anope::ReturnValue = EXIT_FAILURE;
+ }
+ }
}
bool IRCDProto::Parse(const Anope::string &buffer, Anope::map<Anope::string> &tags, Anope::string &source, Anope::string &command, std::vector<Anope::string> &params)
@@ -123,17 +143,76 @@ bool IRCDProto::Parse(const Anope::string &buffer, Anope::map<Anope::string> &ta
return true;
}
-Anope::string IRCDProto::Format(const Anope::string &source, const Anope::string &message)
+bool IRCDProto::Format(Anope::string &message, const Anope::map<Anope::string> &tags, const MessageSource &source, const Anope::string &command, const std::vector<Anope::string> &params)
{
- if (!source.empty())
- return ":" + source + " " + message;
- else
- return message;
+ std::stringstream buffer;
+ if (!tags.empty())
+ {
+ char separator = '@';
+ for (const auto &[tname, tvalue] : tags)
+ {
+ if (IRCD->IsTagValid(tname, tvalue))
+ {
+ buffer << separator << tname;
+ if (!tvalue.empty())
+ buffer << '=' << tvalue;
+ separator = ';';
+ }
+ }
+ if (separator != '@')
+ buffer << ' ';
+ }
+
+ if (source.GetServer())
+ {
+ const auto *s = source.GetServer();
+ if (s != Me && !s->IsJuped())
+ {
+ Log(LOG_DEBUG) << "Attempted to send \"" << command << "\" from " << s->GetName() << " who is not from me";
+ return false;
+ }
+
+ buffer << ':' << s->GetSID() << ' ';
+ }
+ else if (source.GetUser())
+ {
+ const auto *u = source.GetUser();
+ if (u->server != Me && !u->server->IsJuped())
+ {
+ Log(LOG_DEBUG) << "Attempted to send \"" << command << "\" from " << u->nick << " who is not from me";
+ return false;
+ }
+
+ const auto *bi = source.GetBot();
+ if (bi && !bi->introduced)
+ {
+ Log(LOG_DEBUG) << "Attempted to send \"" << command << "\" from " << bi->nick << " when not introduced";
+ return false;
+ }
+
+ buffer << ':' << u->GetUID() << ' ';
+ }
+
+ buffer << command;
+ if (!params.empty())
+ {
+ buffer << ' ';
+ for (auto it = params.begin(); it != params.end() - 1; ++it)
+ buffer << *it << ' ';
+
+
+ const auto &last = params.back();
+ if (last.empty() || last[0] == ':' || last.find(' ') != Anope::string::npos)
+ buffer << ':';
+ buffer << last;
+ }
+
+ message = buffer.str();
+ return true;
}
MessageTokenizer::MessageTokenizer(const Anope::string &msg)
: message(msg)
- , position(0)
{
}
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 26a248a95..7a167582a 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -18,17 +18,18 @@
#include "uplink.h"
#include "bots.h"
#include "channels.h"
+#include "numeric.h"
IRCDProto *IRCD = NULL;
-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, "IRCDProto", creator->name)
+ , proto_name(p)
+ , MaxChannel(Config->GetBlock("networkinfo").Get<unsigned>("chanlen", "32"))
+ , MaxHost(Config->GetBlock("networkinfo").Get<unsigned>("hostlen", "64"))
+ , MaxNick(Config->GetBlock("networkinfo").Get<unsigned>("nicklen", "31"))
+ , MaxUser(Config->GetBlock("networkinfo").Get<unsigned>("userlen", "10"))
{
- 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;
}
@@ -39,11 +40,6 @@ IRCDProto::~IRCDProto()
IRCD = NULL;
}
-const Anope::string &IRCDProto::GetProtocolName()
-{
- return this->proto_name;
-}
-
static inline char nextID(int pos, Anope::string &buf)
{
char &c = buf[pos];
@@ -80,7 +76,7 @@ Anope::string IRCDProto::SID_Retrieve()
if (!IRCD || !IRCD->RequiresID)
return "";
- static Anope::string current_sid = Config->GetBlock("serverinfo")->Get<const Anope::string>("id");
+ static Anope::string current_sid = Config->GetBlock("serverinfo").Get<const Anope::string>("id");
if (current_sid.empty())
current_sid = "00A";
@@ -94,179 +90,112 @@ Anope::string IRCDProto::SID_Retrieve()
return current_sid;
}
+time_t IRCDProto::ExtractTimestamp(const Anope::string &str)
+{
+ auto ts = Anope::TryConvert<time_t>(str);
+ if (!ts.has_value())
+ throw ProtocolException("Invalid timestamp: " + str);
+ return ts.value();
+}
+
+void IRCDProto::SendError(const Anope::string &reason)
+{
+ Uplink::Send("ERROR", reason);
+}
+
void IRCDProto::SendKill(const MessageSource &source, const Anope::string &target, const Anope::string &reason)
{
- UplinkSocket::Message(source) << "KILL " << target << " :" << reason;
+ Uplink::Send(source, "KILL", target, reason);
}
-void IRCDProto::SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf)
+void IRCDProto::SendSVSKill(const MessageSource &source, User *user, const Anope::string &buf)
{
- UplinkSocket::Message(source) << "KILL " << user->GetUID() << " :" << buf;
+ Uplink::Send(source, "KILL", user->GetUID(), buf);
}
-void IRCDProto::SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf)
+void IRCDProto::SendModeInternal(const MessageSource &source, Channel *chan, const Anope::string &modes, const std::vector<Anope::string> &values)
{
- UplinkSocket::Message(source) << "MODE " << dest->name << " " << buf;
+ auto params = values;
+ params.insert(params.begin(), { chan->name, modes });
+ Uplink::SendInternal({}, source, "MODE", params);
}
-void IRCDProto::SendModeInternal(const MessageSource &source, User *dest, const Anope::string &buf)
+void IRCDProto::SendModeInternal(const MessageSource &source, User *dest, const Anope::string &modes, const std::vector<Anope::string> &values)
{
- UplinkSocket::Message(source) << "MODE " << dest->GetUID() << " " << buf;
+ auto params = values;
+ params.insert(params.begin(), { dest->GetUID(), modes });
+ Uplink::SendInternal({}, source, "MODE", params);
}
-void IRCDProto::SendKickInternal(const MessageSource &source, const Channel *c, User *u, const Anope::string &r)
+void IRCDProto::SendKick(const MessageSource &source, const Channel *c, User *u, const Anope::string &r)
{
if (!r.empty())
- UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID() << " :" << r;
+ Uplink::Send(source, "KICK", c->name, u->GetUID(), r);
else
- UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID();
+ Uplink::Send(source, "KICK", c->name, u->GetUID());
}
-void IRCDProto::SendNoticeInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &msg)
+void IRCDProto::SendNotice(const MessageSource &source, const Anope::string &dest, const Anope::string &msg, const Anope::map<Anope::string> &tags)
{
- UplinkSocket::Message(source) << "NOTICE " << dest << " :" << msg;
+ Uplink::Send(tags, source, "NOTICE", dest, msg.empty() ? " " : msg);
}
-void IRCDProto::SendPrivmsgInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf)
+void IRCDProto::SendPrivmsg(const MessageSource &source, const Anope::string &dest, const Anope::string &msg, const Anope::map<Anope::string> &tags)
{
- UplinkSocket::Message(source) << "PRIVMSG " << dest << " :" << buf;
+ Uplink::Send(tags, source, "PRIVMSG", dest, msg.empty() ? " " : msg);
}
-void IRCDProto::SendQuitInternal(User *u, const Anope::string &buf)
+void IRCDProto::SendTagmsg(const MessageSource &source, const Anope::string &dest, const Anope::map<Anope::string> &tags)
{
- if (!buf.empty())
- UplinkSocket::Message(u) << "QUIT :" << buf;
- else
- UplinkSocket::Message(u) << "QUIT";
+ if (CanTagMessage)
+ Uplink::Send(tags, source, "TAGMSG", dest);
}
-void IRCDProto::SendPartInternal(User *u, const Channel *chan, const Anope::string &buf)
+void IRCDProto::SendQuit(User *u, const Anope::string &buf, const Anope::string &operbuf)
{
if (!buf.empty())
- UplinkSocket::Message(u) << "PART " << chan->name << " :" << buf;
+ Uplink::Send(u, "QUIT", buf);
else
- UplinkSocket::Message(u) << "PART " << chan->name;
+ Uplink::Send(u, "QUIT");
}
-void IRCDProto::SendGlobopsInternal(const MessageSource &source, const Anope::string &buf)
+void IRCDProto::SendPart(User *u, const Channel *chan, const Anope::string &buf)
{
- UplinkSocket::Message(source) << "GLOBOPS :" << buf;
+ if (!buf.empty())
+ Uplink::Send(u, "PART", chan->name, buf);
+ else
+ Uplink::Send(u, "PART", chan->name);
}
-void IRCDProto::SendCTCPInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf)
+void IRCDProto::SendGlobops(const MessageSource &source, const Anope::string &message)
{
- Anope::string s = Anope::NormalizeBuffer(buf);
- this->SendNoticeInternal(source, dest, "\1" + s + "\1");
+ Uplink::Send(source, "GLOBOPS", message);
}
-void IRCDProto::SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf)
+void IRCDProto::SendNumericInternal(int numeric, const Anope::string &dest, const std::vector<Anope::string> &params)
{
- Anope::string n = stringify(numeric);
+ Anope::string n = Anope::ToString(numeric);
if (numeric < 10)
n = "0" + n;
if (numeric < 100)
n = "0" + n;
- UplinkSocket::Message(Me) << n << " " << dest << " " << buf;
-}
-
-void IRCDProto::SendTopic(const MessageSource &source, Channel *c)
-{
- UplinkSocket::Message(source) << "TOPIC " << c->name << " :" << c->topic;
-}
-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);
+ auto newparams = params;
+ newparams.insert(newparams.begin(), dest);
+ Uplink::SendInternal({}, Me, n, newparams);
}
-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, ...)
+void IRCDProto::SendTopic(const MessageSource &source, Channel *c)
{
- va_list args;
- char buf[BUFSIZE] = "";
- va_start(args, fmt);
- vsnprintf(buf, BUFSIZE - 1, fmt, args);
- va_end(args);
- SendQuitInternal(u, buf);
+ Uplink::Send(source, "TOPIC", c->name, c->topic);
}
void IRCDProto::SendPing(const Anope::string &servname, const Anope::string &who)
{
if (servname.empty())
- UplinkSocket::Message(Me) << "PING " << who;
+ Uplink::Send("PING", who);
else
- UplinkSocket::Message(Me) << "PING " << servname << " " << who;
+ Uplink::Send("PING", servname, who);
}
/**
@@ -278,74 +207,29 @@ void IRCDProto::SendPing(const Anope::string &servname, const Anope::string &who
void IRCDProto::SendPong(const Anope::string &servname, const Anope::string &who)
{
if (servname.empty())
- UplinkSocket::Message(Me) << "PONG " << who;
+ Uplink::Send("PONG", who);
else
- UplinkSocket::Message(Me) << "PONG " << servname << " " << who;
+ Uplink::Send("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);
+ Uplink::Send(source, "INVITE", u->GetUID(), c->name);
}
void IRCDProto::SendSquit(Server *s, const Anope::string &message)
{
- UplinkSocket::Message() << "SQUIT " << s->GetSID() << " :" << message;
+ Uplink::Send("SQUIT", s->GetSID(), message);
}
void IRCDProto::SendNickChange(User *u, const Anope::string &newnick)
{
- UplinkSocket::Message(u) << "NICK " << newnick << " " << Anope::CurTime;
+ Uplink::Send(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);
+ Uplink::Send("SVSNICK", u->GetUID(), newnick, when);
}
bool IRCDProto::IsNickValid(const Anope::string &nick)
@@ -364,10 +248,10 @@ bool IRCDProto::IsNickValid(const Anope::string &nick)
Anope::string special = "[]\\`_^{|}";
for (unsigned i = 0; i < nick.length(); ++i)
- if (!(nick[i] >= 'A' && nick[i] <= 'Z') && !(nick[i] >= 'a' && nick[i] <= 'z')
+ 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] != '-')))
+ && (!i || ((nick[i] < '0' || nick[i] > '9') && nick[i] != '-')))
return false;
return true;
@@ -375,7 +259,7 @@ bool IRCDProto::IsNickValid(const Anope::string &nick)
bool IRCDProto::IsChannelValid(const Anope::string &chan)
{
- if (chan.empty() || chan[0] != '#' || chan.length() > Config->GetBlock("networkinfo")->Get<unsigned>("chanlen"))
+ if (chan.empty() || chan[0] != '#' || chan.length() > IRCD->MaxChannel)
return false;
if (chan.find_first_of(" ,") != Anope::string::npos)
@@ -386,13 +270,11 @@ bool IRCDProto::IsChannelValid(const Anope::string &chan)
bool IRCDProto::IsIdentValid(const Anope::string &ident)
{
- if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen"))
+ if (ident.empty() || ident.length() > IRCD->MaxUser)
return false;
- for (unsigned i = 0; i < ident.length(); ++i)
+ for (auto c : ident)
{
- const char &c = ident[i];
-
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-')
continue;
@@ -404,11 +286,11 @@ bool IRCDProto::IsIdentValid(const Anope::string &ident)
bool IRCDProto::IsHostValid(const Anope::string &host)
{
- if (host.empty() || host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen"))
+ if (host.empty() || host.length() > IRCD->MaxHost)
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<const Anope::string>("disallow_start_or_end"),
+ vhostchars = Config->GetBlock("networkinfo").Get<const Anope::string>("vhost_chars");
if (vhostdisablebe.find_first_of(host[0]) != Anope::string::npos)
return false;
@@ -416,31 +298,26 @@ bool IRCDProto::IsHostValid(const Anope::string &host)
return false;
int dots = 0;
- for (unsigned i = 0; i < host.length(); ++i)
+ for (auto chr : host)
{
- if (host[i] == '.')
+ if (chr == '.')
++dots;
- if (vhostchars.find_first_of(host[i]) == Anope::string::npos)
+ if (vhostchars.find_first_of(chr) == Anope::string::npos)
return false;
}
- return dots > 0 || Config->GetBlock("networkinfo")->Get<bool>("allow_undotted_vhosts");
+ 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)");
+ SendNumeric(RPL_YOUREOPER, u->GetUID(), "You are now an IRC operator (set by services)");
u->SetMode(NULL, "OPER");
}
-unsigned IRCDProto::GetMaxListFor(Channel *c)
-{
- return c->HasMode("LBAN") ? 0 : Config->GetBlock("networkinfo")->Get<int>("modelistsize");
-}
-
-unsigned IRCDProto::GetMaxListFor(Channel *c, ChannelMode *cm)
+size_t IRCDProto::GetMaxListFor(Channel *c, ChannelMode *cm)
{
- return GetMaxListFor(c);
+ return c->HasMode("LBAN") ? 0 : Config->GetBlock("networkinfo").Get<size_t>("modelistsize", "100");
}
Anope::string IRCDProto::NormalizeMask(const Anope::string &mask)
@@ -450,7 +327,21 @@ Anope::string IRCDProto::NormalizeMask(const Anope::string &mask)
return Entry("", mask).GetNUHMask();
}
-MessageSource::MessageSource(const Anope::string &src) : source(src), u(NULL), s(NULL)
+void IRCDProto::SendContextNotice(BotInfo *bi, User *target, Channel *context, const Anope::string &msg)
+{
+ IRCD->SendNotice(bi, target->GetUID(), Anope::printf("[%s] %s", context->name.c_str(), msg.c_str()), {
+ { "+draft/channel-context", context->name },
+ });
+}
+
+void IRCDProto::SendContextPrivmsg(BotInfo *bi, User *target, Channel *context, const Anope::string &msg)
+{
+ IRCD->SendPrivmsg(bi, target->GetUID(), Anope::printf("[%s] %s", context->name.c_str(), msg.c_str()), {
+ { "+draft/channel-context", context->name },
+ });
+}
+
+MessageSource::MessageSource(const Anope::string &src) : source(src)
{
/* no source for incoming message is our uplink */
if (src.empty())
@@ -461,11 +352,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)
{
}
@@ -499,18 +390,9 @@ 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)
-{
-}
-
-unsigned IRCDMessage::GetParamCount() const
+IRCDMessage::IRCDMessage(Module *o, const Anope::string &n, size_t pc)
+ : Service(o, "IRCDMessage", o->name + "/" + n.lower())
+ , name(n)
+ , param_count(pc)
{
- return this->param_count;
}
-
-void IRCDMessage::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
-{
- // Most IRCds don't support message tags yet so use the tagless variant.
- Run(source, params);
-}
-
diff --git a/src/regchannel.cpp b/src/regchannel.cpp
index 6dbd9df55..f45803e06 100644
--- a/src/regchannel.cpp
+++ b/src/regchannel.cpp
@@ -19,9 +19,10 @@
#include "bots.h"
#include "servers.h"
-Serialize::Checker<registered_channel_map> RegisteredChannelList("ChannelInfo");
+Serialize::Checker<registered_channel_map> RegisteredChannelList(CHANNELINFO_TYPE);
-AutoKick::AutoKick() : Serializable("AutoKick")
+AutoKick::AutoKick()
+ : Serializable(AUTOKICK_TYPE)
{
}
@@ -38,32 +39,40 @@ AutoKick::~AutoKick()
}
}
-void AutoKick::Serialize(Serialize::Data &data) const
+AutoKick::Type::Type()
+ : Serialize::Type(AUTOKICK_TYPE)
{
- data["ci"] << this->ci->name;
- if (this->nc)
- data["nc"] << this->nc->display;
+}
+
+void AutoKick::Type::Serialize(const Serializable *obj, Serialize::Data &data) const
+{
+ const auto *ak = static_cast<const AutoKick *>(obj);
+ data.Store("ci", ak->ci->name);
+ if (ak->nc)
+ data.Store("ncid", ak->nc->GetId());
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;
+ data.Store("mask", ak->mask);
+ data.Store("reason", ak->reason);
+ data.Store("creator", ak->creator);
+ data.Store("addtime", ak->addtime);
+ data.Store("last_used", ak->last_used);
}
-Serializable* AutoKick::Unserialize(Serializable *obj, Serialize::Data &data)
+Serializable *AutoKick::Type::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string sci, snc;
+ uint64_t sncid = 0;
data["ci"] >> sci;
- data["nc"] >> snc;
+ data["nc"] >> snc; // Deprecated 2.0 field
+ data["ncid"] >> sncid;
ChannelInfo *ci = ChannelInfo::Find(sci);
if (!ci)
return NULL;
AutoKick *ak;
- NickCore *nc = NickCore::Find(snc);
+ auto *nc = sncid ? NickCore::FindId(sncid) : NickCore::Find(snc);
if (obj)
{
ak = anope_dynamic_static_cast<AutoKick *>(obj);
@@ -95,37 +104,31 @@ Serializable* AutoKick::Unserialize(Serializable *obj, Serialize::Data &data)
return ak;
}
-ChannelInfo::ChannelInfo(const Anope::string &chname) : Serializable("ChannelInfo"),
- access("ChanAccess"), akick("AutoKick")
+ChannelInfo::ChannelInfo(const Anope::string &chname)
+ : Serializable(CHANNELINFO_TYPE)
+ , access(CHANACCESS_TYPE)
+ , akick(AUTOKICK_TYPE)
+ , name(chname)
+ , time_registered(Anope::CurTime)
+ , last_used(Anope::CurTime)
{
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())
+ if (!RegisteredChannelList->insert_or_assign(this->name, this).second)
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")
+ChannelInfo::ChannelInfo(const ChannelInfo &ci)
+ : Serializable(CHANNELINFO_TYPE)
+ , access(CHANACCESS_TYPE)
+ , akick(AUTOKICK_TYPE)
{
*this = ci;
@@ -178,43 +181,56 @@ ChannelInfo::~ChannelInfo()
}
}
-void ChannelInfo::Serialize(Serialize::Data &data) const
+ChannelInfo::Type::Type()
+ : Serialize::Type(CHANNELINFO_TYPE)
{
- 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;
+}
+
+void ChannelInfo::Type::Serialize(const Serializable *obj, Serialize::Data &data) const
+{
+ const auto *ci = static_cast<const ChannelInfo *>(obj);
+
+ data.Store("name", ci->name);
+ if (ci->founder)
+ data.Store("founderid", ci->founder->GetId());
+ if (ci->successor)
+ data.Store("successorid", ci->successor->GetId());
+ data.Store("description", ci->desc);
+ data.Store("time_registered", ci->time_registered);
+ data.Store("last_used", ci->last_used);
+ data.Store("last_topic", ci->last_topic);
+ data.Store("last_topic_setter", ci->last_topic_setter);
+ data.Store("last_topic_time", ci->last_topic_time);
+ data.Store("bantype", ci->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;
+ for (const auto &[name, level] : ci->levels)
+ levels_buffer += name + " " + Anope::ToString(level) + " ";
+ data.Store("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] << " ";
+ if (ci->bi)
+ data.Store("bi", ci->bi->nick);
+ data.Store("banexpire", ci->banexpire);
+ data.Store("memomax", ci->memos.memomax);
+
+ std::ostringstream oss;
+ for (const auto &ignore : ci->memos.ignores)
+ oss << ignore << " ";
+ data.Store("memoignores", oss.str());
- Extensible::ExtensibleSerialize(this, this, data);
+ Extensible::ExtensibleSerialize(ci, ci, data);
}
-Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data)
+Serializable *ChannelInfo::Type::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string sname, sfounder, ssuccessor, slevels, sbi;
+ uint64_t sfounderid = 0, ssuccessorid = 0;
data["name"] >> sname;
- data["founder"] >> sfounder;
- data["successor"] >> ssuccessor;
+ data["founder"] >> sfounder; // Deprecated 2.0 field
+ data["founderid"] >> sfounderid;
+ data["successor"] >> ssuccessor; // Deprecated 2.0 field
+ data["successorid"] >> ssuccessorid;
data["levels"] >> slevels;
data["bi"] >> sbi;
@@ -224,8 +240,8 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data)
else
ci = new ChannelInfo(sname);
- ci->SetFounder(NickCore::Find(sfounder));
- ci->SetSuccessor(NickCore::Find(ssuccessor));
+ ci->SetFounder(sfounderid ? NickCore::FindId(sfounderid) : NickCore::Find(sfounder));
+ ci->SetSuccessor(ssuccessorid ? NickCore::FindId(ssuccessorid) : NickCore::Find(ssuccessor));
data["description"] >> ci->desc;
data["time_registered"] >> ci->time_registered;
@@ -238,11 +254,14 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data)
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 &) { }
+ {
+ // Begin 2.0 database compatibility.
+ if (v[i] == "FANTASIA")
+ v[i] = "FANTASY";
+ // End 2.0 database compatibility.
+ if (auto level = Anope::TryConvert<int16_t>(v[i + 1]))
+ ci->levels[v[i]] = level.value();
+ }
}
BotInfo *bi = BotInfo::Find(sbi, true);
if (*ci->bi != bi)
@@ -260,7 +279,7 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data)
spacesepstream sep(buf);
ci->memos.ignores.clear();
while (sep.GetToken(buf))
- ci->memos.ignores.push_back(buf);
+ ci->memos.ignores.insert(buf);
}
Extensible::ExtensibleUnserialize(ci, ci, data);
@@ -268,10 +287,6 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &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");
@@ -423,18 +438,10 @@ AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed)
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;
+ group.nc = u->Account();
FindMatches(group, this, u, u->Account());
@@ -443,12 +450,10 @@ AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed)
if (updateLastUsed)
this->last_used = Anope::CurTime;
- for (unsigned i = 0; i < group.paths.size(); ++i)
+ for (auto &p : group.paths)
{
- ChanAccess::Path &p = group.paths[i];
-
- for (unsigned int j = 0; j < p.size(); ++j)
- p[j]->last_seen = Anope::CurTime;
+ for (auto *ca : p)
+ ca->last_seen = Anope::CurTime;
}
}
@@ -527,7 +532,7 @@ void ChannelInfo::ClearAccess()
AutoKick *ChannelInfo::AddAkick(const Anope::string &user, NickCore *akicknc, const Anope::string &reason, time_t t, time_t lu)
{
- AutoKick *autokick = new AutoKick();
+ auto *autokick = new AutoKick();
autokick->ci = this;
autokick->nc = akicknc;
autokick->reason = reason;
@@ -544,7 +549,7 @@ AutoKick *ChannelInfo::AddAkick(const Anope::string &user, NickCore *akicknc, co
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();
+ auto *autokick = new AutoKick();
autokick->ci = this;
autokick->mask = mask;
autokick->nc = NULL;
@@ -646,7 +651,7 @@ Anope::string ChannelInfo::GetIdealBan(User *u) const
}
}
-ChannelInfo* ChannelInfo::Find(const Anope::string &name)
+ChannelInfo *ChannelInfo::Find(const Anope::string &name)
{
registered_channel_map::const_iterator it = RegisteredChannelList->find(name);
if (it != RegisteredChannelList->end())
@@ -688,6 +693,6 @@ void ChannelInfo::RemoveChannelReference(const Anope::string &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);
+ for (auto &[chan, _] : references)
+ chans.push_back(chan);
}
diff --git a/src/serialize.cpp b/src/serialize.cpp
index faf8d0e4a..d820157b4 100644
--- a/src/serialize.cpp
+++ b/src/serialize.cpp
@@ -27,21 +27,25 @@ std::list<Serializable *> *Serializable::SerializableItems;
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);
+ static NickCore::Type nc;
+ static NickAlias::Type na;
+ static BotInfo::Type bi;
+ static ChannelInfo::Type ci;
+ static ChanAccess::Type access;
+ static AutoKick::Type akick;
+ static Memo::Type memo;
+ static XLine::Type xline;
}
void Serialize::CheckTypes()
{
- for (std::map<Anope::string, Serialize::Type *>::const_iterator it = Serialize::Type::GetTypes().begin(), it_end = Serialize::Type::GetTypes().end(); it != it_end; ++it)
+ for (const auto &[_, t] : Serialize::Type::GetTypes())
{
- Serialize::Type *t = it->second;
t->Check();
}
}
-Serializable::Serializable(const Anope::string &serialize_type) : last_commit(0), last_commit_time(0), id(0), redis_ignore(0)
+Serializable::Serializable(const Anope::string &serialize_type)
{
if (SerializableItems == NULL)
SerializableItems = new std::list<Serializable *>();
@@ -55,7 +59,7 @@ Serializable::Serializable(const Anope::string &serialize_type) : last_commit(0)
FOREACH_MOD(OnSerializableConstruct, (this));
}
-Serializable::Serializable(const Serializable &other) : last_commit(0), last_commit_time(0), id(0), redis_ignore(0)
+Serializable::Serializable(const Serializable &other)
{
SerializableItems->push_back(this);
this->s_iter = SerializableItems->end();
@@ -112,7 +116,22 @@ const std::list<Serializable *> &Serializable::GetItems()
return *SerializableItems;
}
-Type::Type(const Anope::string &n, unserialize_func f, Module *o) : name(n), unserialize(f), owner(o), timestamp(0)
+Serialize::DataType Serialize::Data::GetType(const Anope::string &key) const
+{
+ auto it = this->types.find(key);
+ if (it != this->types.end())
+ return it->second;
+ return Serialize::DataType::TEXT;
+}
+
+void Serialize::Data::SetType(const Anope::string &key, Serialize::DataType dt)
+{
+ this->types[key] = dt;
+}
+
+Type::Type(const Anope::string &n, Module *o)
+ : name(n)
+ , owner(o)
{
TypeOrder.push_back(this->name);
Types[this->name] = this;
@@ -124,13 +143,13 @@ Type::~Type()
{
/* 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)
+ {
+ for (auto *s : *Serializable::SerializableItems)
{
- Serializable *s = *it;
-
if (s->s_type == this)
s->s_type = NULL;
}
+ }
std::vector<Anope::string>::iterator it = std::find(TypeOrder.begin(), TypeOrder.end(), this->name);
if (it != TypeOrder.end())
@@ -138,21 +157,11 @@ Type::~Type()
Types.erase(this->name);
}
-Serializable *Type::Unserialize(Serializable *obj, Serialize::Data &data)
-{
- return this->unserialize(obj, data);
-}
-
void Type::Check()
{
FOREACH_MOD(OnSerializeCheck, (this));
}
-time_t Type::GetTimestamp() const
-{
- return this->timestamp;
-}
-
void Type::UpdateTimestamp()
{
this->timestamp = Anope::CurTime;
@@ -165,13 +174,3 @@ Type *Serialize::Type::Find(const Anope::string &name)
return it->second;
return NULL;
}
-
-const std::vector<Anope::string> &Type::GetTypeOrder()
-{
- return TypeOrder;
-}
-
-const std::map<Anope::string, Serialize::Type *>& Type::GetTypes()
-{
- return Types;
-}
diff --git a/src/servers.cpp b/src/servers.cpp
index a945d1642..9f98aeb07 100644
--- a/src/servers.cpp
+++ b/src/servers.cpp
@@ -27,7 +27,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 shops, const Anope::string &desc, const Anope::string &ssid, bool jupe) : name(sname), hops(shops), description(desc), sid(ssid), uplink(up)
{
syncing = true;
juped = jupe;
@@ -48,27 +48,32 @@ Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Ano
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)
+ for (auto &[_, bi] : *BotListByNick)
{
- BotInfo *bi = it->second;
- Anope::string modes = !bi->botmodes.empty() ? ("+" + bi->botmodes) : IRCD->DefaultPseudoclientModes;
+ spacesepstream modesep(bi->botmodes.empty() ? IRCD->DefaultPseudoclientModes : "+" + bi->botmodes);
- bi->SetModesInternal(bi, modes.c_str());
- for (unsigned i = 0; i < bi->botchannels.size(); ++i)
+ Anope::string modechars;
+ modesep.GetToken(modechars);
+
+ std::vector<Anope::string> modeparams;
+ modesep.GetTokens(modeparams);
+
+ bi->SetModesInternal(bi, modechars, modeparams);
+ for (const auto &botchannel : bi->botchannels)
{
- size_t h = bi->botchannels[i].find('#');
+ size_t h = botchannel.find('#');
if (h == Anope::string::npos)
continue;
- Anope::string chname = bi->botchannels[i].substr(h);
+ Anope::string chname = botchannel.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)
+ Anope::string want_modes = botchannel.substr(0, h);
+ for (char want_mode : want_modes)
{
- ChannelMode *cm = ModeManager::FindChannelModeByChar(want_modes[j]);
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(want_mode);
if (cm == NULL)
- cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_modes[j]));
+ cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_mode));
if (cm && cm->type == MODE_STATUS)
{
MessageSource ms = bi;
@@ -81,19 +86,15 @@ Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Ano
IRCD->SendBOB();
- for (unsigned i = 0; i < Me->GetLinks().size(); ++i)
+ for (auto *link : Me->GetLinks())
{
- Server *s = Me->GetLinks()[i];
-
- if (s->juped)
- IRCD->SendServer(s);
+ if (link->juped)
+ IRCD->SendServer(link);
}
/* We make the bots go online */
- for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
+ for (const auto &[_, u] : UserListByNick)
{
- User *u = it->second;
-
BotInfo *bi = BotInfo::Find(u->GetUID());
if (bi)
{
@@ -106,22 +107,22 @@ Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Ano
bi->introduced = true;
}
- for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
+ for (const auto &[_, c] : ChannelList)
{
- 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 (const auto &[_, uc] : c->users)
+ IRCD->SendJoin(uc->user, c, &uc->status);
+ }
- for (Channel::ModeList::const_iterator it2 = c->GetModes().begin(); it2 != c->GetModes().end(); ++it2)
+ for (const auto &[mode, value] : c->GetModes())
{
- ChannelMode *cm = ModeManager::FindChannelModeByName(it2->first);
+ ChannelMode *cm = ModeManager::FindChannelModeByName(mode);
if (!cm || cm->type != MODE_LIST)
continue;
- ModeManager::StackerAdd(c->WhoSends(), c, cm, true, it2->second);
+ ModeManager::StackerAdd(c->WhoSends(), c, cm, true, value);
}
if (!c->topic.empty() && !c->topic_setter.empty())
@@ -139,10 +140,8 @@ Server::~Server()
{
Log(this, "quit") << "quit from " << (this->uplink ? this->uplink->GetName() : "no uplink") << " for " << this->quit_reason;
- for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
+ for (const auto &[_, u] : UserListByNick)
{
- User *u = it->second;
-
if (u->server == this)
{
u->Quit(this->quit_reason);
@@ -259,8 +258,8 @@ void Server::Sync(bool sync_links)
if (sync_links && !this->links.empty())
{
- for (unsigned i = 0, j = this->links.size(); i < j; ++i)
- this->links[i]->Sync(true);
+ for (auto *link : this->links)
+ link->Sync(true);
}
bool me = this->GetUplink() && this->GetUplink() == Me;
@@ -309,9 +308,11 @@ bool Server::IsULined() const
if (this == Me)
return true;
- for (unsigned i = 0; i < Config->Ulines.size(); ++i)
- if (Config->Ulines[i].equals_ci(this->GetName()))
+ for (const auto &uline : Config->Ulines)
+ {
+ if (uline.equals_ci(this->GetName()))
return true;
+ }
return false;
}
@@ -327,7 +328,7 @@ bool Server::IsQuitting() const
void Server::Notice(BotInfo *source, const Anope::string &message)
{
- if (Config->UsePrivmsg && Config->DefPrivmsg)
+ if (Config->DefPrivmsg)
IRCD->SendGlobalPrivmsg(source, this, message);
else
IRCD->SendGlobalNotice(source, this, message);
@@ -351,10 +352,12 @@ Server *Server::Find(const Anope::string &name, bool name_only)
return NULL;
}
-Server* Servers::GetUplink()
+Server *Servers::GetUplink()
{
- for (unsigned i = 0; Me && i < Me->GetLinks().size(); ++i)
- if (!Me->GetLinks()[i]->IsJuped())
- return Me->GetLinks()[i];
+ for (auto *link : Me->GetLinks())
+ {
+ if (!link->IsJuped())
+ return link;
+ }
return NULL;
}
diff --git a/src/siphash.cpp b/src/siphash.cpp
deleted file mode 100644
index 78571c390..000000000
--- a/src/siphash.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/* SipHash-2-4 routines.
- *
- * (C) 2003-2025 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.
- */
-
-/* <MIT License>
- Copyright (c) 2013 Marek Majkowski <marek@popcount.org>
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- </MIT License>
- Original location:
- https://github.com/majek/csiphash/
- Solution inspired by code from:
- Samuel Neves (supercop/crypto_auth/siphash24/little)
- djb (supercop/crypto_auth/siphash24/little2)
- Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c)
-*/
-
-#include "services.h"
-#include "anope.h"
-
-// WARNING: This ifdef maze could be a lot simpler but unfortunately
-// that will cause find_includes to be unable to parse it.
-
-#ifdef __APPLE__
-# include <libkern/OSByteOrder.h>
-# define _le64toh(x) OSSwapLittleToHostInt64(x)
-#endif
-
-#ifdef __FreeBSD__
-# include <sys/endian.h>
-# define _le64toh(x) le64toh(x)
-#endif
-
-#ifdef __linux__
-# include <endian.h>
-#endif
-
-#ifdef __NetBSD__
-# include <sys/endian.h>
-# define _le64toh(x) le64toh(x)
-#endif
-
-#ifdef __OpenBSD__
-# include <sys/endian.h>
-# define _le64toh(x) le64toh(x)
-#endif
-
-// Windows is always little endian.
-#ifdef _WIN32
-# define _le64toh(x) ((uint64_t)(x))
-#endif
-
-// Attempt to work on unenumerated platforms.
-#if defined(le64toh) && !defined(_le64toh)
-# define _le64toh le64toh
-#endif
-
-// We can't do anything about this.
-#ifndef _le64toh
-# error Please define _le64toh for your platform!
-#endif
-
-#define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) )
-
-#define HALF_ROUND(a,b,c,d,s,t) \
- a += b; c += d; \
- b = ROTATE(b, s) ^ a; \
- d = ROTATE(d, t) ^ c; \
- a = ROTATE(a, 32);
-
-#define DOUBLE_ROUND(v0,v1,v2,v3) \
- HALF_ROUND(v0,v1,v2,v3,13,16); \
- HALF_ROUND(v2,v1,v0,v3,17,21); \
- HALF_ROUND(v0,v1,v2,v3,13,16); \
- HALF_ROUND(v2,v1,v0,v3,17,21);
-
-
-uint64_t Anope::SipHash24(const void *src, unsigned long src_sz, const char key[16])
-{
- const uint64_t *_key = (uint64_t *)key;
- uint64_t k0 = _le64toh(_key[0]);
- uint64_t k1 = _le64toh(_key[1]);
- uint64_t b = (uint64_t)src_sz << 56;
- const uint64_t *in = (uint64_t*)src;
-
- uint64_t v0 = k0 ^ 0x736f6d6570736575ULL;
- uint64_t v1 = k1 ^ 0x646f72616e646f6dULL;
- uint64_t v2 = k0 ^ 0x6c7967656e657261ULL;
- uint64_t v3 = k1 ^ 0x7465646279746573ULL;
-
- while (src_sz >= 8)
- {
- uint64_t mi = _le64toh(*in);
- in += 1; src_sz -= 8;
- v3 ^= mi;
- DOUBLE_ROUND(v0,v1,v2,v3);
- v0 ^= mi;
- }
-
- uint64_t t = 0; uint8_t *pt = (uint8_t *)&t; uint8_t *m = (uint8_t *)in;
- switch (src_sz)
- {
- case 7: pt[6] = m[6];
- case 6: pt[5] = m[5];
- case 5: pt[4] = m[4];
- case 4: *((uint32_t*)&pt[0]) = *((uint32_t*)&m[0]); break;
- case 3: pt[2] = m[2];
- case 2: pt[1] = m[1];
- case 1: pt[0] = m[0];
- }
- b |= _le64toh(t);
-
- v3 ^= b;
- DOUBLE_ROUND(v0,v1,v2,v3);
- v0 ^= b; v2 ^= 0xff;
- DOUBLE_ROUND(v0,v1,v2,v3);
- DOUBLE_ROUND(v0,v1,v2,v3);
- return (v0 ^ v1) ^ (v2 ^ v3);
-}
diff --git a/src/socket_clients.cpp b/src/socket_clients.cpp
index 5316be226..1df727efc 100644
--- a/src/socket_clients.cpp
+++ b/src/socket_clients.cpp
@@ -14,7 +14,7 @@
#include "logger.h"
#include "sockets.h"
-#include <errno.h>
+#include <cerrno>
void ConnectionSocket::Connect(const Anope::string &TargetHost, int Port)
{
diff --git a/src/socket_transport.cpp b/src/socket_transport.cpp
index 287e60450..621b2bce4 100644
--- a/src/socket_transport.cpp
+++ b/src/socket_transport.cpp
@@ -13,14 +13,6 @@
#include "sockets.h"
#include "socketengine.h"
-BufferedSocket::BufferedSocket()
-{
-}
-
-BufferedSocket::~BufferedSocket()
-{
-}
-
bool BufferedSocket::ProcessRead()
{
char tbuffer[NET_BUFSIZE];
@@ -55,7 +47,7 @@ bool BufferedSocket::ProcessWrite()
return true;
}
-const Anope::string BufferedSocket::GetLine()
+Anope::string BufferedSocket::GetLine()
{
size_t s = this->read_buffer.find('\n');
if (s == Anope::string::npos)
@@ -115,14 +107,6 @@ BinarySocket::DataBlock::~DataBlock()
delete [] this->orig;
}
-BinarySocket::BinarySocket()
-{
-}
-
-BinarySocket::~BinarySocket()
-{
-}
-
bool BinarySocket::ProcessRead()
{
char tbuffer[NET_BUFSIZE];
diff --git a/src/socketengines/socketengine_epoll.cpp b/src/socketengines/epoll.cpp
index 93f558299..f5cd7c090 100644
--- a/src/socketengines/socketengine_epoll.cpp
+++ b/src/socketengines/epoll.cpp
@@ -15,9 +15,9 @@
#include "socketengine.h"
#include "config.h"
+#include <cerrno>
#include <sys/epoll.h>
#include <ulimit.h>
-#include <errno.h>
static int EngineHandle;
static std::vector<epoll_event> events;
@@ -53,7 +53,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
memset(&ev, 0, sizeof(ev));
- ev.events = (s->flags[SF_READABLE] ? EPOLLIN : 0) | (s->flags[SF_WRITABLE] ? EPOLLOUT : 0);
+ ev.events = (s->flags[SF_READABLE] ? EPOLLIN : 0u) | (s->flags[SF_WRITABLE] ? EPOLLOUT : 0u);
ev.data.fd = s->GetFD();
int mod;
@@ -67,7 +67,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
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());
+ throw SocketException("Unable to epoll_ctl() fd " + Anope::ToString(ev.data.fd) + " to epoll: " + Anope::LastError());
}
void SocketEngine::Process()
@@ -76,7 +76,7 @@ void SocketEngine::Process()
events.resize(events.size() * 2);
int total = epoll_wait(EngineHandle, &events.front(), events.size(), Config->ReadTimeout * 1000);
- Anope::CurTime = time(NULL);
+ Anope::UpdateTime();
/* EINTR can be given if the read timeout expires */
if (total == -1)
diff --git a/src/socketengines/socketengine_kqueue.cpp b/src/socketengines/kqueue.cpp
index 9b3943d72..271f5a49d 100644
--- a/src/socketengines/socketengine_kqueue.cpp
+++ b/src/socketengines/kqueue.cpp
@@ -77,7 +77,7 @@ void SocketEngine::Process()
static timespec kq_timespec = { Config->ReadTimeout, 0 };
int total = kevent(kq_fd, &change_events.front(), change_count, &event_events.front(), event_events.size(), &kq_timespec);
change_count = 0;
- Anope::CurTime = time(NULL);
+ Anope::UpdateTime();
/* EINTR can be given if the read timeout expires */
if (total == -1)
diff --git a/src/socketengines/socketengine_poll.cpp b/src/socketengines/poll.cpp
index 0c728a055..05b1f3ef5 100644
--- a/src/socketengines/socketengine_poll.cpp
+++ b/src/socketengines/poll.cpp
@@ -71,7 +71,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
{
std::map<int, unsigned>::iterator pos = socket_positions.find(s->GetFD());
if (pos == socket_positions.end())
- throw SocketException("Unable to remove fd " + stringify(s->GetFD()) + " from poll, it does not exist?");
+ throw SocketException("Unable to remove fd " + Anope::ToString(s->GetFD()) + " from poll, it does not exist?");
if (pos->second != events.size() - 1)
{
@@ -90,7 +90,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
{
std::map<int, unsigned>::iterator pos = socket_positions.find(s->GetFD());
if (pos == socket_positions.end())
- throw SocketException("Unable to modify fd " + stringify(s->GetFD()) + " in poll, it does not exist?");
+ throw SocketException("Unable to modify fd " + Anope::ToString(s->GetFD()) + " in poll, it does not exist?");
pollfd &ev = events[pos->second];
ev.events = (s->flags[SF_READABLE] ? POLLIN : 0) | (s->flags[SF_WRITABLE] ? POLLOUT : 0);
@@ -100,7 +100,7 @@ void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
void SocketEngine::Process()
{
int total = poll(&events.front(), events.size(), Config->ReadTimeout * 1000);
- Anope::CurTime = time(NULL);
+ Anope::UpdateTime();
/* EINTR can be given if the read timeout expires */
if (total < 0)
diff --git a/src/socketengines/socketengine_select.cpp b/src/socketengines/select.cpp
index c29d971c5..5b895cd9d 100644
--- a/src/socketengines/socketengine_select.cpp
+++ b/src/socketengines/select.cpp
@@ -16,10 +16,7 @@
#include "logger.h"
#include "config.h"
-#ifdef _AIX
-# undef FD_ZERO
-# define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
-#endif /* _AIX */
+#include <thread>
static int MaxFD;
static unsigned FDCount;
@@ -97,13 +94,13 @@ void SocketEngine::Process()
*/
if (FDCount == 0)
{
- sleep(tval.tv_sec);
+ std::this_thread::sleep_for(std::chrono::seconds(tval.tv_sec));
return;
}
#endif
int sresult = select(MaxFD + 1, &rfdset, &wfdset, &efdset, &tval);
- Anope::CurTime = time(NULL);
+ Anope::UpdateTime();
if (sresult == -1)
{
diff --git a/src/sockets.cpp b/src/sockets.cpp
index 2227ba607..908bf34f6 100644
--- a/src/sockets.cpp
+++ b/src/sockets.cpp
@@ -16,7 +16,7 @@
#ifndef _WIN32
#include <arpa/inet.h>
-#include <errno.h>
+#include <cerrno>
#include <fcntl.h>
#endif
@@ -52,6 +52,8 @@ size_t sockaddrs::size() const
return sizeof(sa4);
case AF_INET6:
return sizeof(sa6);
+ case AF_UNIX:
+ return sizeof(saun);
default:
break;
}
@@ -67,6 +69,8 @@ int sockaddrs::port() const
return ntohs(sa4.sin_port);
case AF_INET6:
return ntohs(sa6.sin6_port);
+ case AF_UNIX:
+ return 0;
default:
break;
}
@@ -76,18 +80,51 @@ int sockaddrs::port() const
Anope::string sockaddrs::addr() const
{
- char address[INET6_ADDRSTRLEN];
-
switch (sa.sa_family)
{
case AF_INET:
- if (inet_ntop(AF_INET, &sa4.sin_addr, address, sizeof(address)))
- return address;
+ {
+ char v4address[INET_ADDRSTRLEN];
+ if (inet_ntop(AF_INET, &sa4.sin_addr, v4address, sizeof(v4address)))
+ return v4address;
break;
+ }
case AF_INET6:
- if (inet_ntop(AF_INET6, &sa6.sin6_addr, address, sizeof(address)))
- return address;
+ {
+ char v6address[INET6_ADDRSTRLEN];
+ if (inet_ntop(AF_INET6, &sa6.sin6_addr, v6address, sizeof(v6address)))
+ return v6address;
break;
+ }
+ case AF_UNIX:
+ return saun.sun_path;
+ default:
+ break;
+ }
+
+ return "";
+}
+
+Anope::string sockaddrs::str() const
+{
+ switch (sa.sa_family)
+ {
+ case AF_INET:
+ {
+ char v4address[INET_ADDRSTRLEN];
+ if (!inet_ntop(AF_INET, &sa4.sin_addr, v4address, sizeof(v4address)))
+ strcpy(v4address, "0.0.0.0");
+ return Anope::printf("%s:%u", v4address, sa4.sin_port);
+ }
+ case AF_INET6:
+ {
+ char v6address[INET6_ADDRSTRLEN];
+ if (!inet_ntop(AF_INET6, &sa6.sin6_addr, v6address, sizeof(v6address)))
+ strcpy(v6address, "0:0:0:0:0:0:0:0");
+ return Anope::printf("[%s]:%u", v6address, sa6.sin6_port);
+ }
+ case AF_UNIX:
+ return saun.sun_path;
default:
break;
}
@@ -187,6 +224,15 @@ void sockaddrs::pton(int type, const Anope::string &address, int pport)
}
break;
}
+ case AF_UNIX:
+ {
+ if (address.length() < sizeof(saun.sun_path))
+ {
+ saun.sun_family = AF_UNIX;
+ memcpy(&saun.sun_path, address.c_str(), address.length() + 1);
+ }
+ break;
+ }
default:
break;
}
@@ -236,13 +282,7 @@ cidr::cidr(const Anope::string &ip)
Anope::string cidr_range = ip.substr(sl + 1);
this->cidr_ip = real_ip;
- this->cidr_len = ipv6 ? 128 : 32;
- try
- {
- if (cidr_range.is_pos_number_only())
- this->cidr_len = convertTo<unsigned int>(cidr_range);
- }
- catch (const ConvertException &) { }
+ this->cidr_len = Anope::Convert<unsigned int>(cidr_range, ipv6 ? 128 : 32);
this->addr.pton(ipv6 ? AF_INET6 : AF_INET, real_ip);
}
}
@@ -306,7 +346,7 @@ bool cidr::match(const sockaddrs &other)
byte = len % 8;
if (byte)
{
- uint8_t m = ~0 << (8 - byte);
+ uint8_t m = ~0u << (8 - byte);
return (*ip & m) == (*their_ip & m);
}
@@ -386,23 +426,23 @@ size_t cidr::hash::operator()(const cidr &s) const
}
}
-int SocketIO::Recv(Socket *s, char *buf, size_t sz)
+ssize_t SocketIO::Recv(Socket *s, char *buf, size_t sz)
{
- int i = recv(s->GetFD(), buf, sz, 0);
+ ssize_t i = recv(s->GetFD(), buf, sz, 0);
if (i > 0)
TotalRead += i;
return i;
}
-int SocketIO::Send(Socket *s, const char *buf, size_t sz)
+ssize_t SocketIO::Send(Socket *s, const char *buf, size_t sz)
{
- int i = send(s->GetFD(), buf, sz, 0);
+ ssize_t i = send(s->GetFD(), buf, sz, 0);
if (i > 0)
TotalWritten += i;
return i;
}
-int SocketIO::Send(Socket *s, const Anope::string &buf)
+ssize_t SocketIO::Send(Socket *s, const Anope::string &buf)
{
return this->Send(s, buf.c_str(), buf.length());
}
@@ -432,7 +472,7 @@ SocketFlag SocketIO::FinishAccept(ClientSocket *cs)
void SocketIO::Bind(Socket *s, const Anope::string &ip, int port)
{
- s->bindaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, ip, port);
+ s->bindaddr.pton(s->GetFamily(), ip, port);
if (bind(s->GetFD(), &s->bindaddr.sa, s->bindaddr.size()) == -1)
throw SocketException("Unable to bind to address: " + Anope::LastError());
}
@@ -440,7 +480,7 @@ void SocketIO::Bind(Socket *s, const Anope::string &ip, int port)
void SocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int port)
{
s->flags[SF_CONNECTING] = s->flags[SF_CONNECTED] = false;
- s->conaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, target, port);
+ s->conaddr.pton(s->GetFamily(), target, port);
int c = connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size());
if (c == -1)
{
@@ -488,12 +528,12 @@ Socket::Socket()
throw CoreException("Socket::Socket() ?");
}
-Socket::Socket(int s, bool i, int type)
+Socket::Socket(int s, int f, int type)
{
this->io = &NormalSocketIO;
- this->ipv6 = i;
+ this->family = f;
if (s == -1)
- this->sock = socket(this->ipv6 ? AF_INET6 : AF_INET, type, 0);
+ this->sock = socket(this->family, type, 0);
else
this->sock = s;
this->SetBlocking(false);
@@ -510,14 +550,14 @@ Socket::~Socket()
SocketEngine::Sockets.erase(this->sock);
}
-int Socket::GetFD() const
+int Socket::GetFamily() const
{
- return sock;
+ return family;
}
-bool Socket::IsIPv6() const
+int Socket::GetFD() const
{
- return ipv6;
+ return sock;
}
bool Socket::SetBlocking(bool state)
@@ -567,10 +607,6 @@ ListenSocket::ListenSocket(const Anope::string &bindip, int port, bool i)
throw SocketException("Unable to listen: " + Anope::LastError());
}
-ListenSocket::~ListenSocket()
-{
-}
-
bool ListenSocket::ProcessRead()
{
try
diff --git a/src/threadengine.cpp b/src/threadengine.cpp
index b26463f53..729f3e5ec 100644
--- a/src/threadengine.cpp
+++ b/src/threadengine.cpp
@@ -13,49 +13,21 @@
#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;
-}
+#include <stdexcept>
static void *entry_point(void *parameter)
{
Thread *thread = static_cast<Thread *>(parameter);
thread->Run();
thread->SetExitState();
- pthread_exit(0);
return NULL;
}
-Thread::Thread() : exit(false)
-{
-}
-
-Thread::~Thread()
-{
-}
-
void Thread::Join()
{
this->SetExitState();
- pthread_join(handle, NULL);
+ if (this->handle)
+ this->handle->join();
}
void Thread::SetExitState()
@@ -67,15 +39,19 @@ void Thread::SetExitState()
void Thread::Exit()
{
this->SetExitState();
- pthread_exit(0);
}
void Thread::Start()
{
- if (pthread_create(&this->handle, get_engine_attr(), entry_point, this))
+ try
+ {
+ if (!this->handle)
+ this->handle = std::make_unique<std::thread>(entry_point, this);
+ }
+ catch (const std::system_error &err)
{
this->flags[SF_DEAD] = true;
- throw CoreException("Unable to create thread: " + Anope::LastError());
+ throw CoreException("Unable to create thread: " + Anope::string(err.what()));
}
}
@@ -89,48 +65,3 @@ void Thread::OnNotify()
this->Join();
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);
-}
-
-bool Mutex::TryLock()
-{
- return pthread_mutex_trylock(&mutex) == 0;
-}
-
-Condition::Condition() : Mutex()
-{
- pthread_cond_init(&cond, NULL);
-}
-
-Condition::~Condition()
-{
- pthread_cond_destroy(&cond);
-}
-
-void Condition::Wakeup()
-{
- pthread_cond_signal(&cond);
-}
-
-void Condition::Wait()
-{
- pthread_cond_wait(&cond, &mutex);
-}
diff --git a/src/timers.cpp b/src/timers.cpp
index db20dcd8b..e280434ab 100644
--- a/src/timers.cpp
+++ b/src/timers.cpp
@@ -11,26 +11,23 @@
std::multimap<time_t, Timer *> TimerManager::Timers;
-Timer::Timer(long time_from_now, time_t now, bool repeating)
+Timer::Timer(time_t time_from_now, bool repeating)
+ : trigger(Anope::CurTime + std::abs(time_from_now))
+ , secs(time_from_now)
+ , repeat(repeating)
{
- owner = NULL;
- trigger = now + time_from_now;
- secs = time_from_now;
- repeat = repeating;
- settime = now;
-
- TimerManager::AddTimer(this);
+ if (time_from_now)
+ TimerManager::AddTimer(this);
}
-Timer::Timer(Module *creator, long time_from_now, time_t now, bool repeating)
+Timer::Timer(Module *creator, time_t time_from_now, bool repeating)
+ : owner(creator)
+ , trigger(Anope::CurTime + std::abs(time_from_now))
+ , secs(time_from_now)
+ , repeat(repeating)
{
- owner = creator;
- trigger = now + time_from_now;
- secs = time_from_now;
- repeat = repeating;
- settime = now;
-
- TimerManager::AddTimer(this);
+ if (time_from_now)
+ TimerManager::AddTimer(this);
}
Timer::~Timer()
@@ -55,11 +52,6 @@ bool Timer::GetRepeat() const
return repeat;
}
-time_t Timer::GetSetTime() const
-{
- return settime;
-}
-
void Timer::SetSecs(time_t t)
{
TimerManager::DelTimer(this);
@@ -80,7 +72,7 @@ Module *Timer::GetOwner() const
void TimerManager::AddTimer(Timer *t)
{
- Timers.insert(std::make_pair(t->GetTimer(), t));
+ Timers.emplace(t->GetTimer(), t);
}
void TimerManager::DelTimer(Timer *t)
@@ -96,20 +88,20 @@ void TimerManager::DelTimer(Timer *t)
}
}
-void TimerManager::TickTimers(time_t ctime)
+void TimerManager::TickTimers()
{
while (!Timers.empty())
{
std::multimap<time_t, Timer *>::iterator it = Timers.begin();
Timer *t = it->second;
- if (t->GetTimer() > ctime)
+ if (t->GetTimer() > Anope::CurTime)
break;
- t->Tick(ctime);
+ t->Tick();
if (t->GetRepeat())
- t->SetTimer(ctime + t->GetSecs());
+ t->SetTimer(Anope::CurTime + t->GetSecs());
else
delete t;
}
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index 29421aeeb..249a036ad 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -1,6 +1,6 @@
# 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)
+list(SORT TOOLS_SRCS)
# 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}")
@@ -9,34 +9,34 @@ set_source_files_properties(${TOOLS_SRCS} PROPERTIES LANGUAGE CXX COMPILE_FLAGS
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}
+ RUNTIME
)
# Add the executable to the list of files for CPack to ignore
set(EXE_BINARY "$<TARGET_FILE:${EXE}>")
get_filename_component(EXE_BINARY ${EXE_BINARY} NAME)
add_to_cpack_ignored_files("${EXE_BINARY}$" TRUE)
- endif(NOT SKIP)
-endforeach(SRC)
+ endif()
+endforeach()
-# If not on Windows, generate anoperc and install it along with mydbgen
+# If not on Windows, generate anope.service and anoperc
if(NOT WIN32)
+ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ configure_file(${Anope_SOURCE_DIR}/src/tools/anope.service.in ${Anope_BINARY_DIR}/src/tools/anope.service)
+ install(
+ PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/anope.service
+ DESTINATION ${BIN_DIR}
+ )
+ endif()
+
configure_file(${Anope_SOURCE_DIR}/src/tools/anoperc.in ${Anope_BINARY_DIR}/src/tools/anoperc)
install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/anoperc
DESTINATION ${BIN_DIR}
@@ -44,9 +44,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.service.in b/src/tools/anope.service.in
new file mode 100644
index 000000000..6fe8f652d
--- /dev/null
+++ b/src/tools/anope.service.in
@@ -0,0 +1,17 @@
+[Unit]
+After=network.target
+Description=Anope IRC Services
+Documentation=https://wiki.anope.org/
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+ExecReload=/bin/kill -HUP $MAINPID
+ExecStart=@BIN_DIR@/@PROGRAM_NAME@ --nofork
+Restart=on-failure
+Type=simple
+WorkingDirectory=@CMAKE_INSTALL_PREFIX@
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/src/tools/anoperc.in b/src/tools/anoperc.in
index 0d3b2d07d..24fc77e83 100644
--- a/src/tools/anoperc.in
+++ b/src/tools/anoperc.in
@@ -1,8 +1,8 @@
#!/bin/sh
#
-# Configuration script for Services
+# Configuration script for Anope
#
-# (C) 2003-2024 Anope Team
+# (C) 2003-2025 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"
diff --git a/src/tools/anopesmtp.cpp b/src/tools/anopesmtp.cpp
deleted file mode 100644
index d1c3f7b64..000000000
--- a/src/tools/anopesmtp.cpp
+++ /dev/null
@@ -1,535 +0,0 @@
-/* smtp stuff handler for win32.
- *
- * (C) 2003-2025 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 = gmtime(&t);
-
- strftime(tbuf, sizeof(tbuf) - 1, "%a, %d %b %Y %H:%M:%S +0000", 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 writing 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 writing 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 writing 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 writing 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 writing to socket");
- return 0;
- }
-
- if (!smtp_send("\r\n"))
- {
- alog("SMTP: error writing 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 writing to socket");
- return 0;
- }
- }
- else
- skip_done = true;
-
- if (!smtp_send("\r\n.\r\n"))
- {
- alog("SMTP: error writing 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;
- }
-
- return 1;
-}
-
-void smtp_disconnect()
-{
- char buf[1024];
-
- if (!smtp_send("QUIT\r\n"))
- {
- alog("SMTP: error writing to socket");
- }
-
- if (!smtp_read(buf, 1024))
- {
- alog("SMTP: error reading buffer");
- }
-
- int code = smtp_get_code(buf);
- if (code != 221)
- {
- alog("SMTP: error expected code 221 got %d",code);
- }
-
- 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/tools/mkauthors b/src/tools/mkauthors
new file mode 100755
index 000000000..1a864374d
--- /dev/null
+++ b/src/tools/mkauthors
@@ -0,0 +1,57 @@
+#!/usr/bin/env perl
+#
+# (C) 2003-2025 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.
+
+use v5.26.0;
+use strict;
+use warnings FATAL => qw(all);
+
+use File::Basename qw(dirname);
+use File::Spec::Functions qw(catfile);
+use FindBin qw($RealDir);
+
+my %committers;
+for my $committer (split /\n+/, `git log --pretty='%an <%ae>%n%(trailers:key=Co-Authored-By,valueonly)' HEAD`) {
+ $committers{$committer} ||= 0;
+ $committers{$committer} += 1;
+}
+
+my %authors;
+for my $committer (keys %committers) {
+ open(my $fh, '-|', 'git', 'check-mailmap', $committer);
+ chomp(my $author = <$fh>);
+ close $fh;
+
+ $author = $1 if $author =~ /^(.+) <(?:\S+\@localhost|\S+\@users.noreply.github.com)>$/;
+ next if $author =~ /\[bot\]$/;
+ next if $author =~ /^\(svnadmin\)$/;
+
+ $authors{$author} ||= 0;
+ $authors{$author} += $committers{$committer};
+}
+
+
+my $author_file = catfile dirname(dirname($RealDir)), 'docs', 'AUTHORS.txt';
+open(my $fh, '>', $author_file) or die "Unable to write $author_file: $!";
+say $fh <<"EOH";
+Since the first commit in March 2004 ${\scalar %authors} people have submitted patches, commits,
+and other useful contributions to Anope. These people, ordered by the number of
+contributions they have made, are:
+EOH
+
+for my $author (sort { $authors{$b} <=> $authors{$a} or lc($a) cmp lc($b) } keys %authors) {
+ say $fh " * $author";
+}
+close $fh;
+
+if ($ENV{MKAUTHORS_COMMIT} // 1) {
+ system 'git', 'commit',
+ '--message', 'Update author list.',
+ '--', $author_file;
+}
diff --git a/src/uplink.cpp b/src/uplink.cpp
index f1b524dd1..c8bfc0b3b 100644
--- a/src/uplink.cpp
+++ b/src/uplink.cpp
@@ -17,12 +17,16 @@
UplinkSocket *UplinkSock = NULL;
-class ReconnectTimer : public Timer
+class ReconnectTimer final
+ : public Timer
{
- public:
- ReconnectTimer(int wait) : Timer(wait) { }
+public:
+ ReconnectTimer(time_t wait)
+ : Timer(wait)
+ {
+ }
- void Tick(time_t)
+ void Tick() override
{
try
{
@@ -30,7 +34,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();
+ Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].str() << "): " << ex.GetReason();
}
}
};
@@ -43,21 +47,63 @@ void Uplink::Connect()
return;
}
- if (static_cast<unsigned>(++Anope::CurrentUplink) >= Config->Uplinks.size())
+ if (++Anope::CurrentUplink >= Config->Uplinks.size())
Anope::CurrentUplink = 0;
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"));
+ if (!Config->GetBlock("serverinfo").Get<const Anope::string>("localhost").empty())
+ UplinkSock->Bind(Config->GetBlock("serverinfo").Get<const Anope::string>("localhost"));
FOREACH_MOD(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 << '/' << u.port << ") with protocol " << IRCD->GetProtocolName();
+ Anope::string ip = Anope::Resolve(u.host, u.protocol);
+ Log(LOG_TERMINAL) << "Attempting to connect to uplink #" << (Anope::CurrentUplink + 1) << " " << ip << " (" << u.str() << ")";
UplinkSock->Connect(ip, u.port);
}
-UplinkSocket::UplinkSocket() : Socket(-1, Config->Uplinks[Anope::CurrentUplink].ipv6), ConnectionSocket(), BufferedSocket()
+void Uplink::SendInternal(const Anope::map<Anope::string> &tags, const MessageSource &source, const Anope::string &command, const std::vector<Anope::string> &params)
+{
+ if (!UplinkSock)
+ {
+ Log(LOG_DEBUG) << "Attempted to send \"" << command << "\" from " << source.GetName() << " with a null uplink socket";
+ return;
+ }
+
+ Anope::string message;
+ if (!IRCD->Format(message, tags, source, command, params))
+ return;
+
+ UplinkSock->Write(message);
+
+ Log(LOG_RAWIO) << "Sent " << message;
+ if (Anope::ProtocolDebug)
+ {
+ if (tags.empty())
+ Log() << "\tNo tags";
+ else
+ {
+ for (const auto &[tname, tvalue] : tags)
+ Log() << "\tTag " << tname << ": " << tvalue;
+ }
+
+ if (source.GetSource().empty())
+ Log() << "\tNo source";
+ else
+ Log() << "\tSource: " << source.GetSource();
+
+ Log() << "\tCommand: " << command;
+
+ if (params.empty())
+ Log() << "\tNo params";
+ else
+ {
+ for (size_t i = 0; i < params.size(); ++i)
+ Log() << "\tParam " << i << ": " << params[i];
+ }
+ }
+}
+
+UplinkSocket::UplinkSocket() : Socket(-1, Config->Uplinks[Anope::CurrentUplink].protocol), ConnectionSocket(), BufferedSocket()
{
error = false;
UplinkSock = this;
@@ -79,15 +125,14 @@ UplinkSocket::~UplinkSocket()
{
FOREACH_MOD(OnServerDisconnect, ());
- for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
+ for (const auto &[_, u] : UserListByNick)
{
- User *u = it->second;
-
if (u->server == Me)
{
/* 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());
+ const auto *reason = Anope::Restarting ? "Restarting" : "Shutting down";
+ IRCD->SendQuit(u, reason, Anope::QuitReason);
+ BotInfo *bi = BotInfo::Find(u->GetUID());
if (bi != NULL)
bi->introduced = false;
}
@@ -120,7 +165,7 @@ UplinkSocket::~UplinkSocket()
}
else if (!Anope::Quitting)
{
- time_t retry = Config->GetBlock("options")->Get<time_t>("retrywait");
+ time_t retry = Config->GetBlock("options").Get<time_t>("retrywait");
Log() << "Disconnected, retrying in " << retry << " seconds";
new ReconnectTimer(retry);
@@ -130,7 +175,7 @@ UplinkSocket::~UplinkSocket()
bool UplinkSocket::ProcessRead()
{
bool b = BufferedSocket::ProcessRead();
- for (Anope::string buf; (buf = this->GetLine()).empty() == false;)
+ for (Anope::string buf; !(buf = this->GetLine()).empty();)
{
Anope::Process(buf);
User::QuitUsers();
@@ -141,7 +186,7 @@ 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;
+ Log(LOG_TERMINAL) << "Successfully connected to uplink #" << (Anope::CurrentUplink + 1) << " " << Config->Uplinks[Anope::CurrentUplink].str();
IRCD->SendConnect();
FOREACH_MOD(OnServerConnect, ());
}
@@ -149,64 +194,6 @@ void UplinkSocket::OnConnect()
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) : "");
+ Log(LOG_TERMINAL) << what << " uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].str() << ")" << (!err.empty() ? (": " + err) : "");
error |= !err.empty();
}
-
-UplinkSocket::Message::Message() : source(Me)
-{
-}
-
-UplinkSocket::Message::Message(const MessageSource &src) : source(src)
-{
-}
-
-UplinkSocket::Message::~Message()
-{
- Anope::string message_source;
-
- if (this->source.GetServer() != NULL)
- {
- const Server *s = this->source.GetServer();
-
- if (s != Me && !s->IsJuped())
- {
- Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << s->GetName() << " who is not from me?";
- return;
- }
-
- message_source = s->GetSID();
- }
- else if (this->source.GetUser() != NULL)
- {
- const User *u = this->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?";
- return;
- }
-
- const BotInfo *bi = this->source.GetBot();
- if (bi != NULL && bi->introduced == false)
- {
- Log(LOG_DEBUG) << "Attempted to send \"" << this->buffer.str() << "\" from " << bi->nick << " when not introduced";
- 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";
- return;
- }
-
- Anope::string sent = IRCD->Format(message_source, this->buffer.str());
- UplinkSock->Write(sent);
- Log(LOG_RAWIO) << "Sent: " << sent;
-}
diff --git a/src/users.cpp b/src/users.cpp
index 13a19c0ef..8f8e9570d 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -31,7 +31,8 @@ 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 std::vector<Anope::string> &smodeparams, const Anope::string &suid, NickCore *account)
+ : ip(uip)
{
if (snick.empty() || sident.empty() || shost.empty())
throw CoreException("Bad args passed to User::User");
@@ -40,7 +41,6 @@ User::User(const Anope::string &snick, const Anope::string &sident, const Anope:
quit = false;
server = NULL;
invalid_pw_count = invalid_pw_time = lastmemosend = lastnickreg = lastmail = 0;
- on_access = false;
this->nick = snick;
this->ident = sident;
@@ -50,7 +50,7 @@ User::User(const Anope::string &snick, const Anope::string &sident, const Anope:
this->server = sserver;
this->realname = srealname;
this->timestamp = this->signon = ts;
- this->SetModesInternal(sserver, "%s", smodes.c_str());
+ this->SetModesInternal(sserver, smodes, smodeparams);
this->uid = suid;
this->super_admin = false;
this->nc = NULL;
@@ -93,7 +93,7 @@ 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))
@@ -111,7 +111,7 @@ static void Collide(User *u, const Anope::string &id, const Anope::string &type)
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, NickCore *nc, const std::vector<Anope::string> &smodeparams)
{
// 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
@@ -133,7 +133,7 @@ User* User::OnIntroduce(const Anope::string &snick, const Anope::string &sident,
}
}
- return new User(snick, sident, shost, svhost, sip, sserver, srealname, ts, smodes, suid, nc);
+ return new User(snick, sident, shost, svhost, sip, sserver, srealname, ts, smodes, smodeparams, suid, nc);
}
void User::ChangeNick(const Anope::string &newnick, time_t ts)
@@ -153,14 +153,14 @@ void User::ChangeNick(const Anope::string &newnick, time_t ts)
else
{
NickAlias *old_na = NickAlias::Find(this->nick);
- if (old_na && (this->IsIdentified(true) || this->IsRecognized()))
+ if (old_na && this->IsIdentified(true))
old_na->last_seen = Anope::CurTime;
UserListByNick.erase(this->nick);
this->nick = newnick;
- User* &other = UserListByNick[this->nick];
+ User *&other = UserListByNick[this->nick];
if (other)
{
CollideKill(this, "Nick collision");
@@ -169,11 +169,7 @@ 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())
{
na->last_seen = Anope::CurTime;
@@ -282,7 +278,7 @@ void User::SetRealname(const Anope::string &srealname)
this->realname = srealname;
NickAlias *na = NickAlias::Find(this->nick);
- if (na && (this->IsIdentified(true) || this->IsRecognized()))
+ if (na && this->IsIdentified(true))
na->last_realname = srealname;
Log(this, "realname") << "changed realname to " << srealname;
@@ -332,26 +328,52 @@ void User::SendMessage(BotInfo *source, const char *fmt, ...)
va_end(args);
}
-void User::SendMessage(BotInfo *source, const Anope::string &msg)
+void User::SendMessage(BotInfo *source, int count, const char *singular, const char *plural, ...)
{
- const char *translated_message = Language::Translate(this, msg.c_str());
+ va_list args;
+ char buf[BUFSIZE] = "";
+
+ const char *translated_message = Language::Translate(this, count, singular, plural);
- /* Send privmsg instead of notice if:
- * - UsePrivmsg is enabled
- * - 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")));
- sepstream sep(translated_message, '\n', true);
- for (Anope::string tok; sep.GetToken(tok);)
+ va_start(args, plural);
+ vsnprintf(buf, BUFSIZE - 1, translated_message, args);
+
+ this->SendMessage(source, Anope::string(buf));
+
+ va_end(args);
+}
+
+namespace
+{
+ void SendMessageInternal(BotInfo *source, User *target, const Anope::string &msg, const Anope::map<Anope::string> &tags)
{
- if (send_privmsg)
- IRCD->SendPrivmsg(source, this->GetUID(), "%s", tok.c_str());
- else
- IRCD->SendNotice(source, this->GetUID(), "%s", tok.c_str());
+ const char *translated_message = Language::Translate(target, msg.c_str());
+
+ sepstream sep(translated_message, '\n', true);
+ for (Anope::string tok; sep.GetToken(tok);)
+ {
+ if (target->ShouldPrivmsg())
+ IRCD->SendPrivmsg(source, target->GetUID(), tok, tags);
+ else
+ IRCD->SendNotice(source, target->GetUID(), tok, tags);
+ }
}
}
+void User::SendMessage(BotInfo *source, const Anope::string &msg)
+{
+ SendMessageInternal(source, this, msg, {});
+}
+
+void User::SendMessage(CommandSource &source, const Anope::string &msg)
+{
+ Anope::map<Anope::string> tags;
+ if (!source.msgid.empty())
+ tags["+draft/reply"] = source.msgid;
+
+ SendMessageInternal(*source.service, this, msg, tags);
+}
+
void User::Identify(NickAlias *na)
{
if (this->nick.equals_ci(na->nick))
@@ -372,17 +394,18 @@ void User::Identify(NickAlias *na)
{
if (!this->nc->o->ot->modes.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");
+ auto *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, this->nc->o->ot->modes);
+ this->SendMessage(NULL, _("Changing your usermodes to \002%s\002"), this->nc->o->ot->modes.c_str());
}
if (IRCD->CanSetVHost && !this->nc->o->vhost.empty())
{
- this->SendMessage(NULL, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str());
+ 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);
+ IRCD->SendVHost(this, "", this->nc->o->vhost);
}
}
}
@@ -424,6 +447,11 @@ NickCore *User::Account() const
return this->nc;
}
+NickAlias *User::AccountNick() const
+{
+ return this->nc ? this->nc->na : nullptr;
+}
+
bool User::IsIdentified(bool check_nick) const
{
if (check_nick && this->nc)
@@ -432,56 +460,58 @@ bool User::IsIdentified(bool check_nick) const
return na && *na->nc == *this->nc;
}
- return this->nc ? true : false;
+ return this->nc;
}
-bool User::IsRecognized(bool check_secure) const
+bool User::IsSecurelyConnected() const
{
- if (check_secure && on_access)
- {
- const NickAlias *na = NickAlias::Find(this->nick);
-
- if (!na || na->nc->HasExt("NS_SECURE"))
- return false;
- }
-
- return on_access;
+ return HasMode("SSL") || HasExt("ssl");
}
bool User::IsServicesOper()
{
if (!this->nc || !this->nc->IsServicesOper())
- // No opertype.
- return false;
- else if (this->nc->o->require_oper && !this->HasMode("OPER"))
- return false;
- else if (!this->nc->o->certfp.empty() && this->fingerprint != this->nc->o->certfp)
- // Certfp mismatch
- return false;
- else if (!this->nc->o->hosts.empty())
+ return false; // Account isn't a services oper.
+
+ auto *oper = this->nc->o;
+ if (oper->require_oper && !this->HasMode("OPER"))
+ return false; // User isn't an ircd oper.
+
+ if (!oper->certfp.empty())
+ {
+ bool match = false;
+ for (const auto &certfp : oper->certfp)
+ {
+ if (this->fingerprint == certfp)
+ {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return false; // Wrong TLS fingerprint.
+ }
+
+ if (!oper->hosts.empty())
{
bool match = false;
Anope::string match_host = this->GetIdent() + "@" + this->host;
Anope::string match_ip = this->GetIdent() + "@" + this->ip.addr();
- for (unsigned i = 0; i < this->nc->o->hosts.size(); ++i)
+ for (const auto &userhost : oper->hosts)
{
- const Anope::string &userhost = this->nc->o->hosts[i];
if (Anope::Match(match_host, userhost) || Anope::Match(match_ip, userhost))
{
match = true;
break;
}
}
- if (match == false)
- return false;
+ if (!match)
+ return false; // Wrong user@host/ip.
}
EventReturn MOD_RESULT;
FOREACH_RESULT(IsServicesOper, MOD_RESULT, (this));
- if (MOD_RESULT == EVENT_STOP)
- return false;
-
- return true;
+ return MOD_RESULT != EVENT_STOP;
}
bool User::HasCommand(const Anope::string &command)
@@ -504,11 +534,7 @@ void User::UpdateHost()
return;
NickAlias *na = NickAlias::Find(this->nick);
- on_access = false;
- if (na)
- on_access = na->nc->IsOnAccess(this);
-
- if (na && (this->IsIdentified(true) || this->IsRecognized()))
+ if (na && this->IsIdentified(true))
{
Anope::string last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost();
Anope::string last_realhost = this->GetIdent() + "@" + this->host;
@@ -539,17 +565,18 @@ void User::SetModeInternal(const MessageSource &source, UserMode *um, const Anop
{
if (!this->nc->o->ot->modes.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");
+ auto *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, this->nc->o->ot->modes);
+ this->SendMessage(NULL, _("Changing your usermodes to \002%s\002"), this->nc->o->ot->modes.c_str());
}
if (IRCD->CanSetVHost && !this->nc->o->vhost.empty())
{
- this->SendMessage(NULL, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str());
+ 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);
+ IRCD->SendVHost(this, "", this->nc->o->vhost);
}
}
}
@@ -616,19 +643,24 @@ void User::SetModes(BotInfo *bi, const char *umodes, ...)
{
char buf[BUFSIZE] = "";
va_list args;
- Anope::string modebuf, sbuf;
- int add = -1;
va_start(args, umodes);
vsnprintf(buf, BUFSIZE - 1, umodes, args);
va_end(args);
- spacesepstream sep(buf);
+ SetModes(bi, Anope::string(buf));
+}
+
+void User::SetModes(BotInfo *bi, const Anope::string &umodes)
+{
+ Anope::string modebuf, sbuf;
+ int add = -1;
+ spacesepstream sep(umodes);
sep.GetToken(modebuf);
- for (unsigned i = 0, end = modebuf.length(); i < end; ++i)
+ for (auto mode : modebuf)
{
UserMode *um;
- switch (modebuf[i])
+ switch (mode)
{
case '+':
add = 1;
@@ -639,7 +671,7 @@ void User::SetModes(BotInfo *bi, const char *umodes, ...)
default:
if (add == -1)
continue;
- um = ModeManager::FindUserModeByChar(modebuf[i]);
+ um = ModeManager::FindUserModeByChar(mode);
if (!um)
continue;
}
@@ -656,26 +688,18 @@ void User::SetModes(BotInfo *bi, const char *umodes, ...)
}
}
-void User::SetModesInternal(const MessageSource &source, const char *umodes, ...)
+void User::SetModesInternal(const MessageSource &source, const Anope::string &umodes, const std::vector<Anope::string> &umodeparams)
{
- char buf[BUFSIZE] = "";
- va_list args;
- Anope::string modebuf, sbuf;
- int add = -1;
- va_start(args, umodes);
- vsnprintf(buf, BUFSIZE - 1, umodes, args);
- va_end(args);
-
- if (this->server && this->server->IsSynced() && Anope::string(buf) != "+")
- Log(this, "mode") << "changes modes to " << buf;
+ if (this->server && this->server->IsSynced() && Anope::string(umodes) != "+")
+ Log(this, "mode") << "changes modes to " << umodes;
- spacesepstream sep(buf);
- sep.GetToken(modebuf);
- for (unsigned i = 0, end = modebuf.length(); i < end; ++i)
+ int add = -1;
+ auto paramit = umodeparams.begin();
+ for (const auto mode : umodes)
{
UserMode *um;
- switch (modebuf[i])
+ switch (mode)
{
case '+':
add = 1;
@@ -686,15 +710,16 @@ void User::SetModesInternal(const MessageSource &source, const char *umodes, ...
default:
if (add == -1)
continue;
- um = ModeManager::FindUserModeByChar(modebuf[i]);
+ um = ModeManager::FindUserModeByChar(mode);
if (!um)
continue;
}
if (add)
{
- if (um->type == MODE_PARAM && sep.GetToken(sbuf))
- this->SetModeInternal(source, um, sbuf);
+ Anope::string sbuf;
+ if (um->type == MODE_PARAM && paramit != umodeparams.end())
+ this->SetModeInternal(source, um, *paramit++);
else
this->SetModeInternal(source, um);
}
@@ -707,16 +732,16 @@ Anope::string User::GetModes() const
{
Anope::string m, params;
- for (ModeList::const_iterator it = this->modes.begin(), it_end = this->modes.end(); it != it_end; ++it)
+ for (const auto &[mode, value] : this->modes)
{
- UserMode *um = ModeManager::FindUserModeByName(it->first);
+ UserMode *um = ModeManager::FindUserModeByName(mode);
if (um == NULL)
continue;
m += um->mchar;
- if (!it->second.empty())
- params += " " + it->second;
+ if (!value.empty())
+ params += " " + value;
}
return m + params;
@@ -744,7 +769,7 @@ 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->SendSVSKill(source, this, real_reason);
}
void User::KillInternal(const MessageSource &source, const Anope::string &reason)
@@ -810,14 +835,14 @@ Anope::string User::Mask() const
bool User::BadPassword()
{
- if (!Config->GetBlock("options")->Get<int>("badpasslimit"))
+ if (!Config->GetBlock("options").Get<unsigned int>("badpasslimit"))
return false;
- if (Config->GetBlock("options")->Get<time_t>("badpasstimeout") > 0 && this->invalid_pw_time > 0 && this->invalid_pw_time < Anope::CurTime - Config->GetBlock("options")->Get<time_t>("badpasstimeout"))
+ if (Config->GetBlock("options").Get<time_t>("badpasstimeout") > 0 && this->invalid_pw_time > 0 && this->invalid_pw_time < Anope::CurTime - Config->GetBlock("options").Get<time_t>("badpasstimeout"))
this->invalid_pw_count = 0;
++this->invalid_pw_count;
this->invalid_pw_time = Anope::CurTime;
- if (this->invalid_pw_count >= Config->GetBlock("options")->Get<int>("badpasslimit"))
+ if (this->invalid_pw_count >= Config->GetBlock("options").Get<unsigned int>("badpasslimit"))
{
this->Kill(Me, "Too many invalid passwords");
return true;
@@ -826,7 +851,16 @@ bool User::BadPassword()
return false;
}
-User* User::Find(const Anope::string &name, bool nick_only)
+bool User::ShouldPrivmsg() const
+{
+ // Send a PRIVMSG instead of a NOTICE if:
+ // 1. The user is not registered and msg is in nickserv:defaults.
+ // 2. The user is registered and has set /ns set message on.
+ static ExtensibleRef<bool> msg("MSG");
+ return (!nc && Config->DefPrivmsg) || (nc && msg && msg->HasExt(nc));
+}
+
+User *User::Find(const Anope::string &name, bool nick_only)
{
if (!nick_only && IRCD && IRCD->RequiresID)
{
@@ -847,7 +881,7 @@ User* User::Find(const Anope::string &name, bool nick_only)
void User::QuitUsers()
{
- for (std::list<User *>::iterator it = quitting_users.begin(), it_end = quitting_users.end(); it != it_end; ++it)
- delete *it;
+ for (const auto *quitting_user : quitting_users)
+ delete quitting_user;
quitting_users.clear();
}
diff --git a/src/version.sh b/src/version.sh
index 5be2b116d..d5fbe4a97 100644
--- a/src/version.sh
+++ b/src/version.sh
@@ -1,6 +1,6 @@
#!/bin/sh
VERSION_MAJOR=2
-VERSION_MINOR=0
-VERSION_PATCH=18
+VERSION_MINOR=1
+VERSION_PATCH=14
VERSION_EXTRA="-git"
diff --git a/src/win32/Config.cs b/src/win32/Config.cs
index 812700b5e..fc0b5c78f 100644
--- a/src/win32/Config.cs
+++ b/src/win32/Config.cs
@@ -1,7 +1,7 @@
/*
* Config.cs - Windows Configuration
*
- * (C) 2003-2024 Anope Team
+ * (C) 2003-2025 Anope Team
* Contact us at team@anope.org
*
* This program is free but copyrighted software; see the file COPYING for
diff --git a/src/win32/anope_windows.h b/src/win32/anope_windows.h
index 274667bb6..71e896992 100644
--- a/src/win32/anope_windows.h
+++ b/src/win32/anope_windows.h
@@ -29,9 +29,7 @@
# define DllExport __declspec(dllimport)
#endif
-#define MARK_DEPRECATED
-
-#if GETTEXT_FOUND
+#if HAVE_LOCALIZATION
/* Undefine some functions libintl defines */
# undef snprintf
# undef vsnprintf
@@ -53,13 +51,11 @@
#define EINPROGRESS WSAEWOULDBLOCK
#include "socket.h"
-#include "dir/dir.h"
#include "dl/dl.h"
#include "pipe/pipe.h"
-#include "pthread/pthread.h"
#include "sigaction/sigaction.h"
-typedef int ssize_t;
+typedef SSIZE_T ssize_t;
namespace Anope
{
@@ -69,9 +65,6 @@ namespace Anope
extern CoreExport void OnStartup();
extern CoreExport void OnShutdown();
extern CoreExport USHORT WindowsGetLanguage(const Anope::string &lang);
-extern CoreExport int gettimeofday(timeval *tv, void *);
-extern CoreExport Anope::string GetWindowsVersion();
-extern CoreExport bool SupportedWindowsVersion();
extern int setenv(const char *name, const char *value, int overwrite);
extern int unsetenv(const char *name);
extern int mkstemp(char *input);
diff --git a/src/win32/conanfile.txt b/src/win32/conanfile.txt
index ac72eee2a..d0ef69167 100644
--- a/src/win32/conanfile.txt
+++ b/src/win32/conanfile.txt
@@ -1,4 +1,5 @@
[requires]
+argon2/20190702
libmysqlclient/8.1.0
openssl/3.2.1
pcre2/10.42
@@ -7,6 +8,7 @@ gettext/0.21
libgettext/0.22
[options]
+argon2/*:shared=True
libmysqlclient/*:shared=True
openssl/*:shared=True
pcre2/*:shared=True
diff --git a/src/win32/dir/dir.cpp b/src/win32/dir/dir.cpp
deleted file mode 100644
index 944fd92b1..000000000
--- a/src/win32/dir/dir.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/* POSIX emulation layer for Windows.
- *
- * (C) 2008-2024 Anope Team
- * Contact us at 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];
- _snprintf(real_path, sizeof(real_path), "%s/*", path);
-
- DIR *d = new DIR();
- d->handle = FindFirstFile(real_path, &d->data);
- d->read_first = false;
-
- if (d->handle == INVALID_HANDLE_VALUE)
- {
- delete d;
- return NULL;
- }
-
- return d;
-}
-
-dirent *readdir(DIR *d)
-{
- if (d->read_first == false)
- d->read_first = true;
- else if (!FindNextFile(d->handle, &d->data))
- return NULL;
-
- d->ent.d_ino = 1;
- d->ent.d_name = d->data.cFileName;
-
- return &d->ent;
-}
-
-int closedir(DIR *d)
-{
- FindClose(d->handle);
- delete d;
- return 0;
-}
diff --git a/src/win32/dir/dir.h b/src/win32/dir/dir.h
deleted file mode 100644
index 4f444f672..000000000
--- a/src/win32/dir/dir.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* POSIX emulation layer for Windows.
- *
- * (C) 2008-2024 Anope Team
- * Contact us at team@anope.org
- *
- * Please read COPYING and README for further details.
- */
-
-#include <windows.h>
-
-struct dirent
-{
- int d_ino;
- char *d_name;
-};
-
-struct DIR
-{
- dirent ent;
- HANDLE handle;
- 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 9006c9cc6..464809578 100644
--- a/src/win32/dl/dl.cpp
+++ b/src/win32/dl/dl.cpp
@@ -1,6 +1,6 @@
/* POSIX emulation layer for Windows.
*
- * (C) 2008-2024 Anope Team
+ * (C) 2008-2025 Anope Team
* Contact us at 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 2c3509020..1907554dd 100644
--- a/src/win32/dl/dl.h
+++ b/src/win32/dl/dl.h
@@ -1,6 +1,6 @@
/* POSIX emulation layer for Windows.
*
- * (C) 2008-2024 Anope Team
+ * (C) 2008-2025 Anope Team
* Contact us at 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 d9e81e8eb..fd198e932 100644
--- a/src/win32/pipe/pipe.cpp
+++ b/src/win32/pipe/pipe.cpp
@@ -1,6 +1,6 @@
/* POSIX emulation layer for Windows.
*
- * (C) 2008-2024 Anope Team
+ * (C) 2008-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
diff --git a/src/win32/pipe/pipe.h b/src/win32/pipe/pipe.h
index 81d366d8d..80fbe2a7b 100644
--- a/src/win32/pipe/pipe.h
+++ b/src/win32/pipe/pipe.h
@@ -1,6 +1,6 @@
/* POSIX emulation layer for Windows.
*
- * (C) 2008-2024 Anope Team
+ * (C) 2008-2025 Anope Team
* Contact us at 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 7b705c9d6..000000000
--- a/src/win32/pthread/pthread.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/* POSIX emulation layer for Windows.
- *
- * (C) 2008-2024 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 072d66c93..000000000
--- a/src/win32/pthread/pthread.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* POSIX emulation layer for Windows.
- *
- * (C) 2008-2024 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 4c9af7ff2..3d2dfc60b 100644
--- a/src/win32/resource.h
+++ b/src/win32/resource.h
@@ -1,6 +1,6 @@
/*
*
- * (C) 2005-2024 Anope Team
+ * (C) 2005-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
diff --git a/src/win32/sigaction/sigaction.cpp b/src/win32/sigaction/sigaction.cpp
index 829ce6c66..4a3346aaa 100644
--- a/src/win32/sigaction/sigaction.cpp
+++ b/src/win32/sigaction/sigaction.cpp
@@ -1,6 +1,6 @@
/* POSIX emulation layer for Windows.
*
- * (C) 2008-2024 Anope Team
+ * (C) 2008-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
diff --git a/src/win32/sigaction/sigaction.h b/src/win32/sigaction/sigaction.h
index 0492ca0e0..272b82bbe 100644
--- a/src/win32/sigaction/sigaction.h
+++ b/src/win32/sigaction/sigaction.h
@@ -1,6 +1,6 @@
/* POSIX emulation layer for Windows.
*
- * (C) 2008-2024 Anope Team
+ * (C) 2008-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
@@ -18,7 +18,7 @@
# define SIGPIPE -1
#endif
-struct sigaction
+struct sigaction final
{
void (*sa_handler)(int);
int sa_flags;
diff --git a/src/win32/socket.cpp b/src/win32/socket.cpp
index 3a7a112d8..972cdbcc6 100644
--- a/src/win32/socket.cpp
+++ b/src/win32/socket.cpp
@@ -1,6 +1,6 @@
/* POSIX emulation layer for Windows.
*
- * (C) 2008-2024 Anope Team
+ * (C) 2008-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
@@ -48,87 +48,6 @@ int windows_accept(int fd, struct sockaddr *addr, int *addrlen)
return i;
}
-/** This is inet_pton, but it works on Windows
- * @param af The protocol type, AF_INET or AF_INET6
- * @param src The address
- * @param dst Struct to put results in
- * @return 1 on success, -1 on error
- */
-int windows_inet_pton(int af, const char *src, void *dst)
-{
- int address_length;
- sockaddr_storage sa;
- sockaddr_in *sin = reinterpret_cast<sockaddr_in *>(&sa);
- sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6 *>(&sa);
-
- switch (af)
- {
- case AF_INET:
- address_length = sizeof(sockaddr_in);
- break;
- case AF_INET6:
- address_length = sizeof(sockaddr_in6);
- break;
- default:
- return -1;
- }
-
- if (!WSAStringToAddress(static_cast<LPSTR>(const_cast<char *>(src)), af, NULL, reinterpret_cast<LPSOCKADDR>(&sa), &address_length))
- {
- switch (af)
- {
- case AF_INET:
- memcpy(dst, &sin->sin_addr, sizeof(in_addr));
- break;
- case AF_INET6:
- memcpy(dst, &sin6->sin6_addr, sizeof(in6_addr));
- break;
- }
- return 1;
- }
-
- return 0;
-}
-
-/** This is inet_ntop, but it works on Windows
- * @param af The protocol type, AF_INET or AF_INET6
- * @param src Network address structure
- * @param dst After converting put it here
- * @param size sizeof the dest
- * @return dst
- */
-const char *windows_inet_ntop(int af, const void *src, char *dst, size_t size)
-{
- int address_length;
- DWORD string_length = size;
- sockaddr_storage sa;
- sockaddr_in *sin = reinterpret_cast<sockaddr_in *>(&sa);
- sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6 *>(&sa);
-
- memset(&sa, 0, sizeof(sa));
-
- switch (af)
- {
- case AF_INET:
- address_length = sizeof(sockaddr_in);
- sin->sin_family = af;
- memcpy(&sin->sin_addr, src, sizeof(in_addr));
- break;
- case AF_INET6:
- address_length = sizeof(sockaddr_in6);
- sin6->sin6_family = af;
- memcpy(&sin6->sin6_addr, src, sizeof(in6_addr));
- break;
- default:
- return NULL;
- }
-
- if (!WSAAddressToString(reinterpret_cast<LPSOCKADDR>(&sa), address_length, NULL, dst, &string_length))
- return dst;
-
- return NULL;
-}
-
int fcntl(int fd, int cmd, int arg)
{
if (cmd == F_GETFL)
diff --git a/src/win32/socket.h b/src/win32/socket.h
index 7c20a65ad..1125774a8 100644
--- a/src/win32/socket.h
+++ b/src/win32/socket.h
@@ -1,6 +1,6 @@
/* POSIX emulation layer for Windows.
*
- * (C) 2008-2024 Anope Team
+ * (C) 2008-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
@@ -21,12 +21,8 @@ extern CoreExport int read(int fd, char *buf, size_t count);
extern CoreExport int write(int fd, const char *buf, size_t count);
extern CoreExport int windows_close(int fd);
extern CoreExport int windows_accept(int fd, struct sockaddr *addr, int *addrlen);
-extern CoreExport int windows_inet_pton(int af, const char *src, void *dst);
-extern CoreExport const char *windows_inet_ntop(int af, const void *src, char *dst, size_t size);
extern CoreExport int fcntl(int fd, int cmd, int arg);
#ifndef WIN32_NO_OVERRIDE
# define accept windows_accept
-# define inet_pton windows_inet_pton
-# define inet_ntop windows_inet_ntop
#endif
diff --git a/src/win32/win32.rc.cmake b/src/win32/win32.rc.cmake
index c72fe2b49..f0f3f8759 100644
--- a/src/win32/win32.rc.cmake
+++ b/src/win32/win32.rc.cmake
@@ -34,9 +34,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VER_ANOPE VERSIONINFO
FILEVERSION @VERSION_COMMA@
PRODUCTVERSION @VERSION_COMMA@
-#ifndef MINGW
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
-#endif
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
@@ -54,7 +52,7 @@ BEGIN
VALUE "FileDescription", "Anope IRC Services"
VALUE "FileVersion", "@VERSION_FULL@"
VALUE "InternalName", "Anope"
- VALUE "LegalCopyright", "Copyright (C) 2003-2024 Anope Team"
+ VALUE "LegalCopyright", "Copyright (C) 2003-2025 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 54ce44202..73045f408 100644
--- a/src/win32/windows.cpp
+++ b/src/win32/windows.cpp
@@ -1,7 +1,7 @@
/* POSIX emulation layer for Windows.
*
* (C) 2008-2011 Robin Burchell <w00t@inspircd.org>
- * (C) 2008-2024 Anope Team <team@anope.org>
+ * (C) 2008-2025 Anope Team <team@anope.org>
*
* Please read COPYING and README for further details.
*
@@ -18,23 +18,20 @@
#include <sys/types.h>
#include <fcntl.h>
-static struct WindowsLanguage
+static struct WindowsLanguage final
{
Anope::string languageName;
USHORT windowsLanguageName;
} WindowsLanguages[] = {
- {"ca_ES", LANG_CATALAN},
{"de_DE", LANG_GERMAN},
{"el_GR", LANG_GREEK},
{"en_US", LANG_ENGLISH},
{"es_ES", LANG_SPANISH},
{"fr_FR", LANG_FRENCH},
- {"hu_HU", LANG_HUNGARIAN},
{"it_IT", LANG_ITALIAN},
{"nl_NL", LANG_DUTCH},
{"pl_PL", LANG_POLISH},
{"pt_PT", LANG_PORTUGUESE},
- {"ru_RU", LANG_RUSSIAN},
{"tr_TR", LANG_TURKISH},
};
@@ -64,172 +61,6 @@ USHORT WindowsGetLanguage(const Anope::string &lang)
return LANG_NEUTRAL;
}
-/** Like gettimeofday(), but it works on Windows.
- * @param tv A timeval struct
- * @param tz Should be NULL, it is not used
- * @return 0 on success
- */
-int gettimeofday(timeval *tv, void *)
-{
- SYSTEMTIME st;
- GetSystemTime(&st);
-
- tv->tv_sec = Anope::CurTime;
- tv->tv_usec = st.wMilliseconds;
-
- return 0;
-}
-
-Anope::string GetWindowsVersion()
-{
- OSVERSIONINFOEX osvi;
- SYSTEM_INFO si;
-
- ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
- ZeroMemory(&si, sizeof(SYSTEM_INFO));
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-
- BOOL bOsVersionInfoEx = GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&osvi));
- if (!bOsVersionInfoEx)
- {
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (!GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&osvi)))
- return "";
- }
- GetSystemInfo(&si);
-
- Anope::string buf, extra, cputype;
- /* Determine CPU type 32 or 64 */
- if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
- cputype = " 64-bit";
- else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
- cputype = " 32-bit";
- else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
- cputype = " Itanium 64-bit";
-
- switch (osvi.dwPlatformId)
- {
- /* test for the Windows NT product family. */
- case VER_PLATFORM_WIN32_NT:
- /* Windows Vista or Windows Server 2008 */
- if (osvi.dwMajorVersion == 6 && !osvi.dwMinorVersion)
- {
- if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
- extra = " Enterprise Edition";
- else if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
- extra = " Datacenter Edition";
- else if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
- extra = " Home Premium/Basic";
- if (osvi.dwMinorVersion == 0)
- {
- if (osvi.wProductType & VER_NT_WORKSTATION)
- buf = "Microsoft Windows Vista" + cputype + extra;
- else
- buf = "Microsoft Windows Server 2008" + cputype + extra;
- }
- else if (osvi.dwMinorVersion == 1)
- {
- if (osvi.wProductType & VER_NT_WORKSTATION)
- buf = "Microsoft Windows 7" + cputype + extra;
- else
- buf = "Microsoft Windows Server 2008 R2" + cputype + extra;
- }
- }
- /* Windows 2003 or Windows XP Pro 64 */
- if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
- {
- if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
- extra = " Datacenter Edition";
- else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
- extra = " Enterprise Edition";
-#ifdef VER_SUITE_COMPUTE_SERVER
- else if (osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER)
- extra = " Compute Cluster Edition";
-#endif
- else if (osvi.wSuiteMask == VER_SUITE_BLADE)
- extra = " Web Edition";
- else
- extra = " Standard Edition";
- if (osvi.wProductType & VER_NT_WORKSTATION && si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
- buf = "Microsoft Windows XP Professional x64 Edition" + extra;
- else
- buf = "Microsoft Windows Server 2003 Family" + cputype + extra;
- }
- if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
- {
- if (osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT)
- extra = " Embedded";
- else if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
- extra = " Home Edition";
- buf = "Microsoft Windows XP" + extra;
- }
- if (osvi.dwMajorVersion == 5 && !osvi.dwMinorVersion)
- {
- if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
- extra = " Datacenter Server";
- else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
- extra = " Advanced Server";
- else
- extra = " Server";
- buf = "Microsoft Windows 2000" + extra;
- }
- if (osvi.dwMajorVersion <= 4)
- {
- if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
- extra = " Enterprise Edition";
- buf = "Microsoft Windows NT Server 4.0" + extra;
- }
- break;
- case VER_PLATFORM_WIN32_WINDOWS:
- if (osvi.dwMajorVersion == 4 && !osvi.dwMinorVersion)
- {
- if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B')
- extra = " OSR2";
- buf = "Microsoft Windows 95" + extra;
- }
- if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
- {
- if (osvi.szCSDVersion[1] == 'A')
- extra = "SE";
- buf = "Microsoft Windows 98" + extra;
- }
- if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
- buf = "Microsoft Windows Millennium Edition";
- }
- return buf;
-}
-
-bool SupportedWindowsVersion()
-{
- OSVERSIONINFOEX osvi;
-
- ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-
- BOOL bOsVersionInfoEx = GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&osvi));
- if (!bOsVersionInfoEx)
- {
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (!GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&osvi)))
- return false;
- }
-
- switch (osvi.dwPlatformId)
- {
- /* test for the Windows NT product family. */
- case VER_PLATFORM_WIN32_NT:
- /* win nt4 */
- if (osvi.dwMajorVersion <= 4)
- return false;
- /* the rest */
- return true;
- /* win95 win98 winME */
- case VER_PLATFORM_WIN32_WINDOWS:
- return false;
- }
- return false;
-}
-
int setenv(const char *name, const char *value, int overwrite)
{
return SetEnvironmentVariable(name, value);
diff --git a/src/xline.cpp b/src/xline.cpp
index 87279b412..2b6a93e9a 100644
--- a/src/xline.cpp
+++ b/src/xline.cpp
@@ -21,15 +21,15 @@
/* 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");
+Serialize::Checker<std::multimap<Anope::string, XLine *, ci::less> > XLineManager::XLinesByUID(XLINE_TYPE);
void XLine::Init()
{
- if (this->mask.length() >= 2 && this->mask[0] == '/' && this->mask[this->mask.length() - 1] == '/' && !Config->GetBlock("options")->Get<const Anope::string>("regexengine").empty())
+ if (this->mask.length() >= 2 && this->mask[0] == '/' && this->mask[this->mask.length() - 1] == '/' && !Config->GetBlock("options").Get<const Anope::string>("regexengine").empty())
{
Anope::string stripped_mask = this->mask.substr(1, this->mask.length() - 2);
- ServiceReference<RegexProvider> provider("Regex", Config->GetBlock("options")->Get<const Anope::string>("regexengine"));
+ ServiceReference<RegexProvider> provider("Regex", Config->GetBlock("options").Get<const Anope::string>("regexengine"));
if (provider)
{
try
@@ -86,7 +86,12 @@ 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(const Anope::string &ma, const Anope::string &r, const Anope::string &uid)
+ : Serializable(XLINE_TYPE)
+ , mask(ma)
+ , by(Me->GetName())
+ , reason(r)
+ , id(uid)
{
regex = NULL;
manager = NULL;
@@ -95,7 +100,14 @@ XLine::XLine(const Anope::string &ma, const Anope::string &r, const Anope::strin
this->Init();
}
-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)
+XLine::XLine(const Anope::string &ma, const Anope::string &b, const time_t ex, const Anope::string &r, const Anope::string &uid)
+ : Serializable(XLINE_TYPE)
+ , mask(ma)
+ , by(b)
+ , created(Anope::CurTime)
+ , expires(ex)
+ , reason(r)
+ , id(uid)
{
regex = NULL;
manager = NULL;
@@ -151,19 +163,26 @@ bool XLine::IsRegex() const
return !this->mask.empty() && this->mask[0] == '/' && this->mask[this->mask.length() - 1] == '/';
}
-void XLine::Serialize(Serialize::Data &data) const
+XLine::Type::Type()
+ : Serialize::Type(XLINE_TYPE)
{
- 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;
}
-Serializable* XLine::Unserialize(Serializable *obj, Serialize::Data &data)
+void XLine::Type::Serialize(const Serializable *obj, Serialize::Data &data) const
+{
+ const auto *xl = static_cast<const XLine *>(obj);
+
+ data.Store("mask", xl->mask);
+ data.Store("by", xl->by);
+ data.Store("created", xl->created);
+ data.Store("expires", xl->expires);
+ data.Store("reason", xl->reason);
+ data.Store("uid", xl->id);
+ if (xl->manager)
+ data.Store("manager", xl->manager->name);
+}
+
+Serializable *XLine::Type::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string smanager;
@@ -224,10 +243,8 @@ void XLineManager::UnregisterXLineManager(XLineManager *xlm)
void XLineManager::CheckAll(User *u)
{
- for (std::list<XLineManager *>::iterator it = XLineManagers.begin(), it_end = XLineManagers.end(); it != it_end; ++it)
+ for (auto *xlm : XLineManagers)
{
- XLineManager *xlm = *it;
-
if (xlm->CheckAllXLines(u))
break;
}
@@ -251,7 +268,7 @@ Anope::string XLineManager::GenerateUID()
{
char c;
do
- c = (rand() % 75) + 48;
+ c = (Anope::RandomNumber() % 75) + 48;
while (!isupper(c) && !isdigit(c));
id += c;
}
@@ -261,7 +278,10 @@ Anope::string XLineManager::GenerateUID()
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, "XLineManager", xname)
+ , type(t)
+ , xlines(XLINE_TYPE)
{
}
@@ -288,7 +308,7 @@ const std::vector<XLine *> &XLineManager::GetList() const
void XLineManager::AddXLine(XLine *x)
{
if (!x->id.empty())
- XLinesByUID->insert(std::make_pair(x->id, x));
+ XLinesByUID->emplace(x->id, x);
this->xlines->push_back(x);
x->manager = this;
}
@@ -346,7 +366,7 @@ bool XLineManager::DelXLine(XLine *x)
return false;
}
-XLine* XLineManager::GetEntry(unsigned index)
+XLine *XLineManager::GetEntry(unsigned index)
{
if (index >= this->xlines->size())
return NULL;
@@ -361,9 +381,8 @@ void XLineManager::Clear()
std::vector<XLine *> xl;
this->xlines->swap(xl);
- for (unsigned i = 0; i < xl.size(); ++i)
+ for (auto *x : xl)
{
- XLine *x = xl[i];
if (!x->id.empty())
XLinesByUID->erase(x->id);
delete x;
@@ -417,7 +436,7 @@ bool XLineManager::CanAdd(CommandSource &source, const Anope::string &mask, time
return true;
}
-XLine* XLineManager::HasEntry(const Anope::string &mask)
+XLine *XLineManager::HasEntry(const Anope::string &mask)
{
std::multimap<Anope::string, XLine *, ci::less>::iterator it = XLinesByUID->find(mask);
if (it != XLinesByUID->end())
@@ -427,10 +446,8 @@ XLine* XLineManager::HasEntry(const Anope::string &mask)
it->second->QueueUpdate();
return it->second;
}
- for (unsigned i = 0, end = this->xlines->size(); i < end; ++i)
+ for (auto *x : *this->xlines)
{
- XLine *x = this->xlines->at(i);
-
if (x->mask.equals_ci(mask))
{
x->QueueUpdate();