Example #1
0
        /// <summary>
        /// Parses a condition made of left-hand term, condition type and right-hand term and verifies if it's true.
        /// </summary>
        /// <param name="cfLine">The reference to the line to parse</param>
        /// <param name="data">The BotData needed for variable replacement</param>
        /// <returns></returns>
        public static bool ParseCheckCondition(ref string cfLine, LSGlobals ls)
        {
            var first    = LineParser.ParseLiteral(ref cfLine, "STRING");
            var Comparer = (Comparer)LineParser.ParseEnum(ref cfLine, "Comparer", typeof(Comparer));
            var second   = "";

            if (Comparer != Comparer.Exists && Comparer != Comparer.DoesNotExist)
            {
                second = LineParser.ParseLiteral(ref cfLine, "STRING");
            }

            return(Condition.ReplaceAndVerify(first, Comparer, second, ls));
        }
Example #2
0
        /// <summary>
        /// Gets the Action that needs to be executed.
        /// </summary>
        static internal Action Parse(string line, LSGlobals ls)
        {
            var data  = ls.BotData;
            var input = line.Trim();
            var field = LineParser.ParseToken(ref input, TokenType.Parameter, true).ToUpper();

            return(new Action(() =>
            {
                switch (field)
                {
                case "SOURCE":
                    data.SOURCE = LineParser.ParseLiteral(ref input, "SOURCE", true, ls);
                    break;

                case "STATUS":
                    data.STATUS = LineParser.ParseToken(ref input, TokenType.Parameter, true);

                    // E.g. user wrote SET STATUS CUSTOM "TEST"
                    if (data.STATUS == "CUSTOM" && !string.IsNullOrEmpty(input))
                    {
                        data.STATUS = LineParser.ParseLiteral(ref input, "CUSTOM STATUS");
                    }
                    break;

                case "RESPONSECODE":
                    data.RESPONSECODE = LineParser.ParseInt(ref input, "RESPONSECODE");
                    break;

                case "COOKIE":
                    var name = LineParser.ParseLiteral(ref input, "NAME", true, ls);
                    data.COOKIES.Add(name, LineParser.ParseLiteral(ref input, "VALUE", true, ls));
                    break;

                case "ADDRESS":
                    data.ADDRESS = LineParser.ParseLiteral(ref input, "ADDRESS", true, ls);
                    break;

                case "USEPROXY":
                    var use = LineParser.ParseToken(ref input, TokenType.Parameter, true).ToUpper();

                    if (use == "TRUE")
                    {
                        data.UseProxy = true;
                    }
                    else if (use == "FALSE")
                    {
                        data.UseProxy = false;
                    }
                    break;

                case "PROXY":
                    var prox = LineParser.ParseLiteral(ref input, "PROXY", true, ls);
                    data.Proxy = Proxy.Parse(prox);
                    break;

                case "PROXYTYPE":
                    data.Proxy.Type = (ProxyType)LineParser.ParseEnum(ref input, "PROXYTYPE", typeof(ProxyType));
                    break;

                case "DATA":
                    data.Line.Data = LineParser.ParseLiteral(ref input, "DATA", true, ls);
                    break;

                case "VAR":
                    var varName = LineParser.ParseLiteral(ref input, "NAME", true, ls);
                    var varValue = LineParser.ParseLiteral(ref input, "VALUE", true, ls);
                    BlockBase.GetVariables(data).Set(new StringVariable(varValue)
                    {
                        Name = varName
                    });
                    break;

                case "CAP":
                    var capName = LineParser.ParseLiteral(ref input, "NAME", true, ls);
                    var capValue = LineParser.ParseLiteral(ref input, "VALUE", true, ls);
                    BlockBase.GetVariables(data).Set(new StringVariable(capValue)
                    {
                        Name = capName
                    });
                    data.MarkForCapture(capName);
                    break;

                case "GVAR":
                    try
                    {
                        var globalVarName = LineParser.ParseLiteral(ref input, "NAME", true, ls);
                        var globalVarValue = LineParser.ParseLiteral(ref input, "VALUE", true, ls);
                        ls.Globals.Set(new StringVariable(globalVarValue)
                        {
                            Name = globalVarName
                        });
                    }
                    catch
                    {
                    }
                    break;

                case "NEWGVAR":
                    try
                    {
                        var globalVarName = LineParser.ParseLiteral(ref input, "NAME", true, ls);
                        var globalVarValue = LineParser.ParseLiteral(ref input, "VALUE", true, ls);
                        ls.Globals.SetIfNew(new StringVariable(globalVarValue)
                        {
                            Name = globalVarName
                        });
                    }
                    catch
                    {
                    }
                    break;

                case "GCOOKIES":
                    ls.GlobalCookies.Clear();
                    foreach (var cookie in data.COOKIES)
                    {
                        ls.GlobalCookies.Add(cookie.Key, cookie.Value);
                    }
                    break;

                default:
                    throw new ArgumentException($"Invalid identifier {field}");
                }

                data.Logger.Log($"SET command executed on field {field}", LogColors.White);
            }));
        }
