]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Merge insp20
authorAttila Molnar <attilamolnar@hush.com>
Tue, 21 Jan 2014 17:44:08 +0000 (18:44 +0100)
committerAttila Molnar <attilamolnar@hush.com>
Tue, 21 Jan 2014 17:44:08 +0000 (18:44 +0100)
47 files changed:
1  2 
docs/conf/helpop-full.conf.example
docs/conf/helpop.conf.example
docs/conf/inspircd.conf.example
docs/conf/links.conf.example
docs/conf/modules.conf.example
docs/conf/opers.conf.example
include/configreader.h
include/inspircd.h
modulemanager
src/channels.cpp
src/commands/cmd_commands.cpp
src/commands/cmd_info.cpp
src/commands/cmd_modules.cpp
src/commands/cmd_whois.cpp
src/configparser.cpp
src/inspircd.cpp
src/mode.cpp
src/modules.cpp
src/modules/m_alias.cpp
src/modules/m_callerid.cpp
src/modules/m_channames.cpp
src/modules/m_dccallow.cpp
src/modules/m_dnsbl.cpp
src/modules/m_helpop.cpp
src/modules/m_httpd.cpp
src/modules/m_httpd_stats.cpp
src/modules/m_ident.cpp
src/modules/m_joinflood.cpp
src/modules/m_mlock.cpp
src/modules/m_override.cpp
src/modules/m_permchannels.cpp
src/modules/m_remove.cpp
src/modules/m_ripemd160.cpp
src/modules/m_sajoin.cpp
src/modules/m_sasl.cpp
src/modules/m_services_account.cpp
src/modules/m_showwhois.cpp
src/modules/m_silence.cpp
src/modules/m_spanningtree/main.cpp
src/modules/m_spanningtree/main.h
src/modules/m_spanningtree/svsnick.cpp
src/modules/m_spanningtree/utils.cpp
src/modules/m_svshold.cpp
src/modules/m_uninvite.cpp
src/modules/m_userip.cpp
src/socket.cpp
src/users.cpp

Simple merge
index 5f33b6d88e71d8a4a8b2ca18a1dc52b5fdddeba0,3c23c0af116472e2988444d53e6ae11ec79ac184..6d6a8171977cdde7a184065c4ea0009172e49797
@@@ -34,10 -34,10 +34,10 @@@ PRIVMSG   NOTICE   NICK      JOIN      
  CYCLE     KNOCK    MODE      DEVOICE   TOPIC
  KICK      FPART    REMOVE    TBAN      INVITE
  UNINVITE  AWAY     DCCALLOW  SILENCE   ACCEPT
- MKPASSWD  VHOST    TITLE
+ MKPASSWD  VHOST    TITLE     SETNAME
  
  WHOIS     WHOWAS   ISON      USERHOST  WATCH
 -LIST      NAMES    WHO       MOTD      RULES
 +LIST      NAMES    WHO       MOTD
  ADMIN     MAP      LINKS     LUSERS    TIME
  STATS     VERSION  INFO      MODULES   COMMANDS
  SSLINFO
Simple merge
index b196c5621002b76a6daab6371c6a28132e3e8a60,1b715123dfa704fa61ba9ce6d5537dd47957c81d..5e36689f022205379c5039b5c9b4c1058e16364b
@@@ -29,7 -29,7 +29,7 @@@
  
        # allowmask: Range of IP addresses to allow for this link.
        # Can be a CIDR (see example).
-       allowmask="69.58.44.0/24 127.0.0.0/8"
 -      allowmask="203.0.113.0/24"
++      allowmask="203.0.113.0/24 127.0.0.0/8 2001:db8::/32"
  
        # timeout: If defined, this option defines how long the server
        # will wait to consider the connect attempt failed and try the
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc modulemanager
index 9e4670de87d216c549408fc2131bb69394eed61c,24f4467a44b053727a381f147b4624a531d9281d..86f9ca0c476405eb3e6f5b10ab731c0b8be3d2b1
  use strict;
  use warnings FATAL => qw(all);
  
 -use make::configure;
 +use make::utilities;
  
