aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules
diff options
context:
space:
mode:
authorGravatar Sadie Powell2019-02-05 00:47:30 +0000
committerGravatar Sadie Powell2019-02-05 00:47:30 +0000
commitbfa5fb407e13ad4adb5c062021de50ecd760ed95 (patch)
treec573269b1a94fd7e7da27c1b90b05fa60916de23 /src/modules
parentRemove support for the deprecated <power> config tag. (diff)
parentModuleManager: use std::flush instead of fflush(stdout). (diff)
Merge branch 'insp3' into master.
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/m_anticaps.cpp2
-rw-r--r--src/modules/m_cban.cpp6
-rw-r--r--src/modules/m_cgiirc.cpp4
-rw-r--r--src/modules/m_check.cpp75
-rw-r--r--src/modules/m_cloaking.cpp12
-rw-r--r--src/modules/m_hostchange.cpp4
-rw-r--r--src/modules/m_httpd_stats.cpp372
-rw-r--r--src/modules/m_ident.cpp96
-rw-r--r--src/modules/m_ircv3_sts.cpp2
-rw-r--r--src/modules/m_muteban.cpp10
-rw-r--r--src/modules/m_opermotd.cpp2
-rw-r--r--src/modules/m_rline.cpp6
-rw-r--r--src/modules/m_samode.cpp4
-rw-r--r--src/modules/m_setname.cpp17
-rw-r--r--src/modules/m_showwhois.cpp2
-rw-r--r--src/modules/m_shun.cpp10
-rw-r--r--src/modules/m_spanningtree/delline.cpp7
-rw-r--r--src/modules/m_spanningtree/uid.cpp2
-rw-r--r--src/modules/m_sslinfo.cpp11
-rw-r--r--src/modules/m_svshold.cpp6
20 files changed, 412 insertions, 238 deletions
diff --git a/src/modules/m_anticaps.cpp b/src/modules/m_anticaps.cpp
index efb3d091b..c5da88bfb 100644
--- a/src/modules/m_anticaps.cpp
+++ b/src/modules/m_anticaps.cpp
@@ -148,7 +148,7 @@ class AntiCapsMode : public ParamMode<AntiCapsMode, SimpleExtItem<AntiCapsSettin
out.push_back(':');
out.append(ConvToStr(acs->minlen));
out.push_back(':');
- out.append(ConvToStr(acs->percent));
+ out.append(ConvNumeric(acs->percent));
}
};
diff --git a/src/modules/m_cban.cpp b/src/modules/m_cban.cpp
index 724ebc10f..949b410dd 100644
--- a/src/modules/m_cban.cpp
+++ b/src/modules/m_cban.cpp
@@ -98,9 +98,11 @@ class CommandCBan : public Command
if (parameters.size() == 1)
{
- if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "CBAN", user))
+ std::string reason;
+
+ if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "CBAN", reason, user))
{
- ServerInstance->SNO->WriteGlobalSno('x', "%s removed CBan on %s.",user->nick.c_str(),parameters[0].c_str());
+ ServerInstance->SNO->WriteGlobalSno('x', "%s removed CBan on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str());
}
else
{
diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp
index 55129b78e..ec926242e 100644
--- a/src/modules/m_cgiirc.cpp
+++ b/src/modules/m_cgiirc.cpp
@@ -311,7 +311,7 @@ class ModuleCgiIRC
}
else
{
- throw ModuleException(type + " is an invalid <cgihost:mask> type, at " + tag->getTagLocation());
+ throw ModuleException(type + " is an invalid <cgihost:mask> type, at " + tag->getTagLocation());
}
}
@@ -369,7 +369,7 @@ class ModuleCgiIRC
user->ChangeIdent(newident);
user->SetClientIP(address);
- break;
+ break;
}
return MOD_RES_PASSTHRU;
}
diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp
index ca9541176..cf2954697 100644
--- a/src/modules/m_check.cpp
+++ b/src/modules/m_check.cpp
@@ -30,9 +30,18 @@ enum
class CheckContext
{
+ private:
User* const user;
const std::string& target;
+ std::string FormatTime(time_t ts)
+ {
+ std::string timestr(InspIRCd::TimeString(ts, "%Y-%m-%d %H:%M:%S UTC (", true));
+ timestr.append(ConvToStr(ts));
+ timestr.push_back(')');
+ return timestr;
+ }
+
public:
CheckContext(User* u, const std::string& targetstr)
: user(u)
@@ -51,18 +60,28 @@ class CheckContext
user->WriteRemoteNumeric(RPL_CHECK, type, text);
}
+ void Write(const std::string& type, time_t ts)
+ {
+ user->WriteRemoteNumeric(RPL_CHECK, type, FormatTime(ts));
+ }
+
User* GetUser() const { return user; }
- void DumpListMode(const ListModeBase::ModeList* list)
+ void DumpListMode(ListModeBase* mode, Channel* chan)
{
+ const ListModeBase::ModeList* list = mode->GetList(chan);
if (!list)
return;
- CheckContext::List modelist(*this, "modelist");
for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i)
- modelist.Add(i->mask);
-
- modelist.Flush();
+ {
+ CheckContext::List listmode(*this, "listmode");
+ listmode.Add(ConvToStr(mode->GetModeChar()));
+ listmode.Add(i->mask);
+ listmode.Add(i->setter);
+ listmode.Add(FormatTime(i->time));
+ listmode.Flush();
+ }
}
void DumpExt(Extensible* ext)
@@ -130,19 +149,9 @@ class CommandCheck : public Command
flags_needed = 'o'; syntax = "<nickname>|<ip>|<hostmask>|<channel> <server>";
}
- std::string timestring(time_t time)
- {
- char timebuf[60];
- struct tm *mytime = gmtime(&time);
- strftime(timebuf, 59, "%Y-%m-%d %H:%M:%S UTC (", mytime);
- std::string ret(timebuf);
- ret.append(ConvToStr(time)).push_back(')');
- return ret;
- }
-
CmdResult Handle(User* user, const Params& parameters) override
{
- if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName)
+ if (parameters.size() > 1 && !irc::equals(parameters[1], ServerInstance->Config->ServerName))
return CMD_SUCCESS;
User *targuser;
@@ -173,15 +182,15 @@ class CommandCheck : public Command
context.Write("snomasks", GetSnomasks(targuser));
context.Write("server", targuser->server->GetName());
context.Write("uid", targuser->uuid);
- context.Write("signon", timestring(targuser->signon));
- context.Write("nickts", timestring(targuser->age));
+ context.Write("signon", targuser->signon);
+ context.Write("nickts", targuser->age);
if (loctarg)
- context.Write("lastmsg", timestring(loctarg->idle_lastmsg));
+ context.Write("lastmsg", loctarg->idle_lastmsg);
if (targuser->IsAway())
{
/* user is away */
- context.Write("awaytime", timestring(targuser->awaytime));
+ context.Write("awaytime", targuser->awaytime);
context.Write("awaymsg", targuser->awaymsg);
}
@@ -192,16 +201,10 @@ class CommandCheck : public Command
context.Write("opertype", oper->name);
if (loctarg)
{
- std::string umodes = GetAllowedOperOnlyModes(loctarg, MODETYPE_USER);
- std::string cmodes = GetAllowedOperOnlyModes(loctarg, MODETYPE_CHANNEL);
- context.Write("modeperms", "user=" + umodes + " channel=" + cmodes);
-
- CheckContext::List opcmdlist(context, "commandperms");
- opcmdlist.Add(oper->AllowedOperCommands.ToString());
- opcmdlist.Flush();
- CheckContext::List privlist(context, "permissions");
- privlist.Add(oper->AllowedPrivs.ToString());
- privlist.Flush();
+ context.Write("chanmodeperms", GetAllowedOperOnlyModes(loctarg, MODETYPE_CHANNEL));
+ context.Write("usermodeperms", GetAllowedOperOnlyModes(loctarg, MODETYPE_USER));
+ context.Write("commandperms", oper->AllowedOperCommands.ToString());
+ context.Write("permissions", oper->AllowedPrivs.ToString());
}
}
@@ -237,14 +240,14 @@ class CommandCheck : public Command
else if (targchan)
{
/* /check on a channel */
- context.Write("timestamp", timestring(targchan->age));
+ context.Write("createdat", targchan->age);
if (!targchan->topic.empty())
{
/* there is a topic, assume topic related information exists */
context.Write("topic", targchan->topic);
context.Write("topic_setby", targchan->setby);
- context.Write("topic_setat", timestring(targchan->topicset));
+ context.Write("topic_setat", targchan->topicset);
}
context.Write("modes", targchan->ChanModes(true));
@@ -261,14 +264,14 @@ class CommandCheck : public Command
* Unlike Asuka, I define a clone as coming from the same host. --w00t
*/
const UserManager::CloneCounts& clonecount = ServerInstance->Users->GetCloneCounts(i->first);
- context.Write("member", InspIRCd::Format("%-3u %s%s (%s@%s) %s ", clonecount.global,
- i->second->GetAllPrefixChars().c_str(), i->first->nick.c_str(),
- i->first->ident.c_str(), i->first->GetDisplayedHost().c_str(), i->first->GetRealName().c_str()));
+ context.Write("member", InspIRCd::Format("%u %s%s (%s)", clonecount.global,
+ i->second->GetAllPrefixChars().c_str(), i->first->GetFullHost().c_str(),
+ i->first->GetRealName().c_str()));
}
const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes();
for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i)
- context.DumpListMode((*i)->GetList(targchan));
+ context.DumpListMode(*i, targchan);
context.DumpExt(targchan);
}
diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp
index bf96216c3..01bdce2ca 100644
--- a/src/modules/m_cloaking.cpp
+++ b/src/modules/m_cloaking.cpp
@@ -210,24 +210,24 @@ class ModuleCloaking : public Module
{
// The position at which we found the last dot.
std::string::const_reverse_iterator dotpos;
-
+
// The number of dots we have seen so far.
unsigned int seendots = 0;
-
+
for (std::string::const_reverse_iterator iter = host.rbegin(); iter != host.rend(); ++iter)
{
if (*iter != '.')
continue;
-
+
// We have found a dot!
dotpos = iter;
seendots += 1;
-
+
// Do we have enough segments to stop?
if (seendots >= domainparts)
break;
}
-
+
// We only returns a domain part if more than one label is
// present. See above for a full explanation.
if (!seendots)
@@ -435,7 +435,7 @@ class ModuleCloaking : public Module
else if (stdalgo::string::equalsci(mode, "full"))
newcloaks.push_back(CloakInfo(MODE_OPAQUE, key, prefix, suffix));
else
- throw ModuleException(mode + " is an invalid value for <cloak:mode>; acceptable values are 'half' and 'full', at " + tag->getTagLocation());
+ throw ModuleException(mode + " is an invalid value for <cloak:mode>; acceptable values are 'half' and 'full', at " + tag->getTagLocation());
}
// The cloak configuration was valid so we can apply it.
diff --git a/src/modules/m_hostchange.cpp b/src/modules/m_hostchange.cpp
index b676e19a7..7b53a53d7 100644
--- a/src/modules/m_hostchange.cpp
+++ b/src/modules/m_hostchange.cpp
@@ -34,7 +34,7 @@ class HostRule
// Add the user's nickname to their hostname.
HCA_ADDNICK,
- // Set the user's hostname to the specific value.
+ // Set the user's hostname to the specific value.
HCA_SET
};
@@ -168,7 +168,7 @@ private:
}
else
{
- throw ModuleException(action + " is an invalid <hostchange:action> type, at " + tag->getTagLocation());
+ throw ModuleException(action + " is an invalid <hostchange:action> type, at " + tag->getTagLocation());
}
}
diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp
index 927e6c906..7442587da 100644
--- a/src/modules/m_httpd_stats.cpp
+++ b/src/modules/m_httpd_stats.cpp
@@ -25,34 +25,41 @@
#include "modules/httpd.h"
#include "xline.h"
-class ModuleHttpStats : public Module, public HTTPRequestEventListener
+namespace Stats
{
- static const insp::flat_map<char, char const*>& entities;
- HTTPdAPI API;
+ struct Entities
+ {
+ static const insp::flat_map<char, char const*>& entities;
+ };
- public:
- ModuleHttpStats()
- : HTTPRequestEventListener(this)
- , API(this)
+ static const insp::flat_map<char, char const*>& init_entities()
{
+ static insp::flat_map<char, char const*> entities;
+ entities['<'] = "lt";
+ entities['>'] = "gt";
+ entities['&'] = "amp";
+ entities['"'] = "quot";
+ return entities;
}
- std::string Sanitize(const std::string &str)
+ const insp::flat_map<char, char const*>& Entities::entities = init_entities();
+
+ std::string Sanitize(const std::string& str)
{
std::string ret;
ret.reserve(str.length() * 2);
for (std::string::const_iterator x = str.begin(); x != str.end(); ++x)
{
- insp::flat_map<char, char const*>::const_iterator it = entities.find(*x);
+ insp::flat_map<char, char const*>::const_iterator it = Entities::entities.find(*x);
- if (it != entities.end())
+ if (it != Entities::entities.end())
{
ret += '&';
ret += it->second;
ret += ';';
}
- else if (*x == 0x09 || *x == 0x0A || *x == 0x0D || ((*x >= 0x20) && (*x <= 0x7e)))
+ else if (*x == 0x09 || *x == 0x0A || *x == 0x0D || ((*x >= 0x20) && (*x <= 0x7e)))
{
// The XML specification defines the following characters as valid inside an XML document:
// Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
@@ -73,10 +80,10 @@ class ModuleHttpStats : public Module, public HTTPRequestEventListener
return ret;
}
- void DumpMeta(std::stringstream& data, Extensible* ext)
+ void DumpMeta(std::ostream& data, Extensible* ext)
{
data << "<metadata>";
- for(Extensible::ExtensibleStore::const_iterator i = ext->GetExtList().begin(); i != ext->GetExtList().end(); i++)
+ for (Extensible::ExtensibleStore::const_iterator i = ext->GetExtList().begin(); i != ext->GetExtList().end(); i++)
{
ExtensionItem* item = i->first;
std::string value = item->serialize(FORMAT_USER, ext, i->second);
@@ -88,156 +95,241 @@ class ModuleHttpStats : public Module, public HTTPRequestEventListener
data << "</metadata>";
}
- ModResult HandleRequest(HTTPRequest* http)
+ std::ostream& ServerInfo(std::ostream& data)
{
- std::stringstream data("");
+ return data << "<server><name>" << ServerInstance->Config->ServerName << "</name><description>"
+ << Sanitize(ServerInstance->Config->ServerDesc) << "</description><version>"
+ << Sanitize(ServerInstance->GetVersionString()) << "</version></server>";
+ }
+ std::ostream& ISupport(std::ostream& data)
+ {
+ data << "<isupport>";
+ const std::vector<Numeric::Numeric>& isupport = ServerInstance->ISupport.GetLines();
+ for (std::vector<Numeric::Numeric>::const_iterator i = isupport.begin(); i != isupport.end(); ++i)
{
- ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event");
+ const Numeric::Numeric& num = *i;
+ for (std::vector<std::string>::const_iterator j = num.GetParams().begin(); j != num.GetParams().end() - 1; ++j)
+ data << "<token>" << Sanitize(*j) << "</token>";
+ }
+ return data << "</isupport>";
+ }
- if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/"))
- {
- data << "<inspircdstats><server><name>" << ServerInstance->Config->ServerName << "</name><description>"
- << Sanitize(ServerInstance->Config->ServerDesc) << "</description><version>"
- << Sanitize(ServerInstance->GetVersionString()) << "</version></server>";
+ std::ostream& General(std::ostream& data)
+ {
+ data << "<general>";
+ data << "<usercount>" << ServerInstance->Users->GetUsers().size() << "</usercount>";
+ data << "<localusercount>" << ServerInstance->Users->GetLocalUsers().size() << "</localusercount>";
+ data << "<channelcount>" << ServerInstance->GetChans().size() << "</channelcount>";
+ data << "<opercount>" << ServerInstance->Users->all_opers.size() << "</opercount>";
+ data << "<socketcount>" << (SocketEngine::GetUsedFds()) << "</socketcount><socketmax>" << SocketEngine::GetMaxFds() << "</socketmax>";
+ data << "<uptime><boot_time_t>" << ServerInstance->startup_time << "</boot_time_t></uptime>";
- data << "<general>";
- data << "<usercount>" << ServerInstance->Users->GetUsers().size() << "</usercount>";
- data << "<channelcount>" << ServerInstance->GetChans().size() << "</channelcount>";
- data << "<opercount>" << ServerInstance->Users->all_opers.size() << "</opercount>";
- data << "<socketcount>" << (SocketEngine::GetUsedFds()) << "</socketcount><socketmax>" << SocketEngine::GetMaxFds() << "</socketmax>";
- data << "<uptime><boot_time_t>" << ServerInstance->startup_time << "</boot_time_t></uptime>";
+ data << ISupport;
+ return data << "</general>";
+ }
- data << "<isupport>";
- const std::vector<Numeric::Numeric>& isupport = ServerInstance->ISupport.GetLines();
- for (std::vector<Numeric::Numeric>::const_iterator i = isupport.begin(); i != isupport.end(); ++i)
- {
- const Numeric::Numeric& num = *i;
- for (std::vector<std::string>::const_iterator j = num.GetParams().begin(); j != num.GetParams().end()-1; ++j)
- data << "<token>" << Sanitize(*j) << "</token>" << std::endl;
- }
- data << "</isupport></general><xlines>";
- std::vector<std::string> xltypes = ServerInstance->XLines->GetAllTypes();
- for (std::vector<std::string>::iterator it = xltypes.begin(); it != xltypes.end(); ++it)
- {
- XLineLookup* lookup = ServerInstance->XLines->GetAll(*it);
+ std::ostream& XLines(std::ostream& data)
+ {
+ data << "<xlines>";
+ std::vector<std::string> xltypes = ServerInstance->XLines->GetAllTypes();
+ for (std::vector<std::string>::iterator it = xltypes.begin(); it != xltypes.end(); ++it)
+ {
+ XLineLookup* lookup = ServerInstance->XLines->GetAll(*it);
- if (!lookup)
- continue;
- for (LookupIter i = lookup->begin(); i != lookup->end(); ++i)
- {
- data << "<xline type=\"" << it->c_str() << "\"><mask>"
- << Sanitize(i->second->Displayable()) << "</mask><settime>"
- << i->second->set_time << "</settime><duration>" << i->second->duration
- << "</duration><reason>" << Sanitize(i->second->reason)
- << "</reason></xline>";
- }
- }
+ if (!lookup)
+ continue;
+ for (LookupIter i = lookup->begin(); i != lookup->end(); ++i)
+ {
+ data << "<xline type=\"" << it->c_str() << "\"><mask>"
+ << Sanitize(i->second->Displayable()) << "</mask><settime>"
+ << i->second->set_time << "</settime><duration>" << i->second->duration
+ << "</duration><reason>" << Sanitize(i->second->reason)
+ << "</reason></xline>";
+ }
+ }
+ return data << "</xlines>";
+ }
+
+ std::ostream& Modules(std::ostream& data)
+ {
+ data << "<modulelist>";
+ const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
- data << "</xlines><modulelist>";
- const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
+ for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
+ {
+ Version v = i->second->GetVersion();
+ data << "<module><name>" << i->first << "</name><description>" << Sanitize(v.description) << "</description></module>";
+ }
+ return data << "</modulelist>";
+ }
- for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
- {
- Version v = i->second->GetVersion();
- data << "<module><name>" << i->first << "</name><description>" << Sanitize(v.description) << "</description></module>";
- }
- data << "</modulelist><channellist>";
+ std::ostream& Channels(std::ostream& data)
+ {
+ data << "<channellist>";
- const chan_hash& chans = ServerInstance->GetChans();
- for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
- {
- Channel* c = i->second;
+ const chan_hash& chans = ServerInstance->GetChans();
+ for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
+ {
+ Channel* c = i->second;
- data << "<channel>";
- data << "<usercount>" << c->GetUsers().size() << "</usercount><channelname>" << Sanitize(c->name) << "</channelname>";
- data << "<channeltopic>";
- data << "<topictext>" << Sanitize(c->topic) << "</topictext>";
- data << "<setby>" << Sanitize(c->setby) << "</setby>";
- data << "<settime>" << c->topicset << "</settime>";
- data << "</channeltopic>";
- data << "<channelmodes>" << Sanitize(c->ChanModes(true)) << "</channelmodes>";
+ data << "<channel>";
+ data << "<usercount>" << c->GetUsers().size() << "</usercount><channelname>" << Sanitize(c->name) << "</channelname>";
+ data << "<channeltopic>";
+ data << "<topictext>" << Sanitize(c->topic) << "</topictext>";
+ data << "<setby>" << Sanitize(c->setby) << "</setby>";
+ data << "<settime>" << c->topicset << "</settime>";
+ data << "</channeltopic>";
+ data << "<channelmodes>" << Sanitize(c->ChanModes(true)) << "</channelmodes>";
- const Channel::MemberMap& ulist = c->GetUsers();
- for (Channel::MemberMap::const_iterator x = ulist.begin(); x != ulist.end(); ++x)
- {
- Membership* memb = x->second;
- data << "<channelmember><uid>" << memb->user->uuid << "</uid><privs>"
- << Sanitize(memb->GetAllPrefixChars()) << "</privs><modes>"
- << memb->modes << "</modes>";
- DumpMeta(data, memb);
- data << "</channelmember>";
- }
+ const Channel::MemberMap& ulist = c->GetUsers();
+ for (Channel::MemberMap::const_iterator x = ulist.begin(); x != ulist.end(); ++x)
+ {
+ Membership* memb = x->second;
+ data << "<channelmember><uid>" << memb->user->uuid << "</uid><privs>"
+ << Sanitize(memb->GetAllPrefixChars()) << "</privs><modes>"
+ << memb->modes << "</modes>";
+ DumpMeta(data, memb);
+ data << "</channelmember>";
+ }
- DumpMeta(data, c);
+ DumpMeta(data, c);
- data << "</channel>";
- }
+ data << "</channel>";
+ }
- data << "</channellist><userlist>";
+ return data << "</channellist>";
+ }
- const user_hash& users = ServerInstance->Users->GetUsers();
- for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
- {
- User* u = i->second;
+ std::ostream& Users(std::ostream& data)
+ {
+ data << "<userlist>";
+ const user_hash& users = ServerInstance->Users->GetUsers();
+ for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
+ {
+ User* u = i->second;
- data << "<user>";
- data << "<nickname>" << u->nick << "</nickname><uuid>" << u->uuid << "</uuid><realhost>"
- << u->GetRealHost() << "</realhost><displayhost>" << u->GetDisplayedHost() << "</displayhost><realname>"
- << Sanitize(u->GetRealName()) << "</realname><server>" << u->server->GetName() << "</server>";
- if (u->IsAway())
- data << "<away>" << Sanitize(u->awaymsg) << "</away><awaytime>" << u->awaytime << "</awaytime>";
- if (u->IsOper())
- data << "<opertype>" << Sanitize(u->oper->name) << "</opertype>";
- data << "<modes>" << u->GetModeLetters().substr(1) << "</modes><ident>" << Sanitize(u->ident) << "</ident>";
- LocalUser* lu = IS_LOCAL(u);
- if (lu)
- data << "<port>" << lu->GetServerPort() << "</port><servaddr>"
- << lu->server_sa.str() << "</servaddr>";
- data << "<ipaddress>" << u->GetIPString() << "</ipaddress>";
+ data << "<user>";
+ data << "<nickname>" << u->nick << "</nickname><uuid>" << u->uuid << "</uuid><realhost>"
+ << u->GetRealHost() << "</realhost><displayhost>" << u->GetDisplayedHost() << "</displayhost><realname>"
+ << Sanitize(u->GetRealName()) << "</realname><server>" << u->server->GetName() << "</server>";
+ if (u->IsAway())
+ data << "<away>" << Sanitize(u->awaymsg) << "</away><awaytime>" << u->awaytime << "</awaytime>";
+ if (u->IsOper())
+ data << "<opertype>" << Sanitize(u->oper->name) << "</opertype>";
+ data << "<modes>" << u->GetModeLetters().substr(1) << "</modes><ident>" << Sanitize(u->ident) << "</ident>";
+ LocalUser* lu = IS_LOCAL(u);
+ if (lu)
+ data << "<port>" << lu->GetServerPort() << "</port><servaddr>"
+ << lu->server_sa.str() << "</servaddr>";
+ data << "<ipaddress>" << u->GetIPString() << "</ipaddress>";
- DumpMeta(data, u);
+ DumpMeta(data, u);
- data << "</user>";
- }
+ data << "</user>";
+ }
+ return data << "</userlist>";
+ }
- data << "</userlist><serverlist>";
+ std::ostream& Servers(std::ostream& data)
+ {
+ data << "<serverlist>";
- ProtocolInterface::ServerList sl;
- ServerInstance->PI->GetServerList(sl);
+ ProtocolInterface::ServerList sl;
+ ServerInstance->PI->GetServerList(sl);
- for (ProtocolInterface::ServerList::const_iterator b = sl.begin(); b != sl.end(); ++b)
- {
- data << "<server>";
- data << "<servername>" << b->servername << "</servername>";
- data << "<parentname>" << b->parentname << "</parentname>";
- data << "<description>" << Sanitize(b->description) << "</description>";
- data << "<usercount>" << b->usercount << "</usercount>";
+ for (ProtocolInterface::ServerList::const_iterator b = sl.begin(); b != sl.end(); ++b)
+ {
+ data << "<server>";
+ data << "<servername>" << b->servername << "</servername>";
+ data << "<parentname>" << b->parentname << "</parentname>";
+ data << "<description>" << Sanitize(b->description) << "</description>";
+ data << "<usercount>" << b->usercount << "</usercount>";
// This is currently not implemented, so, commented out.
// data << "<opercount>" << b->opercount << "</opercount>";
- data << "<lagmillisecs>" << b->latencyms << "</lagmillisecs>";
- data << "</server>";
- }
+ data << "<lagmillisecs>" << b->latencyms << "</lagmillisecs>";
+ data << "</server>";
+ }
+
+ return data << "</serverlist>";
+ }
- data << "</serverlist><commandlist>";
+ std::ostream& Commands(std::ostream& data)
+ {
+ data << "<commandlist>";
- const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands();
- for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i)
- {
- data << "<command><name>" << i->second->name << "</name><usecount>" << i->second->use_count << "</usecount></command>";
- }
+ const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands();
+ for (CommandParser::CommandMap::const_iterator i = commands.begin(); i != commands.end(); ++i)
+ {
+ data << "<command><name>" << i->second->name << "</name><usecount>" << i->second->use_count << "</usecount></command>";
+ }
+ return data << "</commandlist>";
+ }
+}
- data << "</commandlist></inspircdstats>";
+class ModuleHttpStats : public Module, public HTTPRequestEventListener
+{
+ HTTPdAPI API;
- /* Send the document back to m_httpd */
- HTTPDocumentResponse response(this, *http, &data, 200);
- response.headers.SetHeader("X-Powered-By", MODNAME);
- response.headers.SetHeader("Content-Type", "text/xml");
- API->SendResponse(response);
- return MOD_RES_DENY; // Handled
- }
+ public:
+ ModuleHttpStats()
+ : HTTPRequestEventListener(this)
+ , API(this)
+ {
+ }
+
+ ModResult HandleRequest(HTTPRequest* http)
+ {
+ std::string uri = http->GetURI();
+
+ if (uri != "/stats" && uri.substr(0, 7) != "/stats/")
+ return MOD_RES_PASSTHRU;
+
+ if (uri[uri.size() - 1] == '/')
+ uri.erase(uri.size() - 1, 1);
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event");
+
+ bool found = true;
+ std::stringstream data;
+ data << "<inspircdstats>";
+
+ if (uri == "/stats")
+ {
+ data << Stats::ServerInfo << Stats::General
+ << Stats::XLines << Stats::Modules
+ << Stats::Channels << Stats::Users
+ << Stats::Servers << Stats::Commands;
+ }
+ else if (uri == "/stats/general")
+ {
+ data << Stats::General;
+ }
+ else if (uri == "/stats/users")
+ {
+ data << Stats::Users;
+ }
+ else
+ {
+ found = false;
}
- return MOD_RES_PASSTHRU;
+
+ if (found)
+ {
+ data << "</inspircdstats>";
+ }
+ else
+ {
+ data.clear();
+ data.str(std::string());
+ }
+
+ /* Send the document back to m_httpd */
+ HTTPDocumentResponse response(this, *http, &data, found ? 200 : 404);
+ response.headers.SetHeader("X-Powered-By", MODNAME);
+ response.headers.SetHeader("Content-Type", "text/xml");
+ API->SendResponse(response);
+ return MOD_RES_DENY; // Handled
}
ModResult OnHTTPRequest(HTTPRequest& req) override
@@ -251,16 +343,4 @@ class ModuleHttpStats : public Module, public HTTPRequestEventListener
}
};
-static const insp::flat_map<char, char const*>& init_entities()
-{
- static insp::flat_map<char, char const*> entities;
- entities['<'] = "lt";
- entities['>'] = "gt";
- entities['&'] = "amp";
- entities['"'] = "quot";
- return entities;
-}
-
-const insp::flat_map<char, char const*>& ModuleHttpStats::entities = init_entities();
-
MODULE_INIT(ModuleHttpStats)
diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp
index dec07ce73..96aa7ef26 100644
--- a/src/modules/m_ident.cpp
+++ b/src/modules/m_ident.cpp
@@ -24,6 +24,24 @@
#include "inspircd.h"
+enum
+{
+ // Either the ident looup has not started yet or the user is registered.
+ IDENT_UNKNOWN = 0,
+
+ // Ident lookups are not enabled and a user has been marked as being skipped.
+ IDENT_SKIPPED,
+
+ // Ident looups are not enabled and a user has been an insecure ident prefix.
+ IDENT_PREFIXED,
+
+ // An ident lookup was done and an ident was found.
+ IDENT_FOUND,
+
+ // An ident lookup was done but no ident was found
+ IDENT_MISSING
+};
+
/* --------------------------------------------------------------
* Note that this is the third incarnation of m_ident. The first
* two attempts were pretty crashy, mainly due to the fact we tried
@@ -254,12 +272,34 @@ class IdentRequestSocket : public EventHandler
class ModuleIdent : public Module
{
- int RequestTimeout;
- bool NoLookupPrefix;
- SimpleExtItem<IdentRequestSocket, stdalgo::culldeleter> ext;
+ private:
+ unsigned int timeout;
+ bool prefixunqueried;
+ SimpleExtItem<IdentRequestSocket, stdalgo::culldeleter> socket;
+ LocalIntExt state;
+
+ static void PrefixIdent(LocalUser* user)
+ {
+ // Check that they haven't been prefixed already.
+ if (user->ident[0] == '~')
+ return;
+
+ // All invalid usernames are prefixed with a tilde.
+ std::string newident(user->ident);
+ newident.insert(newident.begin(), '~');
+
+ // If the username is too long then truncate it.
+ if (newident.length() > ServerInstance->Config->Limits.IdentMax)
+ newident.erase(ServerInstance->Config->Limits.IdentMax);
+
+ // Apply the new username.
+ user->ChangeIdent(newident);
+ }
+
public:
ModuleIdent()
- : ext("ident_socket", ExtensionItem::EXT_USER, this)
+ : socket("ident_socket", ExtensionItem::EXT_USER, this)
+ , state("ident_state", ExtensionItem::EXT_USER, this)
{
}
@@ -271,18 +311,18 @@ class ModuleIdent : public Module
void ReadConfig(ConfigStatus& status) override
{
ConfigTag* tag = ServerInstance->Config->ConfValue("ident");
- RequestTimeout = tag->getDuration("timeout", 5, 1);
- NoLookupPrefix = tag->getBool("nolookupprefix", false);
+ timeout = tag->getDuration("timeout", 5, 1, 60);
+ prefixunqueried = tag->getBool("prefixunqueried");
}
void OnSetUserIP(LocalUser* user) override
{
- IdentRequestSocket* isock = ext.get(user);
+ IdentRequestSocket* isock = socket.get(user);
if (isock)
{
// If an ident lookup request was in progress then cancel it.
isock->Close();
- ext.unset(user);
+ socket.unset(user);
}
// The ident protocol requires that clients are connecting over a protocol with ports.
@@ -295,14 +335,17 @@ class ModuleIdent : public Module
ConfigTag* tag = user->MyClass->config;
if (!tag->getBool("useident", true))
+ {
+ state.set(user, IDENT_SKIPPED);
return;
+ }
user->WriteNotice("*** Looking up your ident...");
try
{
isock = new IdentRequestSocket(user);
- ext.set(user, isock);
+ socket.set(user, isock);
}
catch (ModuleException &e)
{
@@ -317,22 +360,26 @@ class ModuleIdent : public Module
ModResult OnCheckReady(LocalUser *user) override
{
/* Does user have an ident socket attached at all? */
- IdentRequestSocket *isock = ext.get(user);
+ IdentRequestSocket* isock = socket.get(user);
if (!isock)
{
- if ((NoLookupPrefix) && (user->ident[0] != '~'))
- user->ident.insert(user->ident.begin(), 1, '~');
+ if (prefixunqueried && state.get(user) == IDENT_SKIPPED)
+ {
+ PrefixIdent(user);
+ state.set(user, IDENT_PREFIXED);
+ }
return MOD_RES_PASSTHRU;
}
- time_t compare = isock->age;
- compare += RequestTimeout;
+ time_t compare = isock->age + timeout;
/* Check for timeout of the socket */
if (ServerInstance->Time() >= compare)
{
/* Ident timeout */
- user->WriteNotice("*** Ident request timed out.");
+ state.set(user, IDENT_MISSING);
+ PrefixIdent(user);
+ user->WriteNotice("*** Ident lookup timed out, using " + user->ident + " instead.");
}
else if (!isock->HasResult())
{
@@ -341,29 +388,36 @@ class ModuleIdent : public Module
}
/* wooo, got a result (it will be good, or bad) */
- if (isock->result.empty())
+ else if (isock->result.empty())
{
- user->ident.insert(user->ident.begin(), 1, '~');
+ state.set(user, IDENT_MISSING);
+ PrefixIdent(user);
user->WriteNotice("*** Could not find your ident, using " + user->ident + " instead.");
}
else
{
- user->ident = isock->result;
+ state.set(user, IDENT_FOUND);
+ user->ChangeIdent(isock->result);
user->WriteNotice("*** Found your ident, '" + user->ident + "'");
}
- user->InvalidateCache();
isock->Close();
- ext.unset(user);
+ socket.unset(user);
return MOD_RES_PASSTHRU;
}
ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass) override
{
- if (myclass->config->getBool("requireident") && user->ident[0] == '~')
+ if (myclass->config->getBool("requireident") && state.get(user) != IDENT_FOUND)
return MOD_RES_DENY;
return MOD_RES_PASSTHRU;
}
+
+ void OnUserConnect(LocalUser* user) override
+ {
+ // Clear this as it is no longer necessary.
+ state.unset(user);
+ }
};
MODULE_INIT(ModuleIdent)
diff --git a/src/modules/m_ircv3_sts.cpp b/src/modules/m_ircv3_sts.cpp
index 0a83c6e0b..226bdb3ac 100644
--- a/src/modules/m_ircv3_sts.cpp
+++ b/src/modules/m_ircv3_sts.cpp
@@ -130,7 +130,7 @@ class ModuleIRCv3STS : public Module
for (std::vector<ListenSocket*>::const_iterator iter = ServerInstance->ports.begin(); iter != ServerInstance->ports.end(); ++iter)
{
ListenSocket* ls = *iter;
-
+
// Is this listener on the right port?
unsigned int saport = ls->bind_sa.port();
if (saport != port)
diff --git a/src/modules/m_muteban.cpp b/src/modules/m_muteban.cpp
index 97104f0c5..06b55d2cb 100644
--- a/src/modules/m_muteban.cpp
+++ b/src/modules/m_muteban.cpp
@@ -22,7 +22,16 @@
class ModuleQuietBan : public Module
{
+ private:
+ bool notifyuser;
+
public:
+ void ReadConfig(ConfigStatus& status) override
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("muteban");
+ notifyuser = tag->getBool("notifyuser", true);
+ }
+
Version GetVersion() override
{
return Version("Implements extban +b m: - mute bans",VF_OPTCOMMON|VF_VENDOR);
@@ -36,7 +45,6 @@ class ModuleQuietBan : public Module
Channel* chan = target.Get<Channel>();
if (chan->GetExtBanStatus(user, 'm') == MOD_RES_DENY && chan->GetPrefixValue(user) < VOICE_VALUE)
{
- bool notifyuser = ServerInstance->Config->ConfValue("muteban")->getBool("notifyuser", true);
if (!notifyuser)
{
details.echo_original = true;
diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp
index f277d8f6a..b62b6a01f 100644
--- a/src/modules/m_opermotd.cpp
+++ b/src/modules/m_opermotd.cpp
@@ -36,7 +36,7 @@ class CommandOpermotd : public Command
CmdResult Handle(User* user, const Params& parameters) override
{
- if ((parameters.empty()) || (parameters[0] == ServerInstance->Config->ServerName))
+ if ((parameters.empty()) || (irc::equals(parameters[0], ServerInstance->Config->ServerName)))
ShowOperMOTD(user);
return CMD_SUCCESS;
}
diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp
index 23093ae3c..248b3ec0d 100644
--- a/src/modules/m_rline.cpp
+++ b/src/modules/m_rline.cpp
@@ -190,9 +190,11 @@ class CommandRLine : public Command
}
else
{
- if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "R", user))
+ std::string reason;
+
+ if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "R", reason, user))
{
- ServerInstance->SNO->WriteToSnoMask('x',"%s removed R-line on %s",user->nick.c_str(),parameters[0].c_str());
+ ServerInstance->SNO->WriteToSnoMask('x', "%s removed R-line on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str());
}
else
{
diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp
index 564864b31..45dd37e8c 100644
--- a/src/modules/m_samode.cpp
+++ b/src/modules/m_samode.cpp
@@ -124,8 +124,8 @@ class ModuleSaMode : public Module
void Prioritize() override
{
- Module* disabled = ServerInstance->Modules->Find("m_disabled.so");
- ServerInstance->Modules->SetPriority(this, I_OnRawMode, PRIORITY_BEFORE, disabled);
+ Module* disable = ServerInstance->Modules->Find("m_disable.so");
+ ServerInstance->Modules->SetPriority(this, I_OnRawMode, PRIORITY_BEFORE, disable);
Module *override = ServerInstance->Modules->Find("m_override.so");
ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_BEFORE, override);
diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp
index 17a8669e3..9f9db7f79 100644
--- a/src/modules/m_setname.cpp
+++ b/src/modules/m_setname.cpp
@@ -26,6 +26,7 @@
class CommandSetname : public Command
{
public:
+ bool notifyopers;
CommandSetname(Module* Creator) : Command(Creator,"SETNAME", 1, 1)
{
allow_empty_last_param = false;
@@ -42,7 +43,9 @@ class CommandSetname : public Command
if (user->ChangeRealName(parameters[0]))
{
- ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their real name to '%s'", user->nick.c_str(), parameters[0].c_str());
+ if (notifyopers)
+ ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their real name to '%s'",
+ user->nick.c_str(), parameters[0].c_str());
}
return CMD_SUCCESS;
@@ -59,6 +62,18 @@ class ModuleSetName : public Module
{
}
+ void ReadConfig(ConfigStatus& status) override
+ {
+ ConfigTag* tag = ServerInstance->Config->ConfValue("setname");
+
+ // Whether the module should only be usable by server operators.
+ bool operonly = tag->getBool("operonly");
+ cmd.flags_needed = operonly ? 'o' : 0;
+
+ // Whether a snotice should be sent out when a user changes their real name.
+ cmd.notifyopers = tag->getBool("notifyopers", !operonly);
+ }
+
Version GetVersion() override
{
return Version("Provides support for the SETNAME command", VF_VENDOR);
diff --git a/src/modules/m_showwhois.cpp b/src/modules/m_showwhois.cpp
index 58109a67d..ef300cc53 100644
--- a/src/modules/m_showwhois.cpp
+++ b/src/modules/m_showwhois.cpp
@@ -51,7 +51,7 @@ class WhoisNoticeCmd : public Command
void HandleFast(User* dest, User* src)
{
dest->WriteNotice("*** " + src->nick + " (" + src->ident + "@" +
- src->GetHost(dest->HasPrivPermission("users/auspex")) +
+ src->GetHost(dest->HasPrivPermission("users/auspex")) +
") did a /whois on you");
}
diff --git a/src/modules/m_shun.cpp b/src/modules/m_shun.cpp
index eff3557f0..f3117392f 100644
--- a/src/modules/m_shun.cpp
+++ b/src/modules/m_shun.cpp
@@ -69,13 +69,15 @@ class CommandShun : public Command
if (parameters.size() == 1)
{
- if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SHUN", user))
+ std::string reason;
+
+ if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SHUN", reason, user))
{
- ServerInstance->SNO->WriteToSnoMask('x', "%s removed SHUN on %s", user->nick.c_str(), parameters[0].c_str());
+ ServerInstance->SNO->WriteToSnoMask('x', "%s removed SHUN on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str());
}
- else if (ServerInstance->XLines->DelLine(target.c_str(), "SHUN", user))
+ else if (ServerInstance->XLines->DelLine(target.c_str(), "SHUN", reason, user))
{
- ServerInstance->SNO->WriteToSnoMask('x',"%s removed SHUN on %s", user->nick.c_str(), target.c_str());
+ ServerInstance->SNO->WriteToSnoMask('x', "%s removed SHUN on %s: %s", user->nick.c_str(), target.c_str(), reason.c_str());
}
else
{
diff --git a/src/modules/m_spanningtree/delline.cpp b/src/modules/m_spanningtree/delline.cpp
index c64bec654..e376147fd 100644
--- a/src/modules/m_spanningtree/delline.cpp
+++ b/src/modules/m_spanningtree/delline.cpp
@@ -25,12 +25,13 @@
CmdResult CommandDelLine::Handle(User* user, Params& params)
{
const std::string& setter = user->nick;
+ std::string reason;
// XLineManager::DelLine() returns true if the xline existed, false if it didn't
- if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], user))
+ if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], reason, user))
{
- ServerInstance->SNO->WriteToSnoMask('X',"%s removed %s%s on %s", setter.c_str(),
- params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str());
+ ServerInstance->SNO->WriteToSnoMask('X', "%s removed %s%s on %s: %s", setter.c_str(),
+ params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str(), reason.c_str());
return CMD_SUCCESS;
}
return CMD_FAILURE;
diff --git a/src/modules/m_spanningtree/uid.cpp b/src/modules/m_spanningtree/uid.cpp
index 01af56fa6..0729065fc 100644
--- a/src/modules/m_spanningtree/uid.cpp
+++ b/src/modules/m_spanningtree/uid.cpp
@@ -134,7 +134,7 @@ CmdResult CommandUID::HandleServer(TreeServer* remoteserver, CommandBase::Params
}
CmdResult CommandFHost::HandleRemote(RemoteUser* src, Params& params)
-{
+{
src->ChangeDisplayedHost(params[0]);
return CMD_SUCCESS;
}
diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp
index 2266b6861..7e08c8a3d 100644
--- a/src/modules/m_sslinfo.cpp
+++ b/src/modules/m_sslinfo.cpp
@@ -188,6 +188,11 @@ class ModuleSSLInfo
private:
CommandSSLInfo cmd;
+ bool MatchFP(ssl_cert* const cert, const std::string& fp) const
+ {
+ return irc::spacesepstream(fp).Contains(cert->GetFingerprint());
+ }
+
public:
ModuleSSLInfo()
: WebIRC::EventListener(this)
@@ -231,7 +236,7 @@ class ModuleSSLInfo
}
std::string fingerprint;
- if (ifo->oper_block->readString("fingerprint", fingerprint) && (!cert || cert->GetFingerprint() != fingerprint))
+ if (ifo->oper_block->readString("fingerprint", fingerprint) && (!cert || !MatchFP(cert, fingerprint)))
{
user->WriteNumeric(ERR_NOOPERHOST, "This oper login requires a matching SSL certificate fingerprint.");
user->CommandFloodPenalty += 10000;
@@ -251,7 +256,7 @@ class ModuleSSLInfo
return;
const SSLIOHook* const ssliohook = SSLIOHook::IsSSL(&localuser->eh);
- if (!ssliohook)
+ if (!ssliohook || cmd.sslapi.nosslext.get(localuser))
return;
ssl_cert* const cert = ssliohook->GetCertificate();
@@ -275,7 +280,7 @@ class ModuleSSLInfo
{
OperInfo* ifo = i->second;
std::string fp = ifo->oper_block->getString("fingerprint");
- if (fp == cert->fingerprint && ifo->oper_block->getBool("autologin"))
+ if (MatchFP(cert, fp) && ifo->oper_block->getBool("autologin"))
user->Oper(ifo);
}
}
diff --git a/src/modules/m_svshold.cpp b/src/modules/m_svshold.cpp
index ede845fd8..ca8f30d0b 100644
--- a/src/modules/m_svshold.cpp
+++ b/src/modules/m_svshold.cpp
@@ -112,10 +112,12 @@ class CommandSvshold : public Command
if (parameters.size() == 1)
{
- if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SVSHOLD", user))
+ std::string reason;
+
+ if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "SVSHOLD", reason, user))
{
if (!silent)
- ServerInstance->SNO->WriteToSnoMask('x',"%s removed SVSHOLD on %s",user->nick.c_str(),parameters[0].c_str());
+ ServerInstance->SNO->WriteToSnoMask('x', "%s removed SVSHOLD on %s: %s", user->nick.c_str(), parameters[0].c_str(), reason.c_str());
}
else
{