예제 #1
0
        protected void ProcessStalkChildren(XmlElement element, string flag, ComplexStalk complexStalk)
        {
            var foundSearchTree = false;

            if (element.HasChildNodes)
            {
                var childNodeCollection = element.ChildNodes;

                foreach (XmlNode node in childNodeCollection)
                {
                    var xmlElement = node as XmlElement;
                    if (xmlElement == null)
                    {
                        continue;
                    }

                    if (xmlElement.Name == "searchtree")
                    {
                        foundSearchTree = true;

                        try
                        {
                            complexStalk.SetStalkTree(
                                this.StalkNodeFactory.NewFromXmlFragment((XmlElement)xmlElement.FirstChild));
                        }
                        catch (WebException ex)
                        {
                            this.Logger.ErrorFormat(
                                ex,
                                "Error loading stalk {0} in {1} from XML.",
                                complexStalk.Identifier,
                                complexStalk.Channel);

                            complexStalk.IsEnabled   = false;
                            complexStalk.Description = complexStalk.Description
                                                       + "; Disabled automatically on load due to unhandled exception.";
                        }

                        continue;
                    }

                    if (xmlElement.Name == "subscribers")
                    {
                        complexStalk.Subscribers.AddRange(
                            this.PopulateSubscribers(xmlElement.ChildNodes));

                        continue;
                    }

                    this.Logger.DebugFormat("Unrecognised child {0} of stalk {1}", xmlElement.Name, flag);
                }

                if (!foundSearchTree)
                {
                    this.Logger.InfoFormat("Assuming stalk {0} is legacy", flag);
                    complexStalk.SetStalkTree(this.StalkNodeFactory.NewFromXmlFragment((XmlElement)element.FirstChild));
                }
            }
        }
예제 #2
0
        public void ShouldSetLastModified()
        {
            var stalk = new ComplexStalk("abc");

            var span = DateTime.UtcNow - stalk.LastUpdateTime;

            Assert.True(span.HasValue);
            Assert.Less(span.Value.TotalSeconds, 5);
        }
예제 #3
0
        public void ShouldNotBeActive()
        {
            var stalk = new ComplexStalk("abc")
            {
                IsEnabled  = false,
                ExpiryTime = null
            };

            Assert.IsFalse(stalk.IsActive());
        }
예제 #4
0
        public void ShouldNotBeActiveWithExpiry()
        {
            var stalk = new ComplexStalk("abc")
            {
                IsEnabled  = true,
                ExpiryTime = DateTime.UtcNow.AddMinutes(-1)
            };

            Assert.IsFalse(stalk.IsActive());
        }
예제 #5
0
        public void ShouldBeActive()
        {
            var stalk = new ComplexStalk("abc")
            {
                IsEnabled  = true,
                ExpiryTime = null
            };

            Assert.IsTrue(stalk.IsActive());
        }
예제 #6
0
        public dynamic PostNewStalk(dynamic parameters)
        {
            var channel = this.channelConfiguration.Items.FirstOrDefault(x => x.Guid == parameters.channel);

            if (channel == null)
            {
                return(new NotFoundResponse());
            }

            if (!this.UserCanConfigureStalks(this.Context, channel))
            {
                return(new NotFoundResponse());
            }

            if (string.IsNullOrWhiteSpace(this.Request.Form.stalkIdentifier))
            {
                var newStalkModel = this.NewStalk(parameters);
                newStalkModel.Errors.Add("You must set a stalk identifier.");
                return(newStalkModel);
            }

            if (channel.Stalks.ContainsKey(this.Request.Form.stalkIdentifier))
            {
                var newStalkModel = this.NewStalk(parameters);
                newStalkModel.Errors.Add("This stalk identifier is already in use in this channel.");
                return(newStalkModel);
            }

            IStalk stalk = new ComplexStalk(this.Request.Form.stalkIdentifier)
            {
                Channel = channel.Identifier, WatchChannel = this.AppConfiguration.WikimediaChannel
            };

            channel.Stalks.Add(stalk.Identifier, stalk);

            this.channelConfiguration.Save();
            this.FreenodeClient.SendMessage(
                stalk.Channel,
                "The stalk " + stalk.Identifier + " was created by " + this.Context.CurrentUser.UserName
                + " from the web interface.");

            return(this.Response.AsRedirect(string.Format("/channels/{0}/stalk/{1}/edit", channel.Guid, stalk.Identifier)));
        }