Example #3
0
        /// <summary>
        /// Executes a line of the script.
        /// </summary>
        /// <param name="data">The BotData needed for variable replacement</param>
        public async Task TakeStep(LSGlobals ls)
        {
            var data = ls.BotData;

            // TODO: Refactor this with a properly written policy
            // If we have a custom status without forced continue OR we have a status that is not NONE or SUCCESS or CUSTOM
            if (!CanContinue(data))
            {
                i = lines.Length; // Go to the end
                return;
            }

TAKELINE:

            CurrentLine = lines[i];

            // Skip comments and blank lines
            if (IsEmptyOrCommentOrDisabled(CurrentLine))
            {
                i++; // Go to the next
                goto TAKELINE;
            }

            // Lookahead to compact lines. We don't use CompressedLines to be able to provide the line number for errors
            var lookahead = 0;

            // Join the line with the following ones if it's indented
            while (i + 1 + lookahead < lines.Length)
            {
                var nextLine = lines[i + 1 + lookahead];

                if (nextLine.StartsWith(" ") || nextLine.StartsWith("\t"))
                {
                    CurrentLine += $" {nextLine.Trim()}";
                }
                else
                {
                    break;
                }

                lookahead++;
            }

            try
            {
                // If Block -> Process Block
                if (BlockParser.IsBlock(CurrentLine))
                {
                    BlockBase block = null;
                    try
                    {
                        block              = BlockParser.Parse(CurrentLine);
                        CurrentBlock       = block.Label;
                        data.ExecutionInfo = $"Executing block: {block.Label}";

                        if (!block.Disabled)
                        {
                            await block.Process(ls);
                        }
                    }
                    catch (Exception ex)
                    {
                        // We log the error message
                        var errorMessage = data.Providers.GeneralSettings.VerboseMode ? ex.ToString() : ex.Message;
                        data.Logger.Log("ERROR: " + errorMessage, LogColors.Tomato);

                        // Stop the execution only if the block is vital for the execution of the script (requests)
                        // This way we prevent the interruption of the script and an endless retry cycle e.g. if we fail to parse a response given a specific input
                        if (block != null && block is BlockRequest)
                        {
                            data.STATUS = "ERROR";
                            throw new BlockProcessingException(ex.Message);
                        }
                    }
                }

                // If Command -> Process Command
                else if (CommandParser.IsCommand(CurrentLine))
                {
                    try
                    {
                        var action = CommandParser.Parse(CurrentLine, ls);
                        action?.Invoke();
                    }
                    catch (Exception ex)
                    {
                        var errorMessage = data.Providers.GeneralSettings.VerboseMode ? ex.ToString() : ex.Message;
                        data.Logger.Log("ERROR: " + errorMessage, LogColors.Tomato);
                        data.STATUS = "ERROR";
                    }
                }

                // Try to Process Flow Control
                else
                {
                    var cfLine = CurrentLine;
                    var token  = LineParser.ParseToken(ref cfLine, TokenType.Parameter, false); // This proceeds, so we have the cfLine ready for next parsing

                    switch (token.ToUpper())
                    {
                    case "IF":
                        // Check condition, if not true jump to line after first ELSE or ENDIF (check both at the same time on lines, not separately)
                        if (!ParseCheckCondition(ref cfLine, ls))
                        {
                            i = ScanFor(lines, i, true, new string[] { "ENDIF", "ELSE" });
                            data.Logger.Log($"Jumping to line {i + 1}", LogColors.White);
                        }
                        break;

                    case "ELSE":
                        // Here jump to ENDIF because you are coming from an IF and you don't need to process the ELSE
                        i = ScanFor(lines, i, true, new string[] { "ENDIF" });
                        data.Logger.Log($"Jumping to line {i + 1}", LogColors.White);
                        break;

                    case "ENDIF":
                        break;

                    case "WHILE":
                        // Check condition, if false jump to first index after ENDWHILE
                        if (!ParseCheckCondition(ref cfLine, ls))
                        {
                            i = ScanFor(lines, i, true, new string[] { "ENDWHILE" });
                            data.Logger.Log($"Jumping to line {i + 1}", LogColors.White);
                        }
                        break;

                    case "ENDWHILE":
                        // Jump back to the previous WHILE index
                        i = ScanFor(lines, i, false, new string[] { "WHILE" }) - 1;
                        data.Logger.Log($"Jumping to line {i + 1}", LogColors.White);
                        break;

                    case "JUMP":
                        var label = "";
                        try
                        {
                            label = LineParser.ParseToken(ref cfLine, TokenType.Label, true);
                            i     = ScanFor(lines, -1, true, new string[] { $"{label}" }) - 1;
                            data.Logger.Log($"Jumping to line {i + 2}", LogColors.White);
                        }
                        catch { throw new Exception($"No block with label {label} was found"); }
                        break;

                    case "BEGIN":
                        var beginToken = LineParser.ParseToken(ref cfLine, TokenType.Parameter, true);
                        switch (beginToken.ToUpper())
                        {
                        case "SCRIPT":
                            language = (ScriptingLanguage)LineParser.ParseEnum(ref cfLine, "LANGUAGE", typeof(ScriptingLanguage));
                            var end = 0;
                            try
                            {
                                end = ScanFor(lines, i, true, new string[] { "END" }) - 1;
                            }
                            catch
                            {
                                throw new Exception("No 'END SCRIPT' specified");
                            }

                            otherScript = string.Join(Environment.NewLine, lines.Skip(i + 1).Take(end - i));
                            i           = end;
                            data.Logger.Log($"Jumping to line {i + 2}", LogColors.White);
                            break;
                        }
                        break;

                    case "END":
                        var endToken = LineParser.ParseToken(ref cfLine, TokenType.Parameter, true);
                        switch (endToken.ToUpper())
                        {
                        case "SCRIPT":
                            LineParser.EnsureIdentifier(ref cfLine, "->");
                            LineParser.EnsureIdentifier(ref cfLine, "VARS");
                            var outputs = LineParser.ParseLiteral(ref cfLine, "OUTPUTS");

                            try
                            {
                                if (otherScript != string.Empty)
                                {
                                    RunScript(otherScript, language, outputs, data);
                                }
                            }
                            catch (Exception ex)
                            {
                                var errorMessage = data.Providers.GeneralSettings.VerboseMode ? ex.ToString() : ex.Message;
                                data.Logger.Log($"The script failed to be executed: {errorMessage}", LogColors.Tomato);
                            }
                            break;
                        }
                        break;

                    default:
                        break;
                    }
                }
            }
            catch (BlockProcessingException)
            {
                // Rethrow the Block Processing Exception so the error can be displayed in the view above
                throw;
            }
            catch (Exception e)
            {
                // Catch inner and throw line exception
                throw new Exception($"Parsing Exception on line {i + 1}: {e.Message}");
            }

            i += 1 + lookahead;
        }