- if (!module_installed("LWP::Simple"))
- {
-       die "Your system is missing the LWP::Simple Perl module!";
- }
+ BEGIN {
+       unless (module_installed("LWP::Simple")) {
+               die "Your system is missing the LWP::Simple Perl module!";
+       }
+       unless (module_installed("Crypt::SSLeay") || module_installed("IO::Socket::SSL")) {
+               die "Your system is missing the Crypt::SSLeay or IO::Socket::SSL Perl modules!";
+       }
 +
- if (!module_installed("Crypt::SSLeay") && !module_installed("IO::Socket::SSL"))
- {
-       die "Your system is missing the Crypt::SSLeay or IO::Socket::SSL Perl modules!";
  }
  
 +use File::Basename;
  use LWP::Simple;
  
 -our @modlist;
 -
  my %installed;
  # $installed{name} = $version
  
index 563bc27044c204618735dc0cf1bf506a1d95b325,c546e68db0e91180fe4afb1756f8ce143f0b19f6..5865f67245d21a0bbcaa8d17bb355a099a2b23d1
@@@ -654,9 -758,17 +654,10 @@@ const char* Channel::ChanModes(bool sho
   */
  void Channel::UserList(User *user)
  {
-       if (this->IsModeSet(secretmode) && !this->HasUser(user) && !user->HasPrivPermission("channels/auspex"))
 -      char list[MAXBUF];
 -      size_t dlen, curlen;
 -
 -      if (!IS_LOCAL(user))
 -              return;
 -
+       bool has_privs = user->HasPrivPermission("channels/auspex");
 -
 -      if (this->IsModeSet('s') && !this->HasUser(user) && !has_privs)
++      if (this->IsModeSet(secretmode) && !this->HasUser(user) && !has_privs)
        {
 -              user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
 +              user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", this->name.c_str());
                return;
        }
  
        {
                if (i->first->quitting)
                        continue;
-               if ((!has_user) && (i->first->IsModeSet(invisiblemode)))
 -              if ((!has_user) && (i->first->IsModeSet('i')) && (!has_privs))
++              if ((!has_user) && (i->first->IsModeSet(invisiblemode)) && (!has_privs))
                {
                        /*
                         * user is +i, and source not on the channel, does not show
Simple merge
Simple merge
index fe199e7a433259dba318da4bc4e74ccda0a38e09,2a15b43ed841fa675b18cf2c1b186410414dc534..d9fa7d5d5642f60779e3388513b91679e7fdd390
@@@ -51,30 -56,17 +56,30 @@@ class CommandModules : public Comman
   */
  CmdResult CommandModules::Handle (const std::vector<std::string>& parameters, User *user)
  {
 -      if (parameters.size() >= 1 && parameters[0] != ServerInstance->Config->ServerName)
 -              return CMD_SUCCESS;
 +      // Don't ask remote servers about their modules unless the local user asking is an oper
 +      // 2.0 asks anyway, so let's handle that the same way
 +      bool for_us = (parameters.empty() || parameters[0] == ServerInstance->Config->ServerName);
 +      if ((!for_us) || (!IS_LOCAL(user)))
 +      {
 +              if (!user->IsOper())
 +              {
 +                      user->WriteNotice("*** You cannot check what modules other servers have loaded.");
 +                      return CMD_FAILURE;
 +              }
 +
 +              // From an oper and not for us, forward
 +              if (!for_us)
 +                      return CMD_SUCCESS;
 +      }
  
 -      std::vector<std::string> module_names = ServerInstance->Modules->GetAllModuleNames(0);
 +      const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
  
 -      for (unsigned int i = 0; i < module_names.size(); i++)
 +      for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
        {
 -              Module* m = ServerInstance->Modules->Find(module_names[i]);
 +              Module* m = i->second;
                Version V = m->GetVersion();
  
-               if (user->HasPrivPermission("servers/auspex"))
+               if (IS_LOCAL(user) && user->HasPrivPermission("servers/auspex"))
                {
                        std::string flags("SvcC");
                        int pos = 0;
index 7e67676edab33b5fab33bf5de64b9db6fc6c6b24,ba2ad9c1526e1a83b8ad8f2518333f48de66270a..e8a751fa036dc6ade92b4e63feb1b60eb31572a9
@@@ -55,153 -38,11 +55,143 @@@ class CommandWhois : public SplitComman
         * @param user The user issuing the command
         * @return A value from CmdResult to indicate command success or failure.
         */
 -      CmdResult Handle(const std::vector<std::string>& parameters, User *user);
 +      CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user);
 +      CmdResult HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target);
  };
  
-       std::string::size_type start, pos, length;
 +std::string CommandWhois::ChannelList(User* source, User* dest, bool spy)
 +{
 +      std::string list;
 +
 +      for (UCListIter i = dest->chans.begin(); i != dest->chans.end(); i++)
 +      {
 +              Channel* c = *i;
 +              /* If the target is the sender, neither +p nor +s is set, or
 +               * the channel contains the user, it is not a spy channel
 +               */
 +              if (spy != (source == dest || !(c->IsModeSet(privatemode) || c->IsModeSet(secretmode)) || c->HasUser(source)))
 +                      list.append(c->GetPrefixChar(dest)).append(c->name).append(" ");
 +      }
 +
 +      return list;
 +}
 +
 +void CommandWhois::SplitChanList(User* source, User* dest, const std::string& cl)
 +{
 +      std::string line;
 +      std::ostringstream prefix;
-               length = (pos == std::string::npos) ? cl.length() : pos;
-               if (line.length() + namelen + length - start > 510)
++      std::string::size_type start, pos;
 +
 +      prefix << dest->nick << " :";
 +      line = prefix.str();
 +      int namelen = ServerInstance->Config->ServerName.length() + 6;
 +
 +      for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
 +      {
-               if(pos == std::string::npos)
-               {
-                       line.append(cl.substr(start, length - start));
-                       break;
-               }
-               else
-               {
-                       line.append(cl.substr(start, length - start + 1));
-               }
++              if (line.length() + namelen + pos - start > 510)
 +              {
 +                      ServerInstance->SendWhoisLine(source, dest, 319, line);
 +                      line = prefix.str();
 +              }
 +
++              line.append(cl.substr(start, pos - start + 1));
 +      }
 +
 +      if (line.length() != prefix.str().length())
 +      {
 +              ServerInstance->SendWhoisLine(source, dest, 319, line);
 +      }
 +}
 +
 +void CommandWhois::DoWhois(User* user, User* dest, unsigned long signon, unsigned long idle)
 +{
 +      ServerInstance->SendWhoisLine(user, dest, 311, "%s %s %s * :%s", dest->nick.c_str(), dest->ident.c_str(), dest->dhost.c_str(), dest->fullname.c_str());
 +      if (user == dest || user->HasPrivPermission("users/auspex"))
 +      {
 +              ServerInstance->SendWhoisLine(user, dest, 378, "%s :is connecting from %s@%s %s", dest->nick.c_str(), dest->ident.c_str(), dest->host.c_str(), dest->GetIPString().c_str());
 +      }
 +
 +      std::string cl = ChannelList(user, dest, false);
 +      const ServerConfig::OperSpyWhoisState state = user->HasPrivPermission("users/auspex") ? ServerInstance->Config->OperSpyWhois : ServerConfig::SPYWHOIS_NONE;
 +
 +      if (state == ServerConfig::SPYWHOIS_SINGLEMSG)
 +              cl.append(ChannelList(user, dest, true));
 +
 +      SplitChanList(user, dest, cl);
 +
 +      if (state == ServerConfig::SPYWHOIS_SPLITMSG)
 +      {
 +              std::string scl = ChannelList(user, dest, true);
 +              if (scl.length())
 +              {
 +                      ServerInstance->SendWhoisLine(user, dest, 336, "%s :is on private/secret channels:", dest->nick.c_str());
 +                      SplitChanList(user, dest, scl);
 +              }
 +      }
 +      if (user != dest && !ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"))
 +      {
 +              ServerInstance->SendWhoisLine(user, dest, 312, "%s %s :%s", dest->nick.c_str(), ServerInstance->Config->HideWhoisServer.c_str(), ServerInstance->Config->Network.c_str());
 +      }
 +      else
 +      {
 +              ServerInstance->SendWhoisLine(user, dest, 312, "%s %s :%s", dest->nick.c_str(), dest->server->GetName().c_str(), dest->server->GetDesc().c_str());
 +      }
 +
 +      if (dest->IsAway())
 +      {
 +              ServerInstance->SendWhoisLine(user, dest, 301, "%s :%s", dest->nick.c_str(), dest->awaymsg.c_str());
 +      }
 +
 +      if (dest->IsOper())
 +      {
 +              if (ServerInstance->Config->GenericOper)
 +                      ServerInstance->SendWhoisLine(user, dest, 313, "%s :is an IRC operator", dest->nick.c_str());
 +              else
 +                      ServerInstance->SendWhoisLine(user, dest, 313, "%s :is %s %s on %s", dest->nick.c_str(), (strchr("AEIOUaeiou",dest->oper->name[0]) ? "an" : "a"),dest->oper->name.c_str(), ServerInstance->Config->Network.c_str());
 +      }
 +
 +      if (user == dest || user->HasPrivPermission("users/auspex"))
 +      {
 +              if (dest->IsModeSet(snomaskmode))
 +              {
 +                      ServerInstance->SendWhoisLine(user, dest, 379, "%s :is using modes +%s %s", dest->nick.c_str(), dest->FormatModes(), snomaskmode->GetUserParameter(dest).c_str());
 +              }
 +              else
 +              {
 +                      ServerInstance->SendWhoisLine(user, dest, 379, "%s :is using modes +%s", dest->nick.c_str(), dest->FormatModes());
 +              }
 +      }
 +
 +      FOREACH_MOD(OnWhois, (user,dest));
 +
 +      /*
 +       * We only send these if we've been provided them. That is, if hidewhois is turned off, and user is local, or
 +       * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t
 +       */
 +      if ((idle) || (signon))
 +      {
 +              ServerInstance->SendWhoisLine(user, dest, 317, "%s %lu %lu :seconds idle, signon time", dest->nick.c_str(), idle, signon);
 +      }
 +
 +      ServerInstance->SendWhoisLine(user, dest, 318, "%s :End of /WHOIS list.", dest->nick.c_str());
 +}
  
 -CmdResult CommandWhois::Handle (const std::vector<std::string>& parameters, User *user)
 +CmdResult CommandWhois::HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target)
 +{
 +      if (parameters.size() < 2)
 +              return CMD_FAILURE;
 +
 +      User* user = ServerInstance->FindUUID(parameters[0]);
 +      if (!user)
 +              return CMD_FAILURE;
 +
 +      unsigned long idle = ConvToInt(parameters.back());
 +      DoWhois(user, target, target->signon, idle);
 +
 +      return CMD_SUCCESS;
 +}
 +
 +CmdResult CommandWhois::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
  {
        User *dest;
        int userindex = 0;
Simple merge
index 75e9f3699d0966a84aff310ffdafeeae0229c7b9,b201e38c6e6e5c71bf0600f61898fa9a4255670b..fb33f1937cb7f6ff6de11bace05aa239b79fa99e
@@@ -167,10 -255,11 +173,11 @@@ bool InspIRCd::DaemonSeed(
        std::cout << "InspIRCd Process ID: " << con_green << GetCurrentProcessId() << con_reset << std::endl;
        return true;
  #else
-       signal(SIGTERM, InspIRCd::QuickExit);
+       // Do not use QuickExit here: It will exit with status SIGTERM which would break e.g. daemon scripts
+       signal(SIGTERM, VoidSignalHandler);
  
 -      int childpid;
 -      if ((childpid = fork ()) < 0)
 +      int childpid = fork();
 +      if (childpid < 0)
                return false;
        else if (childpid > 0)
        {
@@@ -570,7 -693,7 +577,7 @@@ InspIRCd::InspIRCd(int argc, char** arg
  
                if (!g)
                {
-                       this->Logs->Log("STARTUP", LOG_DEFAULT, "getgrnam() failed (bad user?): %s", strerror(errno));
 -                      this->Logs->Log("SETGUID", DEFAULT, "getgrnam(%s) failed (wrong group?): %s", SetGroup.c_str(), strerror(errno));
++                      this->Logs->Log("STARTUP", LOG_DEFAULT, "getgrnam(%s) failed (wrong group?): %s", SetGroup.c_str(), strerror(errno));
                        this->QuickExit(0);
                }
  
  
                if (ret == -1)
                {
-                       this->Logs->Log("STARTUP", LOG_DEFAULT, "setgid() failed (bad user?): %s", strerror(errno));
 -                      this->Logs->Log("SETGUID", DEFAULT, "setgid() failed (wrong group?): %s", strerror(errno));
++                      this->Logs->Log("STARTUP", LOG_DEFAULT, "setgid() failed (wrong group?): %s", strerror(errno));
                        this->QuickExit(0);
                }
        }
  
                if (!u)
                {
-                       this->Logs->Log("STARTUP", LOG_DEFAULT, "getpwnam() failed (bad user?): %s", strerror(errno));
 -                      this->Logs->Log("SETGUID", DEFAULT, "getpwnam(%s) failed (wrong user?): %s", SetUser.c_str(), strerror(errno));
++                      this->Logs->Log("STARTUP", LOG_DEFAULT, "getpwnam(%s) failed (wrong user?): %s", SetUser.c_str(), strerror(errno));
                        this->QuickExit(0);
                }
  
  
                if (ret == -1)
                {
-                       this->Logs->Log("STARTUP", LOG_DEFAULT, "setuid() failed (bad user?): %s", strerror(errno));
 -                      this->Logs->Log("SETGUID", DEFAULT, "setuid() failed (wrong user?): %s", strerror(errno));
++                      this->Logs->Log("STARTUP", LOG_DEFAULT, "setuid() failed (wrong user?): %s", strerror(errno));
                        this->QuickExit(0);
                }
        }
diff --cc src/mode.cpp
index e0381b6830dcd57f2d66630ef5a0fc965fe1260b,2a32dfac27defefabea4c9c7ec7c46956efcc6f5..ad46e602de1e39390dd3304b785be9266e289c8b
@@@ -197,31 -250,6 +197,36 @@@ void ModeParser::DisplayCurrentModes(Us
        }
  }
  
-       User* target = ServerInstance->FindNick(parameter);
 +PrefixMode::PrefixMode(Module* Creator, const std::string& Name, char ModeLetter)
 +      : ModeHandler(Creator, Name, ModeLetter, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_PREFIX)
 +      , prefix(0), prefixrank(0)
 +{
 +      list = true;
 +      m_paramtype = TR_NICK;
 +}
 +
 +ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding)
 +{
++      User* target;
++      if (IS_LOCAL(source))
++              target = ServerInstance->FindNickOnly(parameter);
++      else
++              target = ServerInstance->FindNick(parameter);
++
 +      if (!target)
 +      {
 +              source->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameter.c_str());
 +              return MODEACTION_DENY;
 +      }
 +
 +      Membership* memb = chan->GetUser(target);
 +      if (!memb)
 +              return MODEACTION_DENY;
 +
 +      parameter = target->nick;
 +      return (memb->SetPrefix(this, adding) ? MODEACTION_ALLOW : MODEACTION_DENY);
 +}
 +
  ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
                std::string &parameter, bool SkipACL)
  {
        return MODEACTION_ALLOW;
  }
  
 -void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
 +void ModeParser::Process(const std::vector<std::string>& parameters, User* user, ModeProcessFlag flags)
  {
-       std::string target = parameters[0];
+       const std::string& target = parameters[0];
        Channel* targetchannel = ServerInstance->FindChan(target);
-       User* targetuser  = ServerInstance->FindNick(target);
+       User* targetuser = NULL;
+       if (!targetchannel)
+       {
+               if (IS_LOCAL(user))
+                       targetuser = ServerInstance->FindNickOnly(target);
+               else
+                       targetuser = ServerInstance->FindNick(target);
+       }
        ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
  
        LastParse.clear();
diff --cc src/modules.cpp
Simple merge
Simple merge
index 3dc932958a97df15f3e8e62c7a6671fc89597e85,09c5c3f244e9040f7491d485d9833af316502405..6f2c6730085560a8715ffc53fdfa09993c76970f
@@@ -154,23 -139,6 +154,28 @@@ public
  
  class CommandAccept : public Command
  {
-       static ACCEPTAction GetTargetAndAction(std::string& tok)
 +      /** Pair: first is the target, second is true to add, false to remove
 +       */
 +      typedef std::pair<User*, bool> ACCEPTAction;
 +
-               User* target = ServerInstance->FindNick(tok);
++      static ACCEPTAction GetTargetAndAction(std::string& tok, User* cmdfrom = NULL)
 +      {
 +              bool remove = (tok[0] == '-');
 +              if ((remove) || (tok[0] == '+'))
 +                      tok.erase(tok.begin());
 +
++              User* target;
++              if (!cmdfrom || !IS_LOCAL(cmdfrom))
++                      target = ServerInstance->FindNick(tok);
++              else
++                      target = ServerInstance->FindNickOnly(tok);
++
 +              if ((!target) || (target->registered != REG_ALL) || (target->quitting) || (IS_SERVER(target)))
 +                      target = NULL;
 +
 +              return std::make_pair(target, !remove);
 +      }
 +
  public:
        CallerIDExtInfo extInfo;
        unsigned int maxaccepts;
                /* Even if callerid mode is not set, we let them manage their ACCEPT list so that if they go +g they can
                 * have a list already setup. */
  
 -              const std::string& tok = parameters[0];
 -
 -              if (tok == "*")
 +              if (parameters[0] == "*")
                {
 -                      if (IS_LOCAL(user))
 -                              ListAccept(user);
 +                      ListAccept(user);
                        return CMD_SUCCESS;
                }
 -              else if (tok[0] == '-')
 -              {
 -                      User* whotoremove;
 -                      if (IS_LOCAL(user))
 -                              whotoremove = ServerInstance->FindNickOnly(tok.substr(1));
 -                      else
 -                              whotoremove = ServerInstance->FindNick(tok.substr(1));
  
 -                      if (whotoremove)
 -                              return (RemoveAccept(user, whotoremove) ? CMD_SUCCESS : CMD_FAILURE);
 -                      else
 -                              return CMD_FAILURE;
 -              }
 -              else
 +              std::string tok = parameters[0];
-               ACCEPTAction action = GetTargetAndAction(tok);
++              ACCEPTAction action = GetTargetAndAction(tok, user);
 +              if (!action.first)
                {
 -                      const std::string target = (tok[0] == '+' ? tok.substr(1) : tok);
 -                      User* whotoadd;
 -                      if (IS_LOCAL(user))
 -                              whotoadd = ServerInstance->FindNickOnly(target);
 -                      else
 -                              whotoadd = ServerInstance->FindNick(target);
 -
 -                      if ((whotoadd) && (whotoadd->registered == REG_ALL) && (!whotoadd->quitting) && (!IS_SERVER(whotoadd)))
 -                              return (AddAccept(user, whotoadd) ? CMD_SUCCESS : CMD_FAILURE);
 -                      else
 -                      {
 -                              user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), tok.c_str());
 -                              return CMD_FAILURE;
 -                      }
 +                      user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", tok.c_str());
 +                      return CMD_FAILURE;
                }
 +
 +              if ((!IS_LOCAL(user)) && (!IS_LOCAL(action.first)))
 +                      // Neither source nor target is local, forward the command to the server of target
 +                      return CMD_SUCCESS;
 +
 +              // The second item in the pair is true if the first char is a '+' (or nothing), false if it's a '-'
 +              if (action.second)
 +                      return (AddAccept(user, action.first) ? CMD_SUCCESS : CMD_FAILURE);
 +              else
 +                      return (RemoveAccept(user, action.first) ? CMD_SUCCESS : CMD_FAILURE);
        }
  
        RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
        {
 -              return ROUTE_BROADCAST;
 +              // There is a list in parameters[0] in two cases:
 +              // Either when the source is remote, this happens because 2.0 servers send comma seperated uuid lists,
 +              // we don't split those but broadcast them, as before.
 +              //
 +              // Or if the source is local then LoopCall() runs OnPostCommand() after each entry in the list,
 +              // meaning the linking module has sent an ACCEPT already for each entry in the list to the
 +              // appropiate server and the ACCEPT with the list of nicks (this) doesn't need to be sent anywhere.
 +              if ((!IS_LOCAL(user)) && (parameters[0].find(',') != std::string::npos))
 +                      return ROUTE_BROADCAST;
 +
 +              // Find the target
 +              std::string targetstring = parameters[0];
-               ACCEPTAction action = GetTargetAndAction(targetstring);
++              ACCEPTAction action = GetTargetAndAction(targetstring, user);
 +              if (!action.first)
 +                      // Target is a "*" or source is local and the target is a list of nicks
 +                      return ROUTE_LOCALONLY;
 +
 +              // Route to the server of the target
 +              return ROUTE_UNICAST(action.first->server);
        }
  
        void ListAccept(User* user)
Simple merge
index 487e4a7ed23fca65038e1d6a473ebe9de56f18ba,db0b54764919b4434e08b95b6fce5eedc73b8f81..7332402bafa1e7566f354b27c1509f3476f65892
@@@ -205,26 -203,30 +205,30 @@@ class CommandDccallow : public Comman
  
        void DisplayHelp(User* user)
        {
 -              user->WriteNumeric(998, "%s :DCCALLOW [<+|->nick [time]] [list] [help]", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :You may allow DCCs from specific users by specifying a", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :DCC allow for the user you want to receive DCCs from.", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :For example, to allow the user Brain to send you inspircd.exe", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :you would type:", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :/DCCALLOW +Brain", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :Brain would then be able to send you files. They would have to", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :resend the file again if the server gave them an error message", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :before you added them to your DCCALLOW list.", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :DCCALLOW entries will be temporary by default, if you want to add", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :them to your DCCALLOW list until you leave IRC, type:", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :/DCCALLOW +Brain 0", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :To remove the user from your DCCALLOW list, type:", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :/DCCALLOW -Brain", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :To see the users in your DCCALLOW list, type:", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :/DCCALLOW LIST", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :NOTE: If the user leaves IRC or changes their nickname", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :  they will be removed from your DCCALLOW list.", user->nick.c_str());
 -              user->WriteNumeric(998, "%s :  your DCCALLOW list will be deleted when you leave IRC.", user->nick.c_str());
 -              user->WriteNumeric(999, "%s :End of DCCALLOW HELP", user->nick.c_str());
 +              user->WriteNumeric(998, ":DCCALLOW [<+|->nick [time]] [list] [help]");
 +              user->WriteNumeric(998, ":You may allow DCCs from specific users by specifying a");
 +              user->WriteNumeric(998, ":DCC allow for the user you want to receive DCCs from.");
 +              user->WriteNumeric(998, ":For example, to allow the user Brain to send you inspircd.exe");
 +              user->WriteNumeric(998, ":you would type:");
 +              user->WriteNumeric(998, ":/DCCALLOW +Brain");
 +              user->WriteNumeric(998, ":Brain would then be able to send you files. They would have to");
 +              user->WriteNumeric(998, ":resend the file again if the server gave them an error message");
 +              user->WriteNumeric(998, ":before you added them to your DCCALLOW list.");
 +              user->WriteNumeric(998, ":DCCALLOW entries will be temporary by default, if you want to add");
 +              user->WriteNumeric(998, ":them to your DCCALLOW list until you leave IRC, type:");
 +              user->WriteNumeric(998, ":/DCCALLOW +Brain 0");
 +              user->WriteNumeric(998, ":To remove the user from your DCCALLOW list, type:");
 +              user->WriteNumeric(998, ":/DCCALLOW -Brain");
 +              user->WriteNumeric(998, ":To see the users in your DCCALLOW list, type:");
 +              user->WriteNumeric(998, ":/DCCALLOW LIST");
 +              user->WriteNumeric(998, ":NOTE: If the user leaves IRC or changes their nickname");
 +              user->WriteNumeric(998, ":  they will be removed from your DCCALLOW list.");
 +              user->WriteNumeric(998, ":  your DCCALLOW list will be deleted when you leave IRC.");
 +              user->WriteNumeric(999, ":End of DCCALLOW HELP");
+               LocalUser* localuser = IS_LOCAL(user);
+               if (localuser)
+                       localuser->CommandFloodPenalty += 4000;
        }
  
        void DisplayDCCAllowList(User* user)
index 10419de5157e59c674adb9afd2543a8c6096e5d2,d4101686a03c1daaba9115da2a8244e2898838d0..6ee1c317ba6155e28e3627203c0589837fd8c880
@@@ -63,141 -65,154 +63,150 @@@ class DNSBLResolver : public DNS::Reque
        {
                /* Check the user still exists */
                LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid);
 -              if (them)
 +              if (!them)
 +                      return;
 +
 +              const DNS::ResourceRecord &ans_record = r->answers[0];
 +
 +              int i = countExt.get(them);
 +              if (i)
 +                      countExt.set(them, i - 1);
 +
 +              // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
 +
 +              unsigned int bitmask = 0, record = 0;
 +              bool match = false;
 +              in_addr resultip;
 +
 +              inet_aton(ans_record.rdata.c_str(), &resultip);
 +
 +              switch (ConfEntry->type)
                {
 -                      int i = countExt.get(them);
 -                      if (i)
 -                              countExt.set(them, i - 1);
 -                      // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
 -                      if(result.length())
 +                      case DNSBLConfEntry::A_BITMASK:
 +                              bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */
 +                              bitmask &= ConfEntry->bitmask;
 +                              match = (bitmask != 0);
 +                      break;
 +                      case DNSBLConfEntry::A_RECORD:
 +                              record = resultip.s_addr >> 24; /* Last octet */
 +                              match = (ConfEntry->records[record] == 1);
 +                      break;
 +              }
 +
 +              if (match)
 +              {
 +                      std::string reason = ConfEntry->reason;
 +                      std::string::size_type x = reason.find("%ip%");
 +                      while (x != std::string::npos)
                        {
 -                              unsigned int bitmask = 0, record = 0;
 -                              bool match = false;
 -                              in_addr resultip;
 +                              reason.erase(x, 4);
 +                              reason.insert(x, them->GetIPString());
 +                              x = reason.find("%ip%");
 +                      }
  
 -                              inet_aton(result.c_str(), &resultip);
 +                      ConfEntry->stats_hits++;
  
 -                              switch (ConfEntry->type)
 +                      switch (ConfEntry->banaction)
 +                      {
 +                              case DNSBLConfEntry::I_KILL:
                                {
 -                                      case DNSBLConfEntry::A_BITMASK:
 -                                              bitmask = resultip.s_addr >> 24; /* Last octet (network byte order) */
 -                                              bitmask &= ConfEntry->bitmask;
 -                                              match = (bitmask != 0);
 -                                      break;
 -                                      case DNSBLConfEntry::A_RECORD:
 -                                              record = resultip.s_addr >> 24; /* Last octet */
 -                                              match = (ConfEntry->records[record] == 1);
 +                                      ServerInstance->Users->QuitUser(them, "Killed (" + reason + ")");
                                        break;
                                }
 -
 -                              if (match)
 +                              case DNSBLConfEntry::I_MARK:
                                {
 -                                      std::string reason = ConfEntry->reason;
 -                                      std::string::size_type x = reason.find("%ip%");
 -                                      while (x != std::string::npos)
 +                                      if (!ConfEntry->ident.empty())
                                        {
 -                                              reason.erase(x, 4);
 -                                              reason.insert(x, them->GetIPString());
 -                                              x = reason.find("%ip%");
 +                                              them->WriteNumeric(304, ":Your ident has been set to " + ConfEntry->ident + " because you matched " + reason);
 +                                              them->ChangeIdent(ConfEntry->ident);
                                        }
  
 -                                      ConfEntry->stats_hits++;
 -
 -                                      switch (ConfEntry->banaction)
 +                                      if (!ConfEntry->host.empty())
                                        {
 -                                              case DNSBLConfEntry::I_KILL:
 -                                              {
 -                                                      ServerInstance->Users->QuitUser(them, "Killed (" + reason + ")");
 -                                                      break;
 -                                              }
 -                                              case DNSBLConfEntry::I_MARK:
 -                                              {
 -                                                      if (!ConfEntry->ident.empty())
 -                                                      {
 -                                                              them->WriteServ("304 " + them->nick + " :Your ident has been set to " + ConfEntry->ident + " because you matched " + reason);
 -                                                              them->ChangeIdent(ConfEntry->ident.c_str());
 -                                                      }
 -
 -                                                      if (!ConfEntry->host.empty())
 -                                                      {
 -                                                              them->WriteServ("304 " + them->nick + " :Your host has been set to " + ConfEntry->host + " because you matched " + reason);
 -                                                              them->ChangeDisplayedHost(ConfEntry->host.c_str());
 -                                                      }
 -
 -                                                      nameExt.set(them, ConfEntry->name);
 -                                                      break;
 -                                              }
 -                                              case DNSBLConfEntry::I_KLINE:
 -                                              {
 -                                                      KLine* kl = new KLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
 -                                                                      "*", them->GetIPString());
 -                                                      if (ServerInstance->XLines->AddLine(kl,NULL))
 -                                                      {
 -                                                              std::string timestr = ServerInstance->TimeString(kl->expiry);
 -                                                              ServerInstance->SNO->WriteGlobalSno('x',"K:line added due to DNSBL match on *@%s to expire on %s: %s",
 -                                                                      them->GetIPString(), timestr.c_str(), reason.c_str());
 -                                                              ServerInstance->XLines->ApplyLines();
 -                                                      }
 -                                                      else
 -                                                      {
 -                                                              delete kl;
 -                                                              return;
 -                                                      }
 -                                                      break;
 -                                              }
 -                                              case DNSBLConfEntry::I_GLINE:
 -                                              {
 -                                                      GLine* gl = new GLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
 -                                                                      "*", them->GetIPString());
 -                                                      if (ServerInstance->XLines->AddLine(gl,NULL))
 -                                                      {
 -                                                              std::string timestr = ServerInstance->TimeString(gl->expiry);
 -                                                              ServerInstance->SNO->WriteGlobalSno('x',"G:line added due to DNSBL match on *@%s to expire on %s: %s",
 -                                                                      them->GetIPString(), timestr.c_str(), reason.c_str());
 -                                                              ServerInstance->XLines->ApplyLines();
 -                                                      }
 -                                                      else
 -                                                      {
 -                                                              delete gl;
 -                                                              return;
 -                                                      }
 -                                                      break;
 -                                              }
 -                                              case DNSBLConfEntry::I_ZLINE:
 -                                              {
 -                                                      ZLine* zl = new ZLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
 -                                                                      them->GetIPString());
 -                                                      if (ServerInstance->XLines->AddLine(zl,NULL))
 -                                                      {
 -                                                              std::string timestr = ServerInstance->TimeString(zl->expiry);
 -                                                              ServerInstance->SNO->WriteGlobalSno('x',"Z:line added due to DNSBL match on *@%s to expire on %s: %s",
 -                                                                      them->GetIPString(), timestr.c_str(), reason.c_str());
 -                                                              ServerInstance->XLines->ApplyLines();
 -                                                      }
 -                                                      else
 -                                                      {
 -                                                              delete zl;
 -                                                              return;
 -                                                      }
 -                                                      break;
 -                                              }
 -                                              case DNSBLConfEntry::I_UNKNOWN:
 -                                              {
 -                                                      break;
 -                                              }
 -                                              break;
 +                                              them->WriteNumeric(304, ":Your host has been set to " + ConfEntry->host + " because you matched " + reason);
 +                                              them->ChangeDisplayedHost(ConfEntry->host);
                                        }
  
 -                                      ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s%s detected as being on a DNS blacklist (%s) with result %d", them->nick.empty() ? "<unknown>" : "", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record);
 +                                      nameExt.set(them, ConfEntry->name);
 +                                      break;
 +                              }
 +                              case DNSBLConfEntry::I_KLINE:
 +                              {
 +                                      KLine* kl = new KLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
 +                                                      "*", them->GetIPString());
 +                                      if (ServerInstance->XLines->AddLine(kl,NULL))
 +                                      {
 +                                              std::string timestr = InspIRCd::TimeString(kl->expiry);
 +                                              ServerInstance->SNO->WriteGlobalSno('x',"K:line added due to DNSBL match on *@%s to expire on %s: %s",
 +                                                      them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
 +                                              ServerInstance->XLines->ApplyLines();
 +                                      }
 +                                      else
++                                      {
 +                                              delete kl;
++                                              return;
++                                      }
 +                                      break;
 +                              }
 +                              case DNSBLConfEntry::I_GLINE:
 +                              {
 +                                      GLine* gl = new GLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
 +                                                      "*", them->GetIPString());
 +                                      if (ServerInstance->XLines->AddLine(gl,NULL))
 +                                      {
 +                                              std::string timestr = InspIRCd::TimeString(gl->expiry);
 +                                              ServerInstance->SNO->WriteGlobalSno('x',"G:line added due to DNSBL match on *@%s to expire on %s: %s",
 +                                                      them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
 +                                              ServerInstance->XLines->ApplyLines();
 +                                      }
 +                                      else
++                                      {
 +                                              delete gl;
++                                              return;
++                                      }
 +                                      break;
 +                              }
 +                              case DNSBLConfEntry::I_ZLINE:
 +                              {
 +                                      ZLine* zl = new ZLine(ServerInstance->Time(), ConfEntry->duration, ServerInstance->Config->ServerName.c_str(), reason.c_str(),
 +                                                      them->GetIPString());
 +                                      if (ServerInstance->XLines->AddLine(zl,NULL))
 +                                      {
 +                                              std::string timestr = InspIRCd::TimeString(zl->expiry);
 +                                              ServerInstance->SNO->WriteGlobalSno('x',"Z:line added due to DNSBL match on *@%s to expire on %s: %s",
 +                                                      them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
 +                                              ServerInstance->XLines->ApplyLines();
 +                                      }
 +                                      else
++                                      {
 +                                              delete zl;
++                                              return;
++                                      }
 +                                      break;
                                }
 -                              else
 -                                      ConfEntry->stats_misses++;
 +                              case DNSBLConfEntry::I_UNKNOWN:
 +                              default:
 +                                      break;
                        }
 -                      else
 -                              ConfEntry->stats_misses++;
 +
 +                      ServerInstance->SNO->WriteGlobalSno('a', "Connecting user %s%s detected as being on a DNS blacklist (%s) with result %d", them->nick.empty() ? "<unknown>" : "", them->GetFullRealHost().c_str(), ConfEntry->domain.c_str(), (ConfEntry->type==DNSBLConfEntry::A_BITMASK) ? bitmask : record);
                }
 +              else
 +                      ConfEntry->stats_misses++;
        }
  
 -      virtual void OnError(ResolverError e, const std::string &errormessage)
 +      void OnError(const DNS::Query *q) CXX11_OVERRIDE
        {
                LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid);
 -              if (them)
 -              {
 -                      int i = countExt.get(them);
 -                      if (i)
 -                              countExt.set(them, i - 1);
 -              }
 -      }
 +              if (!them)
 +                      return;
  
 -      virtual ~DNSBLResolver()
 -      {
 +              int i = countExt.get(them);
 +              if (i)
 +                      countExt.set(them, i - 1);
 +
 +              if (q->error == DNS::ERROR_NO_RECORDS || q->error == DNS::ERROR_DOMAIN_NOT_FOUND)
 +                      ConfEntry->stats_misses++;
        }
  };
  