예제 #7
0
        // ReSharper disable once UnusedMember.Global
        protected IEnumerable <CommandResponse> AddMode()
        {
            var tokenList = this.Arguments;

            var stalkName = tokenList.First();
            var stalk     = new ComplexStalk(stalkName)
            {
                Channel = this.CommandSource, WatchChannel = this.config.WikimediaChannel
            };

            this.channelConfiguration[this.CommandSource].Stalks.Add(stalk.Identifier, stalk);

            yield return(new CommandResponse
            {
                Message = string.Format("Added disabled stalk {0} with CSL value: {1}", stalkName, stalk.SearchTree)
            });

            this.channelConfiguration.Save();
        }
        public IStalk NewFromTemplate(string flag, ITemplate template, IList <string> parameters)
        {
            var formatParameters   = parameters.ToArray <object>();
            var templateSearchTree = string.Format(new StalkConfigFormatter(), template.SearchTree, formatParameters);

            var doc = new XmlDocument();

            doc.LoadXml(templateSearchTree);

            var stalkNode = this.stalkNodeFactory.NewFromXmlFragment(doc.DocumentElement);

            if (flag == null)
            {
                if (template.StalkFlag == null)
                {
                    throw new Exception("Cannot create stalk without defined flag");
                }

                flag = string.Format(template.StalkFlag, formatParameters);
            }


            string description = null;

            if (template.Description != null)
            {
                description = string.Format(template.Description, formatParameters);
            }

            var stalk = new ComplexStalk(flag)
            {
                Description  = description,
                IsEnabled    = template.StalkIsEnabled,
                ExpiryTime   = template.ExpiryDuration.HasValue ? DateTime.UtcNow + template.ExpiryDuration : null,
                SearchTree   = stalkNode,
                WatchChannel = template.WatchChannel
            };

            return(stalk);
        }
예제 #9
0
        public void ShouldConstructFlag()
        {
            var stalk = new ComplexStalk("abc");

            Assert.AreEqual("abc", stalk.Identifier);
        }
예제 #10
0
        protected override void execute(User source, string destination, string[] tokens)
        {
            // =acc id user

            if (tokens.Length < 2)
            {
                EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                return;
            }

            string id = GlobalFunctions.popFromFront(ref tokens);
            string user = string.Join(" ", tokens);

            var s = new ComplexStalk( "acc" + id );

            OrNode or = new OrNode();

            OrNode uor = new OrNode();
            UserStalkNode usn = new UserStalkNode();
            usn.setMatchExpression(user);

            PageStalkNode psn = new PageStalkNode();
            psn.setMatchExpression(user);

            uor.LeftChildNode = usn;
            uor.RightChildNode = psn;

            OrNode upor = new OrNode();

            PageStalkNode upsn = new PageStalkNode();
            upsn.setMatchExpression("User:"******"User talk:" + user);

            upor.LeftChildNode = upsn;
            upor.RightChildNode = utpsn;

            SummaryStalkNode ssn = new SummaryStalkNode();
            ssn.setMatchExpression(user);

            OrNode or2 = new OrNode();
            or2.LeftChildNode = uor;
            or2.RightChildNode = upor;

            or.LeftChildNode = or2;
            or.RightChildNode = ssn;
            s.immediatemail = true;
            s.Description = "ACC " + id + ": " + user;
            s.mail = false;
            s.setSearchTree(or, true);
            s.enabled = true;

            s.expiryTime = DateTime.Now.AddMonths(3);

            EyeInTheSkyBot.Config.Stalks.Add("acc" + id, s);
            EyeInTheSkyBot.Config.save();

            EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                "Set new stalk " + s.Flag +
                " with CSL value: " + or);
        }
