]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Merge pull request #235 from attilamolnar/insp20+invitefix
authorAttila Molnar <attilamolnar@hush.com>
Wed, 27 Jun 2012 23:29:21 +0000 (16:29 -0700)
committerAttila Molnar <attilamolnar@hush.com>
Wed, 27 Jun 2012 23:29:21 +0000 (16:29 -0700)
src/configparser.cpp
src/modules/m_cap.cpp
src/modules/m_cap.h
src/modules/m_cban.cpp
src/modules/m_chanhistory.cpp
src/modules/m_rline.cpp
src/modules/m_shun.cpp
src/modules/m_svshold.cpp

index 51d67b4f5be84357d9cb89bde65a1498a6a459b7..a8e36f6e0048c1c1c2a91a719ee81d575dcccbcb 100644 (file)
@@ -317,9 +317,13 @@ void ParseStack::DoReadFile(const std::string& key, const std::string& name, int
        char linebuf[MAXBUF*10];
        while (fgets(linebuf, sizeof(linebuf), file))
        {
-               int len = strlen(linebuf);
+               size_t len = strlen(linebuf);
                if (len)
+               {
+                       if (linebuf[len-1] == '\n')
+                               len--;
                        cache.push_back(std::string(linebuf, len));
+               }
        }
 }
 
index 36674b9c5a41c41f5f88629e65d3a2cadcaca470..662e128a4aa18c385ef2ef1e182bc07a355dd341 100644 (file)
@@ -55,19 +55,14 @@ class CommandCAP : public Command
 
                if (subcommand == "REQ")
                {
-                       CapEvent Data(creator, "cap_req");
-
-                       Data.type = subcommand;
-                       Data.user = user;
-                       Data.creator = this->creator;
-
                        if (parameters.size() < 2)
                                return CMD_FAILURE;
 
+                       CapEvent Data(creator, user, CapEvent::CAPEVENT_REQ);
+
                        // tokenize the input into a nice list of requested caps
-                       std::string param = parameters[1];
                        std::string cap_;
-                       irc::spacesepstream cap_stream(param);
+                       irc::spacesepstream cap_stream(parameters[1]);
 
                        while (cap_stream.GetToken(cap_))
                        {
@@ -95,11 +90,7 @@ class CommandCAP : public Command
                }
                else if ((subcommand == "LS") || (subcommand == "LIST"))
                {
-                       CapEvent Data(creator, subcommand == "LS" ? "cap_ls" : "cap_list");
-
-                       Data.type = subcommand;
-                       Data.user = user;
-                       Data.creator = this->creator;
+                       CapEvent Data(creator, user, subcommand == "LS" ? CapEvent::CAPEVENT_LS : CapEvent::CAPEVENT_LIST);
 
                        reghold.set(user, 1);
                        Data.Send();
@@ -107,31 +98,28 @@ class CommandCAP : public Command
                        std::string Result;
                        if (Data.wanted.size() > 0)
                                Result = irc::stringjoiner(" ", Data.wanted, 0, Data.wanted.size() - 1).GetJoined();
-                       else
-                               Result = "";
 
                        user->WriteServ("CAP %s %s :%s", user->nick.c_str(), subcommand.c_str(), Result.c_str());
                }
                else if (subcommand == "CLEAR")
                {
-                       CapEvent Data(creator, "cap_clear");
-
-                       Data.type = subcommand;
-                       Data.user = user;
-                       Data.creator = this->creator;
+                       CapEvent Data(creator, user, CapEvent::CAPEVENT_CLEAR);
 
                        reghold.set(user, 1);
                        Data.Send();
 
-                       std::string Result = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
+                       std::string Result;
+                       if (!Data.ack.empty())
+                               Result = irc::stringjoiner(" ", Data.ack, 0, Data.ack.size() - 1).GetJoined();
                        user->WriteServ("CAP %s ACK :%s", user->nick.c_str(), Result.c_str());
                }
                else
                {
                        user->WriteNumeric(ERR_INVALIDCAPSUBCOMMAND, "%s %s :Invalid CAP subcommand", user->nick.c_str(), subcommand.c_str());
+                       return CMD_FAILURE;
                }
 
-               return CMD_FAILURE;
+               return CMD_SUCCESS;
        }
 };
 