index 64bdc2400c6410a99d665c24d545c7b1de5f9cb6,4bbe8785e4ef4f7b2f22d059b56f81682eb8d6fe..2fe958a71c2c96fa4c7bc71be7e0741a4c667c48
@@@ -96,7 -98,7 +96,6 @@@ class CommandHelpop : public Comman
  
  class ModuleHelpop : public Module
  {
-               std::string  h_file;
 -      private:
                CommandHelpop cmd;
                Helpop ho;
  
                {
                }
  
 -              void init()
 +              void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
                {
-                       helpop_map.clear();
 -                      ReadConfig();
 -                      ServerInstance->Modules->AddService(ho);
 -                      ServerInstance->Modules->AddService(cmd);
 -                      Implementation eventlist[] = { I_OnRehash, I_OnWhois };
 -                      ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
 -              }
 -
 -              void ReadConfig()
 -              {
 -                      std::map<irc::string, std::string> help;
++                      HelpopMap help;
  
                        ConfigTagList tags = ServerInstance->Config->ConfTags("helpop");
                        for(ConfigIter i = tags.first; i != tags.second; ++i)
                                throw ModuleException("m_helpop: Helpop file is missing important entry 'nohelp'. Please check the example conf.");
                        }
  
+                       helpop_map.swap(help);
                }
  
 -              void OnRehash(User* user)
 -              {
 -                      ReadConfig();
 -              }
 -
 -              void OnWhois(User* src, User* dst)
 +              void OnWhois(User* src, User* dst) CXX11_OVERRIDE
                {
 -                      if (dst->IsModeSet('h'))
 +                      if (dst->IsModeSet(ho))
                        {
 -                              ServerInstance->SendWhoisLine(src, dst, 310, src->nick+" "+dst->nick+" :is available for help.");
 +                              ServerInstance->SendWhoisLine(src, dst, 310, dst->nick+" :is available for help.");
                        }
                }
  