예제 #11
0
        public IStalk NewFromXmlElement(XmlElement element)
        {
            var flag = element.Attributes["flag"].Value;

            // Last update time
            var      timeAttribute  = element.Attributes["lastupdate"];
            DateTime?lastUpdateTime = null;

            if (timeAttribute != null)
            {
                lastUpdateTime = this.ParseDate(flag, timeAttribute.Value, "last update time");
            }

            // Creation time
            var creationAttribute = element.Attributes["creation"];
            var creation          = DateTime.MinValue;

            if (creationAttribute != null)
            {
                creation = this.ParseDate(flag, creationAttribute.Value, "creation time");
            }

            // Last trigger time
            timeAttribute = element.Attributes["lasttrigger"];
            DateTime?lastTriggerTime = null;

            if (timeAttribute != null)
            {
                lastTriggerTime = this.ParseDate(flag, timeAttribute.Value, "last trigger time");

                // backwards compat
                if (lastTriggerTime == new DateTime(1970, 1, 1, 0, 0, 0))
                {
                    lastTriggerTime = null;
                }
            }

            // Expiry time
            timeAttribute = element.Attributes["expiry"];
            DateTime?expiryTime = null;

            if (timeAttribute != null)
            {
                expiryTime = this.ParseDate(flag, timeAttribute.Value, "expiry time");

                // backwards compat
                if (expiryTime == new DateTime(9999, 12, 31, 23, 59, 59))
                {
                    expiryTime = null;
                }
            }

            // Dynamic expiry
            var      dynamicExpiryAttribute = element.GetAttribute("dynamicexpiry");
            TimeSpan?dynamicExpiry          = null;

            if (!string.IsNullOrWhiteSpace(dynamicExpiryAttribute))
            {
                dynamicExpiry = XmlConvert.ToTimeSpan(dynamicExpiryAttribute);
            }

            // Enabled attribute
            var  enabledText = element.GetAttribute("enabled");
            bool enabled;

            if (!bool.TryParse(enabledText, out enabled))
            {
                this.Logger.WarnFormat(
                    "Unable to parse enabled attribute value '{1}' for stalk {0}. Defaulting to enabled.",
                    flag,
                    enabledText);
                enabled = true;
            }

            var triggercountText = element.GetAttribute("triggercount");
            int triggerCount;

            int.TryParse(triggercountText, out triggerCount);

            var description = element.GetAttribute("description");

            if (string.IsNullOrWhiteSpace(description))
            {
                description = null;
            }

            var lastMessageId = element.GetAttribute("lastmessageid");

            if (string.IsNullOrWhiteSpace(lastMessageId))
            {
                lastMessageId = null;
            }

            var watchChannel = element.GetAttribute("watchchannel");

            if (string.IsNullOrWhiteSpace(watchChannel))
            {
                watchChannel = this.appConfig.WikimediaChannel;
            }

            var s = new ComplexStalk(
                flag,
                lastUpdateTime,
                lastTriggerTime,
                description,
                expiryTime,
                enabled,
                triggerCount,
                lastMessageId,
                watchChannel,
                dynamicExpiry,
                creation);

            this.ProcessStalkChildren(element, flag, s);

            return(s);
        }