index 604fdb0efcd6dd2e5e845b2d5a9c806f2a40a8bc..ce7e7f3943c9611954aa94a0776e034a0b3f3a65 100644 (file)
 #ifndef M_CAP_H
 #define M_CAP_H
 
-#include <map>
-#include <string>
-
 class CapEvent : public Event
 {
  public:
-       irc::string type;
+       enum CapEventType
+       {
+               CAPEVENT_REQ,
+               CAPEVENT_LS,
+               CAPEVENT_LIST,
+               CAPEVENT_CLEAR
+       };
+
+       CapEventType type;
        std::vector<std::string> wanted;
        std::vector<std::string> ack;
        User* user;
-       Module* creator;
-       CapEvent(Module* sender, const std::string& t) : Event(sender, t) {}
+       CapEvent(Module* sender, User* u, CapEventType capevtype) : Event(sender, "cap_request"), type(capevtype), user(u) {}
 };
 
 class GenericCap
@@ -47,28 +51,37 @@ class GenericCap
 
        void HandleEvent(Event& ev)
        {
+               if (ev.id != "cap_request")
+                       return;
+
                CapEvent *data = static_cast<CapEvent*>(&ev);
-               if (ev.id == "cap_req")
+               if (data->type == CapEvent::CAPEVENT_REQ)
                {
-                       std::vector<std::string>::iterator it;
-                       if ((it = std::find(data->wanted.begin(), data->wanted.end(), cap)) != data->wanted.end())
+                       for (std::vector<std::string>::iterator it = data->wanted.begin(); it != data->wanted.end(); ++it)
                        {
-                               // we can handle this, so ACK it, and remove it from the wanted list
-                               data->ack.push_back(*it);
-                               data->wanted.erase(it);
-                               ext.set(data->user, 1);
+                               if (it->empty())
+                                       continue;
+                               bool enablecap = ((*it)[0] != '-');
+                               if (((enablecap) && (*it == cap)) || (*it == "-" + cap))
+                               {
+                                       // we can handle this, so ACK it, and remove it from the wanted list
+                                       data->ack.push_back(*it);
+                                       data->wanted.erase(it);
+                                       ext.set(data->user, enablecap ? 1 : 0);
+                                       break;
+                               }
                        }
                }
-               else if (ev.id == "cap_ls")
+               else if (data->type == CapEvent::CAPEVENT_LS)
                {
                        data->wanted.push_back(cap);
                }
-               else if (ev.id == "cap_list")
+               else if (data->type == CapEvent::CAPEVENT_LIST)
                {
                        if (ext.get(data->user))
                                data->wanted.push_back(cap);
                }
-               else if (ev.id == "cap_clear")
+               else if (data->type == CapEvent::CAPEVENT_CLEAR)
                {
                        data->ack.push_back("-" + cap);
                        ext.set(data->user, 0);
index 93a3d5b5a52aace04b7c379b9a7ebb395a04be4b..92f97158ecf123758a39f992d41293d2eed2ccc0 100644 (file)
@@ -74,7 +74,7 @@ class CBanFactory : public XLineFactory
  public:
        CBanFactory() : XLineFactory("CBAN") { }
 
-       /** Generate a shun
+       /** Generate a CBAN
        */
        XLine* Generate(time_t set_time, long duration, std::string source, std::string reason, std::string xline_specific_mask)
        {
@@ -112,56 +112,41 @@ class CommandCBan : public Command
                        else
                        {
                                user->WriteServ("NOTICE %s :*** CBan %s not found in list, try /stats C.",user->nick.c_str(),parameters[0].c_str());
+                               return CMD_FAILURE;
                        }
-
-                       return CMD_SUCCESS;
                }
-               else if (parameters.size() >= 2)
+               else
                {
                        // Adding - XXX todo make this respect <insane> tag perhaps..
                        long duration = ServerInstance->Duration(parameters[1]);
-                       CBan *r = NULL;
                        const char *reason = (parameters.size() > 2) ? parameters[2].c_str() : "No reason supplied";
+                       CBan* r = new CBan(ServerInstance->Time(), duration, user->nick.c_str(), reason, parameters[0].c_str());
 
-                       try
-                       {
-                               r = new CBan(ServerInstance->Time(), duration, user->nick.c_str(), reason, parameters[0].c_str());
-                       }
-                       catch (...)
-                       {
-                               ; // Do nothing. If we get here, the regex was fucked up, and they already got told it fucked up.
-                       }
-
-                       if (r)
+                       if (ServerInstance->XLines->AddLine(r, user))
                        {
-                               if (ServerInstance->XLines->AddLine(r, user))
+                               if (!duration)
                                {
-                                       if (!duration)
-                                       {
-                                               ServerInstance->SNO->WriteGlobalSno('x', "%s added permanent CBan for %s: %s", user->nick.c_str(), parameters[0].c_str(), reason);
-                                       }
-                                       else
-                                       {
-                                               time_t c_requires_crap = duration + ServerInstance->Time();
-                                               ServerInstance->SNO->WriteGlobalSno('x', "%s added timed CBan for %s, expires on %s: %s", user->nick.c_str(), parameters[0].c_str(), ServerInstance->TimeString(c_requires_crap).c_str(), reason);
-                                       }
-
-                                       ServerInstance->XLines->ApplyLines();
+                                       ServerInstance->SNO->WriteGlobalSno('x', "%s added permanent CBan for %s: %s", user->nick.c_str(), parameters[0].c_str(), reason);
                                }
                                else
                                {
-                                       delete r;
-                                       user->WriteServ("NOTICE %s :*** CBan for %s already exists", user->nick.c_str(), parameters[0].c_str());
+                                       time_t c_requires_crap = duration + ServerInstance->Time();
+                                       ServerInstance->SNO->WriteGlobalSno('x', "%s added timed CBan for %s, expires on %s: %s", user->nick.c_str(), parameters[0].c_str(), ServerInstance->TimeString(c_requires_crap).c_str(), reason);
                                }
                        }
+                       else
+                       {
+                               delete r;
+                               user->WriteServ("NOTICE %s :*** CBan for %s already exists", user->nick.c_str(), parameters[0].c_str());
+                               return CMD_FAILURE;
+                       }
                }
-
-               return CMD_FAILURE;
+               return CMD_SUCCESS;
        }
 
        RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
        {
-               return ROUTE_BROADCAST;
+               return ROUTE_LOCALONLY;
        }
 };
 