index 5a71f8018e3b6cb82bcde7f6f7812499f5840ce6,a853e12c2f95ecde967375b17145f160f27f3eff..735551dffa3ba6dd184a014fa72200b99560d961
@@@ -66,7 -72,12 +70,12 @@@ class HttpServerSocket : public Buffere
                        GetIOHook()->OnStreamSocketAccept(this, client, server);
        }
  
 -      virtual void OnError(BufferedSocketError)
+       ~HttpServerSocket()
+       {
+               sockets.erase(this);
+       }
 +      void OnError(BufferedSocketError) CXX11_OVERRIDE
        {
                ServerInstance->GlobalCulls.AddItem(this);
        }
        }
  };
  
 +class HTTPdAPIImpl : public HTTPdAPIBase
 +{
 + public:
 +      HTTPdAPIImpl(Module* parent)
 +              : HTTPdAPIBase(parent)
 +      {
 +      }
 +
 +      void SendResponse(HTTPDocumentResponse& resp) CXX11_OVERRIDE
 +      {
 +              claimed = true;
 +              resp.src.sock->Page(resp.document, resp.responsecode, &resp.headers);
 +      }
 +};
 +
  class ModuleHttpServer : public Module
  {
 +      std::vector<HttpServerSocket *> httpsocks;
 +      HTTPdAPIImpl APIImpl;
+       unsigned int timeoutsec;
  
   public:
 +      ModuleHttpServer()
 +              : APIImpl(this)
 +      {
 +      }
  
 -      void init()
 +      void init() CXX11_OVERRIDE
        {
                HttpModule = this;
 -              Implementation eventlist[] = { I_OnAcceptConnection, I_OnBackgroundTimer, I_OnRehash };
 -              ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
 -              OnRehash(NULL);
        }
  
 -      void OnRehash(User* user)
++      void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+       {
+               ConfigTag* tag = ServerInstance->Config->ConfValue("httpd");
+               timeoutsec = tag->getInt("timeout");
+       }
 -      void OnRequest(Request& request)
 -      {
 -              if (strcmp(request.id, "HTTP-DOC") != 0)
 -                      return;
 -              HTTPDocumentResponse& resp = static_cast<HTTPDocumentResponse&>(request);
 -              claimed = true;
 -              resp.src.sock->Page(resp.document, resp.responsecode, &resp.headers);
 -      }
 -
 -      ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server)
 +      ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE
        {
                if (from->bind_tag->getString("type") != "httpd")
                        return MOD_RES_PASSTHRU;
                return MOD_RES_ALLOW;
        }
  