Example #4
0
        /// <summary>
        /// Gets the Action that needs to be executed.
        /// </summary>
        static internal Action Parse(string line, LSGlobals ls)
        {
            var data  = ls.BotData;
            var input = line.Trim();
            var field = LineParser.ParseToken(ref input, TokenType.Parameter, true).ToUpper();

            return(new Action(() =>
            {
                var name = "";
                var comparer = Comparer.EqualTo;

                switch (field)
                {
                case "COOKIE":
                    if (LineParser.Lookahead(ref input) == TokenType.Parameter)
                    {
                        comparer = (Comparer)LineParser.ParseEnum(ref input, "TYPE", typeof(Comparer));
                    }

                    name = LineParser.ParseLiteral(ref input, "NAME");

                    for (var i = 0; i < data.COOKIES.Count; i++)
                    {
                        var curr = data.COOKIES.ToList()[i].Key;

                        if (Condition.ReplaceAndVerify(curr, comparer, name, ls))
                        {
                            data.COOKIES.Remove(curr);
                        }
                    }
                    break;

                case "VAR":
                    if (LineParser.Lookahead(ref input) == TokenType.Parameter)
                    {
                        comparer = (Comparer)LineParser.ParseEnum(ref input, "TYPE", typeof(Comparer));
                    }

                    name = LineParser.ParseLiteral(ref input, "NAME");
                    BlockBase.GetVariables(data).RemoveAll(comparer, name, ls);
                    break;

                case "GVAR":
                    if (LineParser.Lookahead(ref input) == TokenType.Parameter)
                    {
                        comparer = (Comparer)LineParser.ParseEnum(ref input, "TYPE", typeof(Comparer));
                    }

                    name = LineParser.ParseLiteral(ref input, "NAME");

                    try
                    {
                        ls.Globals.RemoveAll(comparer, name, ls);
                    }
                    catch
                    {
                    }
                    break;

                default:
                    throw new ArgumentException($"Invalid identifier {field}");
                }

                data.Logger.Log($"DELETE command executed on field {field}", LogColors.White);
            }));
        }