@@ -203,9 +188,8 @@ class ModuleCBan : public Module
                {
                        // Channel is banned.
                        user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick.c_str(), cname, rl->reason.c_str());
-                       ServerInstance->SNO->WriteToSnoMask('a', "%s tried to join %s which is CBANed (%s)",
+                       ServerInstance->SNO->WriteGlobalSno('a', "%s tried to join %s which is CBANed (%s)",
                                 user->nick.c_str(), cname, rl->reason.c_str());
-                       ServerInstance->PI->SendSNONotice("A", user->nick + " tried to join " + std::string(cname) + " which is CBANed (" + rl->reason + ")");
                        return MOD_RES_DENY;
                }
 
index 9275152ea505dbba9368130cede3516697197e1a..482d526ebc3e05d9e413c4521617733a8bfc4c87 100644 (file)
@@ -37,9 +37,23 @@ struct HistoryList
 
 class HistoryMode : public ModeHandler
 {
+       bool IsValidDuration(const std::string duration)
+       {
+               for (std::string::const_iterator i = duration.begin(); i != duration.end(); ++i)
+               {
+                       unsigned char c = *i;
+                       if (((c >= '0') && (c <= '9')) || (c == 's') || (c != 'S'))
+                               continue;
+
+                       if (duration_multi[c] == 1)
+                               return false;
+               }
+               return true;
+       }
+
  public:
        SimpleExtItem<HistoryList> ext;
-       int maxlines;
+       unsigned int maxlines;
        HistoryMode(Module* Creator) : ModeHandler(Creator, "history", 'H', PARAM_SETONLY, MODETYPE_CHANNEL),
                ext("history", Creator) { }
 
@@ -50,9 +64,14 @@ class HistoryMode : public ModeHandler
                        std::string::size_type colon = parameter.find(':');
                        if (colon == std::string::npos)
                                return MODEACTION_DENY;
-                       int len = atoi(parameter.substr(0, colon).c_str());
-                       int time = ServerInstance->Duration(parameter.substr(colon+1));
-                       if (len <= 0 || time < 0)
+
+                       std::string duration = parameter.substr(colon+1);
+                       if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration))))
+                               return MODEACTION_DENY;
+
+                       unsigned int len = ConvToInt(parameter.substr(0, colon));
+                       int time = ServerInstance->Duration(duration);
+                       if (len == 0 || time < 0)
                                return MODEACTION_DENY;
                        if (len > maxlines && IS_LOCAL(source))
                                return MODEACTION_DENY;