-       ~ModuleHttpServer()
 -      void OnBackgroundTimer(time_t curtime)
++      void OnBackgroundTimer(time_t curtime) CXX11_OVERRIDE
+       {
+               if (!timeoutsec)
+                       return;
+               time_t oldest_allowed = curtime - timeoutsec;
+               for (std::set<HttpServerSocket*>::const_iterator i = sockets.begin(); i != sockets.end(); )
+               {
+                       HttpServerSocket* sock = *i;
+                       ++i;
+                       if (sock->createtime < oldest_allowed)
+                       {
+                               sock->cull();
+                               delete sock;
+                       }
+               }
+       }
 -      CullResult cull()
++      CullResult cull() CXX11_OVERRIDE
        {
-               for (size_t i = 0; i < httpsocks.size(); i++)
+               std::set<HttpServerSocket*> local;
+               local.swap(sockets);
+               for (std::set<HttpServerSocket*>::const_iterator i = local.begin(); i != local.end(); ++i)
                {
-                       httpsocks[i]->cull();
-                       delete httpsocks[i];
+                       HttpServerSocket* sock = *i;
+                       sock->cull();
+                       delete sock;
                }
+               return Module::cull();
        }
  
 -      virtual Version GetVersion()
 +      Version GetVersion() CXX11_OVERRIDE
        {
                return Version("Provides HTTP serving facilities to modules", VF_VENDOR);
        }