예제 #12
0
        // ReSharper disable once UnusedMember.Global
        protected IEnumerable <CommandResponse> CloneMode()
        {
            var tokenList        = this.Arguments;
            var sourceChannel    = tokenList[0];
            var sourceIdentifier = tokenList[1];
            var targetIdentifier = tokenList[2];

            var sourceChannelConfig = this.channelConfiguration.ContainsKey(sourceChannel)
                ? this.channelConfiguration[sourceChannel]
                : null;

            if (sourceChannelConfig == null)
            {
                throw new CommandErrorException(string.Format("The channel {0} does not exist in configuration", sourceChannel));
            }

            var sourceStalk = sourceChannelConfig.Stalks.ContainsKey(sourceIdentifier)
                ? sourceChannelConfig.Stalks[sourceIdentifier]
                : null;

            if (sourceStalk == null)
            {
                throw new CommandErrorException(string.Format("The channel {0} does not exist in configuration", sourceChannel));
            }

            if (this.channelConfiguration[this.CommandSource].Stalks.ContainsKey(targetIdentifier))
            {
                throw new CommandErrorException(string.Format("The identifier {0} already exists in this channel!",
                                                              targetIdentifier));
            }

            var tree = sourceStalk.SearchTree;

            // bounce it via XML to ensure its a) different objects and b) saves properly
            tree = this.stalkNodeFactory.NewFromXmlFragment(this.stalkNodeFactory.ToXml(new XmlDocument(), tree));

            var newStalk = new ComplexStalk(targetIdentifier)
            {
                Channel         = this.CommandSource,
                Description     = string.Format("{0}; based on stalk {1} from {2}", sourceStalk.Description, sourceIdentifier, sourceChannel),
                ExpiryTime      = sourceStalk.ExpiryTime,
                IsEnabled       = sourceStalk.IsEnabled,
                SearchTree      = tree,
                WatchChannel    = sourceStalk.WatchChannel,
                DynamicExpiry   = sourceStalk.DynamicExpiry,
                LastTriggerTime = sourceStalk.LastTriggerTime
            };

            this.channelConfiguration[this.CommandSource].Stalks.Add(newStalk.Identifier, newStalk);
            this.channelConfiguration.Save();

            yield return(new CommandResponse
            {
                Message = string.Format("Created new {1} stalk {0}{2} with CSL {3}",
                                        newStalk.Identifier,
                                        newStalk.IsEnabled ? "enabled" : "disabled",
                                        newStalk.ExpiryTime.HasValue
                        ? newStalk.ExpiryTime < DateTime.UtcNow
                            ? string.Format(" (expired {0:%d}d {0:%h}h {0:%m}m ago)", newStalk.ExpiryTime.Value - DateTime.UtcNow)
                            : string.Format(" (expiring in {0:%d}d {0:%h}h {0:%m}m)", newStalk.ExpiryTime.Value - DateTime.UtcNow)
                        : string.Empty,
                                        tree
                                        )
            });
        }
예제 #13
0
        protected override void execute(User source, string destination, string[] tokens)
        {
            // =quick token type value

            if (tokens.Length < 3)
            {
                EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                return;
            }

            string name = GlobalFunctions.popFromFront(ref tokens);
            string type = GlobalFunctions.popFromFront(ref tokens);
            string regex = string.Join(" ", tokens);

            var s = new ComplexStalk(name);

            EyeInTheSkyBot.Config.Stalks.Add(name, s);

            switch (type)
            {
                case "user":
                    UserStalkNode usn = new UserStalkNode();
                    usn.setMatchExpression(regex);
                    s.setSearchTree(usn, true);
                    EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                               "Set " + type + " for new stalk " + name +
                               " with CSL value: " + usn);
                    break;
                case "page":
                    PageStalkNode psn = new PageStalkNode();
                    psn.setMatchExpression(regex);
                    s.setSearchTree(psn, true);
                    EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                               "Set " + type + " for new stalk " + name +
                               " with CSL value: " + psn);
                    break;
                case "summary":
                    SummaryStalkNode ssn = new SummaryStalkNode();
                    ssn.setMatchExpression(regex);
                    s.setSearchTree(ssn, true);
                    EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                               "Set " + type + " for new stalk " + name +
                               " with CSL value: " + ssn);
                    break;
                case "xml":
                    string xmlfragment = string.Join(" ", tokens);
                    try
                    {
                        XmlDocument xd = new XmlDocument();
                        xd.LoadXml(xmlfragment);

                        StalkNode node = StalkNode.newFromXmlFragment(xd.FirstChild);
                        s.setSearchTree(node, true);
                        EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                               "Set " + type + " for new stalk " + name +
                               " with CSL value: " + node);

                    }
                    catch (XmlException)
                    {
                        EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "XML Error.");
                    }
                    break;
                default:
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "Unknown stalk type!");
                    return;
            }

            s.enabled = true;

            EyeInTheSkyBot.Config.save();
        }