@@ -60,7 +79,21 @@ class HistoryMode : public ModeHandler
                                len = maxlines;
                        if (parameter == channel->GetModeParameter(this))
                                return MODEACTION_DENY;
-                       ext.set(channel, new HistoryList(len, time));
+
+                       HistoryList* history = ext.get(channel);
+                       if (history)
+                       {
+                               // Shrink the list if the new line number limit is lower than the old one
+                               if (len < history->lines.size())
+                                       history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len));
+
+                               history->maxlen = len;
+                               history->maxtime = time;
+                       }
+                       else
+                       {
+                               ext.set(channel, new HistoryList(len, time));
+                       }
                        channel->SetModeParam('H', parameter);
                }
                else
@@ -77,6 +110,7 @@ class HistoryMode : public ModeHandler
 class ModuleChanHistory : public Module
 {
        HistoryMode m;
+       bool sendnotice;
  public:
        ModuleChanHistory() : m(this)
        {
@@ -93,7 +127,9 @@ class ModuleChanHistory : public Module
 
        void OnRehash(User*)
        {
-               m.maxlines = ServerInstance->Config->ConfValue("chanhistory")->getInt("maxlines", 50);
+               ConfigTag* tag = ServerInstance->Config->ConfValue("chanhistory");
+               m.maxlines = tag->getInt("maxlines", 50);
+               sendnotice = tag->getInt("notice", true);
        }
 
        ~ModuleChanHistory()
@@ -121,14 +157,22 @@ class ModuleChanHistory : public Module
 
        void OnPostJoin(Membership* memb)
        {
+               if (IS_REMOTE(memb->user))
+                       return;
+
                HistoryList* list = m.ext.get(memb->chan);
                if (!list)
                        return;
                time_t mintime = 0;
                if (list->maxtime)
                        mintime = ServerInstance->Time() - list->maxtime;
-               memb->user->WriteServ("NOTICE %s :Replaying up to %d lines of pre-join history spanning up to %d seconds",
-                       memb->chan->name.c_str(), list->maxlen, list->maxtime);
+
+               if (sendnotice)
+               {
+                       memb->user->WriteServ("NOTICE %s :Replaying up to %d lines of pre-join history spanning up to %d seconds",
+                               memb->chan->name.c_str(), list->maxlen, list->maxtime);
+               }
+
                for(std::deque<HistoryItem>::iterator i = list->lines.begin(); i != list->lines.end(); ++i)
                {
                        if (i->ts >= mintime)
index 06c852938b9f564101efdf5285a15af6882cc9b7..28fa891b61cd1854134c73979a03107640d46bbc 100644 (file)
@@ -27,7 +27,7 @@
 #include "xline.h"
 
 static bool ZlineOnMatch = false;
-static std::vector<ZLine *> background_zlines;
+static bool added_zline = false;
 
 class RLine : public XLine
 {
@@ -75,8 +75,17 @@ class RLine : public XLine
 
        void Apply(User* u)
        {
-               if (ZlineOnMatch) {
-                       background_zlines.push_back(new ZLine(ServerInstance->Time(), duration ? expiry - ServerInstance->Time() : 0, ServerInstance->Config->ServerName.c_str(), reason.c_str(), u->GetIPString()));
+               if (ZlineOnMatch)
+               {
+                       ZLine* zl = new ZLine(ServerInstance->Time(), duration ? expiry - ServerInstance->Time() : 0, ServerInstance->Config->ServerName.c_str(), reason.c_str(), u->GetIPString());
+                       if (ServerInstance->XLines->AddLine(zl, NULL))
+                       {
+                               ServerInstance->SNO->WriteToSnoMask('x', "Z-line added due to R-line match on *@%s%s%s: %s",
+                                       zl->ipaddr.c_str(), zl->duration ? " to expire on " : "", zl->duration ? ServerInstance->TimeString(zl->expiry).c_str() : "", zl->reason.c_str());
+                               added_zline = true;
+                       }
+                       else
+                               delete zl;
                }
                DefaultApply(u, "R", false);
        }
@@ -199,7 +208,7 @@ class CommandRLine : public Command
 
        RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
        {
-               return ROUTE_BROADCAST;
+               return ROUTE_LOCALONLY;
        }
 };
 
@@ -254,9 +263,6 @@ class ModuleRLine : public Module
        {
                ConfigReader Conf;
 
-               if (!Conf.ReadFlag("rline", "zlineonmatch", 0) && ZlineOnMatch)
-                       background_zlines.clear();
-
                MatchOnNickChange = Conf.ReadFlag("rline", "matchonnickchange", 0);
                ZlineOnMatch = Conf.ReadFlag("rline", "zlineonmatch", 0);
                std::string newrxengine = Conf.ReadValue("rline", "engine", 0);
@@ -299,18 +305,11 @@ class ModuleRLine : public Module
 
        virtual void OnBackgroundTimer(time_t curtime)
        {
-               if (!ZlineOnMatch) return;
-               for (std::vector<ZLine *>::iterator i = background_zlines.begin(); i != background_zlines.end(); i++)
+               if (added_zline)
                {
-                       ZLine *zl = *i;
-                       if (ServerInstance->XLines->AddLine(zl,NULL))
-                       {
-                               ServerInstance->SNO->WriteToSnoMask('x',"Z-line added due to R-line match on *@%s%s%s: %s", 
-                                       zl->ipaddr.c_str(), zl->duration ? " to expire on " : "", zl->duration ? ServerInstance->TimeString(zl->expiry).c_str() : "", zl->reason.c_str());
-                               ServerInstance->XLines->ApplyLines();
-                       }
+                       added_zline = false;
+                       ServerInstance->XLines->ApplyLines();
                }
-               background_zlines.clear();
        }
 
 };
index 391f9a187155d08cf05fe58da6456f02abced4d3..fe1c41162b8300157bee3272557a7f44a7306951 100644 (file)
@@ -59,11 +59,6 @@ public:
                return false;
        }
 
-       void Apply(User *u)
-       {
-       }
-
-
        void DisplayExpiry()
        {
                ServerInstance->SNO->WriteToSnoMask('x',"Removing expired shun %s (set by %s %ld seconds ago)",
@@ -89,6 +84,11 @@ class ShunFactory : public XLineFactory
        {
                return new Shun(set_time, duration, source, reason, xline_specific_mask);
        }
+
+       bool AutoApplyToUserList(XLine *x)
+       {
+               return false;
+       }
 };
 
 //typedef std::vector<Shun> shunlist;
@@ -121,11 +121,10 @@ class CommandShun : public Command
                        else
                        {
                                user->WriteServ("NOTICE %s :*** Shun %s not found in list, try /stats H.",user->nick.c_str(),target.c_str());
+                               return CMD_FAILURE;
                        }
-
-                       return CMD_SUCCESS;
                }
-               else if (parameters.size() >= 2)
+               else
                {
                        // Adding - XXX todo make this respect <insane> tag perhaps..
                        long duration;
@@ -140,49 +139,35 @@ class CommandShun : public Command
                                duration = 0;
                                expr = parameters[1];
                        }
-                       Shun *r = NULL;
 
-                       try
-                       {
-                               r = new Shun(ServerInstance->Time(), duration, user->nick.c_str(), expr.c_str(), target.c_str());
-                       }
-                       catch (...)
+                       Shun* r = new Shun(ServerInstance->Time(), duration, user->nick.c_str(), expr.c_str(), target.c_str());
+                       if (ServerInstance->XLines->AddLine(r, user))
                        {
-                               ; // Do nothing. If we get here, the regex was fucked up, and they already got told it fucked up.
-                       }
-
-                       if (r)
-                       {
-                               if (ServerInstance->XLines->AddLine(r, user))
+                               if (!duration)
                                {
-                                       if (!duration)
-                                       {
-                                               ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent SHUN for %s: %s",
-                                                       user->nick.c_str(), target.c_str(), expr.c_str());
-                                       }
-                                       else
-                                       {
-                                               time_t c_requires_crap = duration + ServerInstance->Time();
-                                               ServerInstance->SNO->WriteToSnoMask('x', "%s added timed SHUN for %s to expire on %s: %s",
-                                                       user->nick.c_str(), target.c_str(), ServerInstance->TimeString(c_requires_crap).c_str(), expr.c_str());
-                                       }
-
-                                       ServerInstance->XLines->ApplyLines();
+                                       ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent SHUN for %s: %s",
+                                               user->nick.c_str(), target.c_str(), expr.c_str());
                                }
                                else
                                {
-                                       delete r;
-                                       user->WriteServ("NOTICE %s :*** Shun for %s already exists", user->nick.c_str(), expr.c_str());
+                                       time_t c_requires_crap = duration + ServerInstance->Time();
+                                       ServerInstance->SNO->WriteToSnoMask('x', "%s added timed SHUN for %s to expire on %s: %s",
+                                               user->nick.c_str(), target.c_str(), ServerInstance->TimeString(c_requires_crap).c_str(), expr.c_str());
                                }
                        }
+                       else
+                       {
+                               delete r;
+                               user->WriteServ("NOTICE %s :*** Shun for %s already exists", user->nick.c_str(), expr.c_str());
+                               return CMD_FAILURE;
+                       }
                }
-
-               return CMD_FAILURE;
+               return CMD_SUCCESS;
        }
 
        RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
        {
-               return ROUTE_BROADCAST;
+               return ROUTE_LOCALONLY;
        }
 };
 