Simple merge
index c73e26b16f0fb211451067a19a12e13923d29343,f0ced1db79789ba313711dc97defae384f1dc8b1..1f57fc3e1a8009262309abeba041a9706ca4203a
@@@ -336,8 -360,10 +336,8 @@@ class ModuleIdent : public Modul
                /* wooo, got a result (it will be good, or bad) */
                if (isock->result.empty())
                {
-                       user->ident.insert(0, 1, '~');
+                       user->ident.insert(user->ident.begin(), 1, '~');
 -                      user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead.", user->ident.c_str());
 +                      user->WriteNotice("*** Could not find your ident, using " + user->ident + " instead.");
                }
                else
                {
index 81ad7e1692de7560c2abe8f225debe3f9be107a7,63bcc38a4180c30526814f66ee6396d433b94ae8..edce2b22cb6310236f5fcddb1911a0113f00c761
@@@ -121,15 -169,12 +121,11 @@@ class JoinFlood : public ModeHandle
                }
                else
                {
 -                      if (channel->IsModeSet('j'))
 -                      {
 -                              ext.unset(channel);
 -                              channel->SetModeParam('j', "");
 -                              return MODEACTION_ALLOW;
 -                      }
 +                      if (!channel->IsModeSet(this))
 +                              return MODEACTION_DENY;
 +
-                       joinfloodsettings* f = ext.get(channel);
-                       if (f)
-                       {
-                               ext.unset(channel);
-                               return MODEACTION_ALLOW;
-                       }
++                      ext.unset(channel);
++                      return MODEACTION_ALLOW;
                }
                return MODEACTION_DENY;
        }