예제 #14
0
        protected override void execute(User source, string destination, string[] tokens)
        {
            if (tokens.Length < 1)
            {
                EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                return;
            }

            string mode = GlobalFunctions.popFromFront(ref tokens);
            if(mode == "add")
            #region add
            {
                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }

                var s = new ComplexStalk(tokens[0]);

                EyeInTheSkyBot.Config.Stalks.Add(tokens[0],s);
                EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination, "Added stalk " + tokens[0]);
            }
            #endregion
            if (mode == "del")
            #region del
            {
                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }
                EyeInTheSkyBot.Config.Stalks.Remove(tokens[0]);
                EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination, "Deleted stalk " + tokens[0]);
            }
            #endregion
            if (mode == "set")
            #region set
            {
                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }
                string stalk = GlobalFunctions.popFromFront(ref tokens);

                ComplexStalk s = EyeInTheSkyBot.Config.Stalks[stalk];

                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }
                string type = GlobalFunctions.popFromFront(ref tokens);

                    string regex = string.Join(" ", tokens);

                    switch (type)
                    {
                        case "user":
                            var usn = new UserStalkNode();
                            usn.setMatchExpression(regex);
                            s.setSearchTree(usn, true);
                            EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                       "Set " + type + " for stalk " + stalk +
                                       " with CSL value: " + usn);
                            break;
                        case "page":
                            var psn = new PageStalkNode();
                            psn.setMatchExpression(regex);
                            s.setSearchTree(psn, true);
                            EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                       "Set " + type + " for stalk " + stalk +
                                       " with CSL value: " + psn);
                            break;
                        case "summary":
                            var ssn = new SummaryStalkNode();
                            ssn.setMatchExpression(regex);
                            s.setSearchTree(ssn, true);
                            EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                       "Set " + type + " for stalk " + stalk +
                                       " with CSL value: " + ssn);
                            break;
                        case "xml":
                            string xmlfragment = string.Join(" ", tokens);
                            try
                            {
                                var xd = new XmlDocument();
                                xd.LoadXml(xmlfragment);

                                StalkNode node = StalkNode.newFromXmlFragment(xd.FirstChild);
                                s.setSearchTree(node, true);
                                EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                       "Set " + type + " for stalk " + stalk +
                                       " with CSL value: " + node);

                            }
                            catch (XmlException)
                            {
                                EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "XML Error.");
                            }
                            break;
                        default:
                            EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "Unknown stalk type!");
                            return;
                    }
            }
            #endregion
            if (mode == "list")
            #region list
            {
                EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "Stalk list:");
                foreach (KeyValuePair<string, ComplexStalk> kvp in EyeInTheSkyBot.Config.Stalks)
                {
                        EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname,
                                                              kvp.Value.ToString());

                }
                EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "End of stalk list.");
            }
            #endregion
            if(mode == "mail")
            #region mail
            {
                if (tokens.Length < 2)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }

                if(tokens[1] == "immediate")
                {
                    if (tokens.Length < 3 )
                    {
                        EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                        return;
                    }

                    bool imail = bool.Parse(tokens[2]);
                    EyeInTheSkyBot.Config.Stalks[tokens[0]].immediatemail = imail;
                    EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                                           "Set immediatemail attribute on stalk " + tokens[0] + " to " + imail);
                }

                bool mail = bool.Parse(tokens[1]);
                EyeInTheSkyBot.Config.Stalks[tokens[0]].mail = mail;
                EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                                       "Set mail attribute on stalk " + tokens[0] + " to " + mail);
            }
            #endregion
            if(mode == "description")
            #region description
            {
                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }

                string stalk = GlobalFunctions.popFromFront(ref tokens);
                string descr = string.Join(" ", tokens);

                EyeInTheSkyBot.Config.Stalks[stalk].Description = descr;
                EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                       "Set description attribute on stalk " + stalk + " to " + descr);

            }
            #endregion
            if(mode == "expiry")
            #region expiry
            {
                if (tokens.Length < 2)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }
                string stalk = GlobalFunctions.popFromFront(ref tokens);
                string date = string.Join(" ", tokens);

                DateTime expiryTime = DateTime.Parse(date);
                EyeInTheSkyBot.Config.Stalks[stalk].expiryTime = expiryTime;
                EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                                       "Set expiry attribute on stalk " + stalk + " to " + expiryTime);

            }
            #endregion
            if (mode == "enabled")
            #region enabled
            {
                if (tokens.Length < 2)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }

                bool enabled = bool.Parse(tokens[1]);
                EyeInTheSkyBot.Config.Stalks[tokens[0]].enabled = enabled;
                EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                                       "Set enabled attribute on stalk " + tokens[0] + " to " + enabled);
            }
            #endregion
            if (mode == "and")
            #region and
            {
                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }
                string stalk = GlobalFunctions.popFromFront(ref tokens);

                ComplexStalk s = EyeInTheSkyBot.Config.Stalks[stalk];

                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }
                string type = GlobalFunctions.popFromFront(ref tokens);

                string regex = string.Join(" ", tokens);

                var newroot = new AndNode {LeftChildNode = s.getSearchTree()};

                switch (type)
                {
                    case "user":
                        var usn = new UserStalkNode();
                        usn.setMatchExpression(regex);
                        newroot.RightChildNode = usn;
                        s.setSearchTree(newroot, true);
                        EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                   "Set " + type + " for stalk " + stalk +
                                   " with CSL value: " + newroot);
                        break;
                    case "page":
                        var psn = new PageStalkNode();
                        psn.setMatchExpression(regex);
                        newroot.RightChildNode = psn;
                        s.setSearchTree(newroot, true);
                        EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                   "Set " + type + " for stalk " + stalk +
                                   " with CSL value: " + newroot);
                        break;
                    case "summary":
                        var ssn = new SummaryStalkNode();
                        ssn.setMatchExpression(regex);
                        newroot.RightChildNode = ssn;
                        s.setSearchTree(newroot, true);
                        EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                   "Set " + type + " for stalk " + stalk +
                                   " with CSL value: " + newroot);
                        break;
                    case "xml":
                        string xmlfragment = string.Join(" ", tokens);
                        try
                        {
                            var xd = new XmlDocument();
                            xd.LoadXml(xmlfragment);

                            StalkNode node = StalkNode.newFromXmlFragment(xd.FirstChild);

                            newroot.RightChildNode = node;
                            s.setSearchTree(newroot, true);
                            EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                   "Set " + type + " for stalk " + stalk +
                                   " with CSL value: " + newroot);

                        }
                        catch (XmlException)
                        {
                            EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "XML Error.");
                        }
                        break;
                    default:
                        EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "Unknown stalk type!");
                        return;
                }
            }
            #endregion
            if (mode == "or")
            #region or
            {
                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }
                string stalk = GlobalFunctions.popFromFront(ref tokens);

                ComplexStalk s = EyeInTheSkyBot.Config.Stalks[stalk];

                if (tokens.Length < 1)
                {
                    EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "More params pls!");
                    return;
                }
                string type = GlobalFunctions.popFromFront(ref tokens);

                string regex = string.Join(" ", tokens);

                var newroot = new OrNode { LeftChildNode = s.getSearchTree() };

                switch (type)
                {
                    case "user":
                        var usn = new UserStalkNode();
                        usn.setMatchExpression(regex);
                        newroot.RightChildNode = usn;
                        s.setSearchTree(newroot, true);
                        EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                   "Set " + type + " for stalk " + stalk +
                                   " with CSL value: " + newroot);
                        break;
                    case "page":
                        var psn = new PageStalkNode();
                        psn.setMatchExpression(regex);
                        newroot.RightChildNode = psn;
                        s.setSearchTree(newroot, true);
                        EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                   "Set " + type + " for stalk " + stalk +
                                   " with CSL value: " + newroot);
                        break;
                    case "summary":
                        var ssn = new SummaryStalkNode();
                        ssn.setMatchExpression(regex);
                        newroot.RightChildNode = ssn;
                        s.setSearchTree(newroot, true);
                        EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                   "Set " + type + " for stalk " + stalk +
                                   " with CSL value: " + newroot);
                        break;
                    case "xml":
                        string xmlfragment = string.Join(" ", tokens);
                        try
                        {
                            var xd = new XmlDocument();
                            xd.LoadXml(xmlfragment);

                            StalkNode node = StalkNode.newFromXmlFragment(xd.FirstChild);

                            newroot.RightChildNode = node;
                            s.setSearchTree(newroot, true);
                            EyeInTheSkyBot.IrcFreenode.ircPrivmsg(destination,
                                   "Set " + type + " for stalk " + stalk +
                                   " with CSL value: " + newroot);

                        }
                        catch (XmlException)
                        {
                            EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "XML Error.");
                        }
                        break;
                    default:
                        EyeInTheSkyBot.IrcFreenode.ircNotice(source.nickname, "Unknown stalk type!");
                        return;
                }
            }
            #endregion
            EyeInTheSkyBot.Config.save();
        }