@@ -200,8 +185,8 @@ class ModuleShun : public Module
                ServerInstance->XLines->RegisterFactory(&f);
                ServerInstance->AddCommand(&cmd);
 
-               Implementation eventlist[] = { I_OnStats, I_OnPreCommand, I_OnUserConnect, I_OnRehash };
-               ServerInstance->Modules->Attach(eventlist, this, 4);
+               Implementation eventlist[] = { I_OnStats, I_OnPreCommand, I_OnRehash };
+               ServerInstance->Modules->Attach(eventlist, this, 3);
                OnRehash(NULL);
        }
 
@@ -235,8 +220,6 @@ class ModuleShun : public Module
                        cmds = "PING PONG QUIT";
 
                ShunEnabledCommands.clear();
-               NotifyOfShun = true;
-               affectopers = false;
 
                std::stringstream dcmds(cmds);
                std::string thiscmd;
@@ -250,21 +233,6 @@ class ModuleShun : public Module
                affectopers = MyConf.ReadFlag("shun", "affectopers", "no", 0);
        }
 
-       virtual void OnUserConnect(LocalUser* user)
-       {
-               if (!IS_LOCAL(user))
-                       return;
-
-               // Apply lines on user connect
-               XLine *rl = ServerInstance->XLines->MatchesLine("SHUN", user);
-
-               if (rl)
-               {
-                       // Bang. :P
-                       rl->Apply(user);
-               }
-       }
-
        virtual ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, LocalUser* user, bool validated, const std::string &original_line)
        {
                if (validated)
@@ -296,10 +264,10 @@ class ModuleShun : public Module
                        /* Allow QUIT but dont show any quit message */
                        parameters.clear();
                }