Simple merge
index ce9ea17e273ef9fca24455d3c75641174765ac2f,3e42c4f7927885f023bc9b5bf05775b21f8a28a8..346d38b9f32b68518898689746f223e67a148a55
@@@ -30,28 -32,35 +30,42 @@@ class ModuleOverride : public Modul
  {
        bool RequireKey;
        bool NoisyOverride;
 +      ChanModeReference topiclock;
 +      ChanModeReference inviteonly;
 +      ChanModeReference key;
 +      ChanModeReference limit;
  
+       static bool IsOverride(unsigned int userlevel, const std::string& modeline)
+       {
+               for (std::string::const_iterator i = modeline.begin(); i != modeline.end(); ++i)
+               {
+                       ModeHandler* mh = ServerInstance->Modes->FindMode(*i, MODETYPE_CHANNEL);
+                       if (!mh)
+                               continue;
+                       if (mh->GetLevelRequired() > userlevel)
+                               return true;
+               }
+               return false;
+       }
   public:
 +      ModuleOverride()
 +              : topiclock(this, "topiclock")
 +              , inviteonly(this, "inviteonly")
 +              , key(this, "key")
 +              , limit(this, "limit")
 +      {
 +      }
  
 -      void init()
 +      void init() CXX11_OVERRIDE
        {
 -              // read our config options (main config file)
 -              OnRehash(NULL);
                ServerInstance->SNO->EnableSnomask('v', "OVERRIDE");
 -              Implementation eventlist[] = { I_OnRehash, I_OnPreMode, I_On005Numeric, I_OnUserPreJoin, I_OnUserPreKick, I_OnPreTopicChange };
 -              ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
        }
  
 -      void OnRehash(User* user)
 +      void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
        {
 -              // re-read our config options on a rehash
 +              // re-read our config options
                ConfigTag* tag = ServerInstance->Config->ConfValue("override");
                NoisyOverride = tag->getBool("noisy");
                RequireKey = tag->getBool("requirekey");
Simple merge
Simple merge
index 41331543acee35a5a4962c6ca78c90039ad6a7d1,04c27e83d181bfe38003000da054cbef7eefbbbe..261cd1e27ede6925ac7dd3e77cdc54eb6ec4ed60
@@@ -402,8 -417,8 +405,7 @@@ class RIProv : public HashProvide
  
        byte *RMD(byte *message, dword length, unsigned int* key)
        {
 -              ServerInstance->Logs->Log("m_ripemd160", DEBUG, "RMD: '%s' length=%u", (const char*)message, length);
                dword         MDbuf[RMDsize/32];   /* contains (A, B, C, D(E))   */
-               static byte   hashcode[RMDsize/8]; /* for final hash-value         */
                dword         X[16];               /* current 16-word chunk        */
                unsigned int  i;                   /* counter                      */
                dword         nbytes;              /* # of bytes not yet processed */
index eda58ef96e1db9548cc825f7941430045386cbae,7ac46573224f8eb9aa1e6f9edd7bc08e4060b6f5..0748c013b96344c698f60f42203b9cf101cb32ee
@@@ -50,18 -52,27 +50,18 @@@ class CommandSajoin : public Comman
                                return CMD_FAILURE;
                        }
  
 -                      /* For local users, we send the JoinUser which may create a channel and set its TS.
 +                      /* For local users, we call Channel::JoinUser which may create a channel and set its TS.
                         * For non-local users, we just return CMD_SUCCESS, knowing this will propagate it where it needs to be
 -                       * and then that server will generate the users JOIN or FJOIN instead.
 +                       * and then that server will handle the command.
                         */
 -                      if (IS_LOCAL(dest))
 +                      LocalUser* localuser = IS_LOCAL(dest);
 +                      if (localuser)
                        {
 -                              Channel::JoinUser(dest, parameters[1].c_str(), true, "", false, ServerInstance->Time());
 -                              /* Fix for dotslasher and w00t - if the join didnt succeed, return CMD_FAILURE so that it doesnt propagate */
 -                              Channel* n = ServerInstance->FindChan(parameters[1]);
 -                              if (n)
 +                              Channel* n = Channel::JoinUser(localuser, parameters[1], true);
 +                              if (n && n->HasUser(dest))
                                {
-                                       ServerInstance->SNO->WriteToSnoMask('a', user->nick+" used SAJOIN to make "+dest->nick+" join "+parameters[1]);
 -                                      if (n->HasUser(dest))
 -                                      {
 -                                              ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAJOIN to make "+dest->nick+" join "+parameters[1]);
 -                                              return CMD_SUCCESS;
 -                                      }
 -                                      else
 -                                      {
 -                                              user->WriteServ("NOTICE "+user->nick+" :*** Could not join "+dest->nick+" to "+parameters[1]+" (User is probably banned, or blocking modes)");
 -                                              return CMD_FAILURE;
 -                                      }
++                                      ServerInstance->SNO->WriteGlobalSno('a', user->nick+" used SAJOIN to make "+dest->nick+" join "+parameters[1]);
 +                                      return CMD_SUCCESS;
                                }
                                else
                                {
index 1d67f0c025040bd428a39244759c4b5e5e9c2a44,66efcfe4ee1a5f0918caa4e8de511a4a6d659f6b..796d343ea6fa9fe1b5e69adff540e6d18c142a4d
@@@ -105,6 -106,10 +104,10 @@@ class SaslAuthenticato
                                this->state = SASL_DONE;
                                this->result = this->GetSaslResult(msg[3]);
                        }
 -                              ServerInstance->Logs->Log("m_sasl", DEFAULT, "Services sent an unknown SASL message \"%s\" \"%s\"", msg[2].c_str(), msg[3].c_str());
+                       else if (msg[2] == "M")
+                               this->user->WriteNumeric(908, "%s %s :are available SASL mechanisms", this->user->nick.c_str(), msg[3].c_str());
+                       else
++                              ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Services sent an unknown SASL message \"%s\" \"%s\"", msg[2].c_str(), msg[3].c_str());
  
                        break;
                 case SASL_DONE:
index 5f288424ca685bc0c008452b404b0f695ce694f1,154968e9ec274b38ca22bd9820d47aaa8d61f6d0..8ab9c9a3ba37a79e7933e7e5e4b235672013ad85
@@@ -102,56 -104,54 +102,86 @@@ class AChannel_M : public SimpleChannel
        AChannel_M(Module* Creator) : SimpleChannelModeHandler(Creator, "regmoderated", 'M') { }
  };
  
 -class ModuleServicesAccount : public Module
++static bool ReadCGIIRCExt(const char* extname, User* user, const std::string*& out)
+ {
 -      AChannel_R m1;
 -      AChannel_M m2;
 -      AUser_R m3;
 -      Channel_r m4;
 -      User_r m5;
 -      AccountExtItem accountname;
 -      bool checking_ban;
++      ExtensionItem* wiext = ServerInstance->Extensions.GetItem(extname);
++      if (!wiext)
++              return false;
 -      static bool ReadCGIIRCExt(const char* extname, User* user, const std::string*& out)
 -      {
 -              ExtensionItem* wiext = ServerInstance->Extensions.GetItem(extname);
 -              if (!wiext)
 -                      return false;
 -
 -              if (wiext->creator->ModuleSourceFile != "m_cgiirc.so")
 -                      return false;
++      if (wiext->creator->ModuleSourceFile != "m_cgiirc.so")
++              return false;
 -              StringExtItem* stringext = static_cast<StringExtItem*>(wiext);
 -              std::string* addr = stringext->get(user);
 -              if (!addr)
 -                      return false;
++      StringExtItem* stringext = static_cast<StringExtItem*>(wiext);
++      std::string* addr = stringext->get(user);
++      if (!addr)
++              return false;
 -              out = addr;
 -              return true;
 -      }
++      out = addr;
++      return true;
++}
 +class AccountExtItemImpl : public AccountExtItem
 +{
   public:
 -      ModuleServicesAccount() : m1(this), m2(this), m3(this), m4(this), m5(this),
 -              accountname("accountname", this), checking_ban(false)
 +      AccountExtItemImpl(Module* mod)
 +              : AccountExtItem("accountname", mod)
        {
        }
  
 -      void init()
 +      void unserialize(SerializeFormat format, Extensible* container, const std::string& value)
        {
 -              ServiceProvider* providerlist[] = { &m1, &m2, &m3, &m4, &m5, &accountname };
 -              ServerInstance->Modules->AddServices(providerlist, sizeof(providerlist)/sizeof(ServiceProvider*));
 -              Implementation eventlist[] = { I_OnWhois, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreJoin, I_OnCheckBan,
 -                      I_OnDecodeMetaData, I_On005Numeric, I_OnUserPostNick, I_OnSetConnectClass };
 +              User* user = dynamic_cast<User*>(container);
 +              if (!user)
 +                      return;
 +
 +              StringExtItem::unserialize(format, container, value);
 +              if (!value.empty())
 +              {
 +                      // Logged in
 +                      if (IS_LOCAL(user))
-                               user->WriteNumeric(900, "%s %s :You are now logged in as %s",
-                                       user->GetFullHost().c_str(), value.c_str(), value.c_str());
++                      {
++                              const std::string* host = &user->dhost;
++                              if (user->registered != REG_ALL)
++                              {
++                                      if (!ReadCGIIRCExt("cgiirc_webirc_hostname", user, host))
++                                      {
++                                              ReadCGIIRCExt("cgiirc_webirc_ip", user, host);
++                                      }
++                              }
 -              ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
++                              user->WriteNumeric(900, "%s!%s@%s %s :You are now logged in as %s",
++                                      user->nick.c_str(), user->ident.c_str(), host->c_str(), value.c_str(), value.c_str());
++                      }
 +
 +                      AccountEvent(creator, user, value).Send();
 +              }
 +              else
 +              {
 +                      // Logged out
 +                      AccountEvent(creator, user, "").Send();
 +              }
        }
 +};
  
 -      void On005Numeric(std::string &t)
 +class ModuleServicesAccount : public Module
 +{
 +      AChannel_R m1;
 +      AChannel_M m2;
 +      AUser_R m3;
 +      Channel_r m4;
 +      User_r m5;
 +      AccountExtItemImpl accountname;
++      bool checking_ban;
 + public:
 +      ModuleServicesAccount() : m1(this), m2(this), m3(this), m4(this), m5(this),
 +              accountname(this)
 +      {
 +      }
 +
 +      void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
        {
 -              ServerInstance->AddExtBanChar('R');
 -              ServerInstance->AddExtBanChar('U');
 +              tokens["EXTBAN"].push_back('R');
 +              tokens["EXTBAN"].push_back('U');
        }
  
        /* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */
                return MOD_RES_PASSTHRU;
        }
  
 -      ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask)
 +      ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask) CXX11_OVERRIDE
        {
-               static bool checking = false;
-               if (checking)
+               if (checking_ban)
                        return MOD_RES_PASSTHRU;
  
                if ((mask.length() > 2) && (mask[1] == ':'))
Simple merge
index fe741862131f4d90c75e853e63975917c6966023,c82ab3f9d6052ecf7c21f571bdfee029291b119a..3a213c6e7c2e0b2c43d8526a75f3137d04736767
@@@ -299,9 -302,20 +299,9 @@@ class ModuleSilence : public Modul
        {
        }
  
 -      void init()
 -      {
 -              OnRehash(NULL);
 -              ServerInstance->Modules->AddService(cmdsilence);
 -              ServerInstance->Modules->AddService(cmdsvssilence);
 -              ServerInstance->Modules->AddService(cmdsilence.ext);
 -
 -              Implementation eventlist[] = { I_OnRehash, I_On005Numeric, I_OnUserPreNotice, I_OnUserPreMessage, I_OnUserPreInvite };
 -              ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
 -      }
 -
 -      void OnRehash(User* user)
 +      void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
        {
-               maxsilence = ServerInstance->Config->ConfValue("showwhois")->getInt("maxentries", 32);
+               maxsilence = ServerInstance->Config->ConfValue("silence")->getInt("maxentries", 32);
                if (!maxsilence)
                        maxsilence = 32;
        }
index 9a7cddec3ce6e395ef48625641ac23dd77d67ea6,d702ab4a25c9d93e497a5283c945de4c5dc3cc85..671e102691af8a0bd7a3f3762cd135a4acf7fad7
  #include "protocolinterface.h"
  
  ModuleSpanningTree::ModuleSpanningTree()
 -      : KeepNickTS(false)
 +      : rconnect(this), rsquit(this), map(this)
 +      , commands(NULL), DNS(this, "DNS")
++      , KeepNickTS(false)
  {
 -      Utils = new SpanningTreeUtilities(this);
 -      commands = new SpanningTreeCommands(this);
 -      RefreshTimer = NULL;
  }
  
  SpanningTreeCommands::SpanningTreeCommands(ModuleSpanningTree* module)
@@@ -529,7 -645,9 +530,7 @@@ void ModuleSpanningTree::OnChangeName(U
        if (user->registered != REG_ALL || !IS_LOCAL(user))
                return;
  
-       CmdBuilder(user, "FNAME").push(gecos).Broadcast();
 -      parameterlist params;
 -      params.push_back(":" + gecos);
 -      Utils->DoOneToMany(user->uuid,"FNAME",params);
++      CmdBuilder(user, "FNAME").push_last(gecos).Broadcast();
  }
  
  void ModuleSpanningTree::OnChangeIdent(User* user, const std::string &ident)
@@@ -591,7 -709,8 +592,8 @@@ void ModuleSpanningTree::OnUserPostNick
                        user->age = ServerInstance->Time();
  
                params.push_back(ConvToStr(user->age));
 -              Utils->DoOneToMany(user->uuid,"NICK",params);
 +              params.Broadcast();
+               this->KeepNickTS = false;
        }
        else if (!loopCall && user->nick == user->uuid)
        {
index 513e86a2f2b97967a5f4cc9657b61ad3a0083c71,eb17c4195fe8bc6b42823202d9ed891da5792ca5..12667aebf0b4d494508eb0e618766168ac583937
@@@ -73,10 -63,11 +73,15 @@@ class ModuleSpanningTree : public Modul
         */
        bool loopCall;
  
 +      /** True if users are quitting due to a netsplit
 +       */
 +      bool SplitInProgress;
 +
+       /** If true OnUserPostNick() won't update the nick TS before sending the NICK,
+        * used when handling SVSNICK.
+        */
+       bool KeepNickTS;
        /** Constructor
         */
        ModuleSpanningTree();
index a504afbd7b25faacf61c9c49fda3f071c0dbca4e,59973202ddc06cc52a73a214648eeeaae45986dc..b3480eb55404bcc726c3187ce81f18bab7f9eeb0
  
  #include "inspircd.h"
  
 -#include "utils.h"
+ #include "main.h"
  #include "commands.h"
  
 -CmdResult CommandSVSNick::Handle(const std::vector<std::string>& parameters, User *user)
 +CmdResult CommandSVSNick::Handle(User* user, std::vector<std::string>& parameters)
  {
        User* u = ServerInstance->FindNick(parameters[0]);
  
                if (isdigit(nick[0]))
                        nick = u->uuid;
  
 -              if (!u->ForceNickChange(nick.c_str()))
+               // Don't update the TS if the nick is exactly the same
+               if (u->nick == nick)
+                       return CMD_FAILURE;
+               time_t NickTS = ConvToInt(parameters[2]);
+               if (NickTS <= 0)
+                       return CMD_FAILURE;
+               ModuleSpanningTree* st = (ModuleSpanningTree*)(Module*)creator;
+               st->KeepNickTS = true;
+               u->age = NickTS;
 +              if (!u->ForceNickChange(nick))
                {
                        /* buh. UID them */
 -                      if (!u->ForceNickChange(u->uuid.c_str()))
 +                      if (!u->ForceNickChange(u->uuid))
                        {
                                ServerInstance->Users->QuitUser(u, "Nickname collision");
-                               return CMD_SUCCESS;
                        }
                }
  
Simple merge
index b1b454e63d99547004daec9ffd1d67b205bd79a4,e666b0fe24b977c1de8f5845e03c9152e01e12cc..c821f63bb3e744e3d5cf5de24da0e46a484dff31
  #include "inspircd.h"
  #include "xline.h"
  
 -/* $ModDesc: Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services. */
 -
+ namespace
+ {
+       bool silent;
+ }
  /** Holds a SVSHold item
   */
  class SVSHold : public XLine
@@@ -45,12 -56,23 +50,21 @@@ public
  
        bool Matches(const std::string &s)
        {
 -              if (nickname == s)
 -                      return true;
 -              return false;
 +              return InspIRCd::Match(s, nickname);
        }
  
 -                      ServerInstance->SNO->WriteToSnoMask('x',"Removing expired SVSHOLD %s (set by %s %ld seconds ago)",
 -                              this->nickname.c_str(), this->source.c_str(), (long int)(ServerInstance->Time() - this->set_time));
+       void DisplayExpiry()
+       {
+               if (!silent)
+               {
 -      const char* Displayable()
++                      ServerInstance->SNO->WriteToSnoMask('x', "Removing expired SVSHOLD %s (set by %s %ld seconds ago)",
++                              nickname.c_str(), source.c_str(), (long)(ServerInstance->Time() - set_time));
+               }
+       }
 +      const std::string& Displayable()
        {
 -              return nickname.c_str();
 +              return nickname;
        }
  };
  
@@@ -154,12 -182,22 +172,18 @@@ class ModuleSVSHold : public Modul
        {
        }
  
 -      void init()
 +      void init() CXX11_OVERRIDE
        {
                ServerInstance->XLines->RegisterFactory(&s);
 -              ServerInstance->Modules->AddService(cmd);
 -              Implementation eventlist[] = { I_OnUserPreNick, I_OnStats, I_OnRehash };
 -              ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
 -              OnRehash(NULL);
        }
  
 -      void OnRehash(User* user)
++      void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+       {
+               ConfigTag* tag = ServerInstance->Config->ConfValue("svshold");
+               silent = tag->getBool("silent");
+       }
 -      virtual ModResult OnStats(char symbol, User* user, string_list &out)
 +      ModResult OnStats(char symbol, User* user, string_list &out) CXX11_OVERRIDE
        {
                if(symbol != 'S')
                        return MOD_RES_PASSTHRU;
Simple merge
Simple merge
diff --cc src/socket.cpp
Simple merge
diff --cc src/users.cpp
index eff72033d021e9c2af29920748c7ce512630734d,573d4db904c40e48007506a5ef84044f5f26075a..dab3aad6c402f5993e397c2e462905935f5031b5
@@@ -760,11 -977,11 +760,11 @@@ const std::string& User::GetIPString(
        {
                irc::sockets::satoap(client_sa, cachedip, port);
                /* IP addresses starting with a : on irc are a Bad Thing (tm) */
 -              if (cachedip.c_str()[0] == ':')
 +              if (cachedip[0] == ':')
-                       cachedip.insert(0,1,'0');
+                       cachedip.insert(cachedip.begin(),1,'0');
        }
  
 -      return cachedip.c_str();
 +      return cachedip;
  }
  
  irc::sockets::cidr_mask User::GetCIDRMask()