-               else if (command == "PART")
+               else if ((command == "PART") && (parameters.size() > 1))
                {
                        /* same for PART */
-                       parameters[1] = "";
+                       parameters[1].clear();
                }
 
                /* if we're here, allow the command. */
index a38776d8db7a501a7a8f1fefe20a19cb4cccfce9..37288a32299433549be19abf525b44f443ee5491 100644 (file)
@@ -81,6 +81,11 @@ class SVSHoldFactory : public XLineFactory
        {
                return new SVSHold(set_time, duration, source, reason, xline_specific_mask);
        }
+
+       bool AutoApplyToUserList(XLine *x)
+       {
+               return false;
+       }
 };
 
 /** Handle /SVSHold
@@ -115,45 +120,30 @@ class CommandSvshold : public Command
                        {
                                user->WriteServ("NOTICE %s :*** SVSHOLD %s not found in list, try /stats S.",user->nick.c_str(),parameters[0].c_str());
                        }
-
-                       return CMD_SUCCESS;
                }
-               else if (parameters.size() >= 2)
+               else
                {
                        // Adding - XXX todo make this respect <insane> tag perhaps..
                        long duration = ServerInstance->Duration(parameters[1]);
-                       SVSHold *r = NULL;
+                       SVSHold* r = new SVSHold(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str());
 
-                       try
-                       {
-                               r = new SVSHold(ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str());
-                       }
-                       catch (...)
+                       if (ServerInstance->XLines->AddLine(r, user))
                        {
-                               ; // Do nothing.
-                       }
-
-                       if (r)
-                       {
-                               if (ServerInstance->XLines->AddLine(r, user))
+                               if (!duration)
                                {
-                                       if (!duration)
-                                       {
-                                               ServerInstance->SNO->WriteGlobalSno('x', "%s added permanent SVSHOLD for %s: %s", user->nick.c_str(), parameters[0].c_str(), parameters[2].c_str());
-                                       }
-                                       else
-                                       {
-                                               time_t c_requires_crap = duration + ServerInstance->Time();
-                                               ServerInstance->SNO->WriteGlobalSno('x', "%s added timed SVSHOLD for %s, expires on %s: %s", user->nick.c_str(), parameters[0].c_str(), ServerInstance->TimeString(c_requires_crap).c_str(), parameters[2].c_str());
-                                       }
-
-                                       ServerInstance->XLines->ApplyLines();
+                                       ServerInstance->SNO->WriteGlobalSno('x', "%s added permanent SVSHOLD for %s: %s", user->nick.c_str(), parameters[0].c_str(), parameters[2].c_str());
                                }
                                else
                                {
-                                       delete r;
+                                       time_t c_requires_crap = duration + ServerInstance->Time();
+                                       ServerInstance->SNO->WriteGlobalSno('x', "%s added timed SVSHOLD for %s, expires on %s: %s", user->nick.c_str(), parameters[0].c_str(), ServerInstance->TimeString(c_requires_crap).c_str(), parameters[2].c_str());
                                }
                        }
+                       else
+                       {
+                               delete r;
+                               return CMD_FAILURE;
+                       }
                }
 
                return CMD_SUCCESS;
@@ -161,7 +151,7 @@ class CommandSvshold : public Command
 
        RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
        {
-               return ROUTE_BROADCAST;
+               return ROUTE_LOCALONLY;
        }
 };