Full Code of bytebutcher/burp-send-to for AI

master db1e378bbc5f cached
80 files
246.0 KB
60.3k tokens
417 symbols
1 requests
Download .txt
Showing preview only (275K chars total). Download the full file or copy to clipboard to get everything.
Repository: bytebutcher/burp-send-to
Branch: master
Commit: db1e378bbc5f
Files: 80
Total size: 246.0 KB

Directory structure:
gitextract_4gomkmw3/

├── .gitignore
├── BappDescription.html
├── BappManifest.bmf
├── README.md
└── burp-send-to-extension/
    ├── build.gradle
    ├── gradle/
    │   └── wrapper/
    │       ├── gradle-wrapper.jar
    │       └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle
    └── src/
        └── main/
            └── java/
                ├── burp/
                │   ├── BurpExtender.java
                │   ├── Cookie.java
                │   ├── IRequestInfoWrapper.java
                │   ├── IRequestResponseHolder.java
                │   ├── IResponseInfoWrapper.java
                │   ├── RequestInfoWrapper.java
                │   ├── RequestResponseHolder.java
                │   └── ResponseInfoWrapper.java
                ├── com/
                │   └── google/
                │       └── gson/
                │           └── typeadapters/
                │               └── RuntimeTypeAdapterFactory.java
                └── net/
                    └── bytebutcher/
                        └── burpsendtoextension/
                            ├── builder/
                            │   └── CommandBuilder.java
                            ├── executioner/
                            │   └── CommandExecutioner.java
                            ├── gui/
                            │   ├── CommandsChangeListener.java
                            │   ├── SendToAddAdvancedDialog.form
                            │   ├── SendToAddAdvancedDialog.java
                            │   ├── SendToAddAdvancedPlaceholderBehaviourPanel.form
                            │   ├── SendToAddAdvancedPlaceholderBehaviourPanel.java
                            │   ├── SendToAddDialog.form
                            │   ├── SendToAddDialog.java
                            │   ├── SendToContextMenu.java
                            │   ├── SendToContextMenuItem.java
                            │   ├── SendToPreviewDialog.form
                            │   ├── SendToPreviewDialog.java
                            │   ├── SendToRunInTerminalBehaviourChoiceDialog.form
                            │   ├── SendToRunInTerminalBehaviourChoiceDialog.java
                            │   ├── SendToTab.form
                            │   ├── SendToTab.java
                            │   ├── SendToTabSettingsContextMenu.java
                            │   ├── SendToTable.java
                            │   ├── SendToTableListener.java
                            │   ├── action/
                            │   │   └── SendToContextMenuItemAction.java
                            │   ├── listener/
                            │   │   └── ToolTipActionListener.java
                            │   └── util/
                            │       ├── DialogUtil.java
                            │       ├── SelectionUtil.java
                            │       └── WebUtil.java
                            ├── models/
                            │   ├── CommandObject.java
                            │   ├── Config.java
                            │   ├── Context.java
                            │   ├── ERunInTerminalBehaviour.java
                            │   ├── ERuntimeBehaviour.java
                            │   ├── Placeholders.java
                            │   └── placeholder/
                            │       ├── AbstractPlaceholder.java
                            │       ├── AbstractRequestInfoPlaceholder.java
                            │       ├── AbstractRequestPlaceholder.java
                            │       ├── AbstractRequestResponseInfoPlaceholder.java
                            │       ├── AbstractRequestResponsePlaceholder.java
                            │       ├── AbstractRequestResponsePlaceholderBase.java
                            │       ├── CookiesPlaceholder.java
                            │       ├── HostPlaceholder.java
                            │       ├── HttpBodyToFilePlaceholder.java
                            │       ├── HttpContentLengthPlaceholder.java
                            │       ├── HttpHeadersToFilePlaceholder.java
                            │       ├── HttpMethodPlaceholder.java
                            │       ├── HttpRequestResponsePlaceholder.java
                            │       ├── HttpStatusCodePlaceholder.java
                            │       ├── IPlaceholder.java
                            │       ├── IPlaceholderParser.java
                            │       ├── IPlaceholderParserFactory.java
                            │       ├── PortPlaceholder.java
                            │       ├── ProtocolPlaceholder.java
                            │       ├── SelectedTextPlaceholder.java
                            │       ├── SelectedTextToFilePlaceholder.java
                            │       ├── UrlPathPlaceholder.java
                            │       ├── UrlPlaceholder.java
                            │       ├── UrlQueryPlaceholder.java
                            │       └── behaviour/
                            │           ├── CommandSeparatedPlaceholderBehaviour.java
                            │           ├── FileSeparatedPlaceholderBehaviour.java
                            │           ├── IPlaceholderBehaviour.java
                            │           └── StringSeparatedPlaceholderBehaviour.java
                            └── utils/
                                ├── OsUtils.java
                                └── StringUtils.java

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
burp-send-to-extension/.idea
burp-send-to-extension/.gradle
burp-send-to-extension/build
burp-send-to-extension/out


================================================
FILE: BappDescription.html
================================================
<p>Adds a customizable "Send to..."-context-menu to your BurpSuite.</p>

<p><b>Configuration</b></p>

<p>After loading the extension the "Send to"-Tab contains all necessary options to configure the "Send to"-context-menu. </p>

<p>New context-menu-entries can be added using the "Add"-button. Each entry consists of following fields:</p>

<ul>
    <li><strong>Name:</strong> the name of the context-menu-entry</li>

    <li><strong>Command:</strong> the command to be executed. You can use following placeholders:

    <ul>
            <li><strong>%H:</strong> will be replaced with the host</li>

            <li><strong>%P:</strong> will be replaced with the port</li>

            <li><strong>%T:</strong> will be replaced with the protocol</li>

            <li><strong>%U:</strong> will be replaced with the url</li>

            <li><strong>%A:</strong> will be replaced with the url path</li>

            <li><strong>%Q:</strong> will be replaced with the url query</li>

            <li><strong>%C:</strong> will be replaced with the cookies</li>

            <li><strong>%M:</strong> will be replaced with the HTTP-method</li>

            <li><strong>%S:</strong> will be replaced with the selected text</li>

            <li><strong>%F:</strong> will be replaced with the path to a temporary file containing the selected text</li>

            <li><strong>%R:</strong> will be replaced with the path to a temporary file containing the content of the focused request/response</li>

            <li><strong>%E:</strong> will be replaced with the path to a temporary file containing the header of the focused request/response</li>

            <li><strong>%B:</strong> will be replaced with the path to a temporary file containing the body of the focused request/response</li>
    </ul>

    <li><strong>Run in terminal:</strong> defines whether a terminal-window should appear in which the configured command is executed. By default "xterm" is used as terminal-emulator. You can change the terminal-emulator in the "Terminal Options" to your liking.</li>

    <li><strong>Show preview:</strong> gives you the chance to preview and change the command before executing it</li>

    <li><strong>Output should replace selection:</strong> will replace the selection with the output of the to be executed command</li>
</ul>

<p>
In addition it is possible to customize how placeholders behave when multiple HTTP messages are selected by clicking the "Advanced"-button.
By default each selected HTTP message forms a separate command. However, it is also possible to join all values of a specific placeholder using a custom separator.
</p>

<p>After creating new context-menu-entries using the "Add"-button they can be edited or deleted again using the "Edit"- and "Remove"-button. In addition the order in which they appear in the context-menu can be altered using the "Up"- and "Down"-button.</p>

<p><b>Terminal Options</b></p>

<p>
The "Terminal Options" allow to configure the graphical terminal to use. In addition it is possible to specify how multiple commands should be run in terminal. Multiple commands can either be run sequential in a single terminal or in parallel in separate terminals. While it's possible to choose a default behaviour, the exact behaviour can also be selected via a dialog, everytime a send-to context menu entry is selected. However, if you prefer one behaviour all the time, this dialog can also be disabled.
</p>

<p><b>Context-Menu</b></p>

<p>The "Send to..." context-menu contains all entries which were added in the "Send to"-Tab.
    In addition you can add new entries via the "Custom command..."-context-menu-entry.</p>

<p><b>Save and load options</b></p>

<p>Usually the options of the "Send to"-Tab are saved automatically. However, if you switch computers you may save and load your current options. This can be done by clicking on the gear-symbol in the upper-left corner of the "Send to"-Tab and select the appropriate context-menu-entry.</p>

<p><b>Security Notes</b></p>

<p>Executing commands based on untrusted input always introduces the risk of command injection. This is especially true when using the <strong>%S</strong> placeholder. Thus it is recommended to always activate the <strong>Show preview</strong> option when using the <strong>%S</strong> placeholder and closely analyse commands in the preview window prior to execution.</p>



================================================
FILE: BappManifest.bmf
================================================
Uuid: f089f1ad056545489139cb9f32900f8e
ExtensionType: 1
Name: Custom Send To
RepoName: custom-send-to
ScreenVersion: 1.4
SerialVersion: 1
MinPlatformVersion: 0
ProOnly: False
Author: Thomas Engel
ShortDescription: Add a customizable "Send to..." menu to the context menu
EntryPoint: burp-send-to-extension/build/libs/burp-send-to-extension-1.4.jar
BuildCommand: cd burp-send-to-extension; ./gradlew fatJar


================================================
FILE: README.md
================================================
# Burp-Send-To-Extension

Adds a customizable "Send to..."-context-menu to your BurpSuite.

![Burp-Send-To-Extension Tab](images/burp-send-to-extension-intro.png)

## Configuration

After loading the extension the "Send to"-Tab contains all necessary options to configure the "Send to"-context-menu. 

New context-menu-entries can be added using the "Add"-button. Each entry consists of following fields:
* **Name:** the name of the context-menu-entry.
* **Command:** the command to be executed. You can use following placeholders:
	* **%H:** will be replaced with the host
	* **%P:** will be replaced with the port
	* **%T:** will be replaced with the protocol
	* **%U:** will be replaced with the url
	* **%A:** will be replaced with the url path
	* **%Q:** will be replaced with the url query
	* **%C:** will be replaced with the cookies
	* **%L:** will be replaced with the HTTP-content-length
	* **%M:** will be replaced with the HTTP-method
	* **%O:** will be replaced with the HTTP-status-code
	* **%S:** will be replaced with the selected text
	* **%F:** will be replaced with the path to a temporary file containing the selected text
	* **%R:** will be replaced with the path to a temporary file containing the content of the focused request/response
	* **%E:** will be replaced with the path to a temporary file containing the header of the focused request/response
	* **%B:** will be replaced with the path to a temporary file containing the body of the focused request/response
* **Group:** the name of the sub-menu in which this entry will be shown. Can be left blank.
* **Run in terminal:** defines whether a terminal-window should appear in which the configured command is executed. By default "xterm" is used as terminal-emulator. You can change the terminal-emulator in the "Miscellaneous Options" to your liking.
* **Show preview:** gives you the chance to preview and change the command before executing it.
* **Output should replace selection:** will replace the selection with the output of the to be executed command.

![Burp-Send-To-Extension Add-/Edit-Dialog](images/burp-send-to-extension-add-edit-dialog.png)

In addition it is possible to customize how placeholders behave when multiple HTTP messages are selected by clicking the "Advanced"-button. 
By default each selected HTTP message forms a separate command. However, it is also possible to join all values of a specific placeholder using a custom separator, or to store all values of a specific placeholder within a file.

![Burp-Send-To-Extension Advanced-Dialog](images/burp-send-to-extension-advanced-dialog.png)

After creating new context-menu-entries using the "Add"-button they can be edited or deleted again using the "Edit"- and "Remove"-button. In addition the order in which they appear in the context-menu can be altered using the "Up"- and "Down"-button.

![Burp-Send-To-Extension Tab](images/burp-send-to-extension-tab.png)

## Terminal Options

The "Terminal Options" allow to configure the graphical terminal to use. In addition it is possible to specify how multiple commands should be run in terminal. Multiple commands can either be run sequential in a single terminal or in parallel in separate terminals. While it's possible to choose a default behaviour, the exact behaviour can also be selected via a dialog, everytime a send-to context menu entry is selected. However, if you prefer one behaviour all the time, this dialog can also be disabled.

## Context-Menu

The "Send to..." context-menu contains all entries which were added in the "Send to"-Tab.
In addition you can add new entries via the "Custom command..."-context-menu-entry.

#### Request Field

![Burp-Send-To-Extension Context-Menu](images/burp-send-to-extension-context-menu-repeater.png)

#### Proxy History

![Burp-Send-To-Extension Context-Menu](images/burp-send-to-extension-context-menu-target-sitemap.png)

## Save and load options

Usually the options of the "Send to"-Tab are saved automatically. However, if you switch computers you may save and load your current options. This can be done by clicking on the gear-symbol in the upper-left corner of the "Send to"-Tab and select the appropriate context-menu-entry.

![Burp-Send-To-Extension Options](images/burp-send-to-extension-options.png)

## Extending the Extension

Not satisfied yet? The [Wiki Page](https://github.com/bytebutcher/burp-send-to/wiki/Examples) lists some additional context-menu entries which might come in handy.

## Security Notes

Executing commands based on untrusted input always introduces the risk of command injection. This is especially true when using the **%S** placeholder. Thus it is recommended to always activate the **Show preview** option when using the **%S** placeholder and closely analyse commands in the preview window prior to execution.

![Burp-Send-To-Extension Options](images/burp-send-to-extension-forkbomb.png)

## Build

This project was built using IntelliJ and Gradle. When you make changes to the source (and especially the GUI) you should apply following settings within Intellij to make sure that everything builds successfully:
* File -> Settings -> Editor -> GUI Designer -> Generate GUI into: Java source
* File -> Settings -> Build, Execution, Deployment -> Compiler -> Build project automatically
* File -> Settings -> Build, Execution, Deployment -> Build Tools -> Gradle -> Build and run using: IntelliJ IDEA

When the GUI is not updated correctly you may rebuild the project manually:
* Build -> Rebuild Project

After that you can execute the "fatJar"-task within the "build.gradle"-file. This will produce a jar in the "build/libs/" directory called "burp-send-to-extension-{version}.jar".


================================================
FILE: burp-send-to-extension/build.gradle
================================================
apply plugin: 'java'

group 'net.bytebutcher'
version '1.6'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    compile 'com.intellij:forms_rt:7.0.3'
    compile 'net.portswigger.burp.extender:burp-extender-api:1.7.22'
    compile group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
    compile group: 'com.google.guava', name: 'guava', version: '27.0.1-jre'

}

task fatJar(type: Jar) {
    baseName = project.name
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}


================================================
FILE: burp-send-to-extension/gradle/wrapper/gradle-wrapper.properties
================================================
#Sun Mar 17 11:46:47 CET 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip


================================================
FILE: burp-send-to-extension/gradlew
================================================
#!/usr/bin/env sh

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn () {
    echo "$*"
}

die () {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
  NONSTOP* )
    nonstop=true
    ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Escape application args
save () {
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
    echo " "
}
APP_ARGS=$(save "$@")

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
  cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"


================================================
FILE: burp-send-to-extension/gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windows variants

if not "%OS%" == "Windows_NT" goto win9xME_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: burp-send-to-extension/settings.gradle
================================================
rootProject.name = 'burp-send-to-extension'



================================================
FILE: burp-send-to-extension/src/main/java/burp/BurpExtender.java
================================================
package burp;

import net.bytebutcher.burpsendtoextension.gui.SendToContextMenu;
import net.bytebutcher.burpsendtoextension.gui.SendToTab;
import net.bytebutcher.burpsendtoextension.gui.SendToTable;
import net.bytebutcher.burpsendtoextension.models.Config;

import javax.swing.*;
import java.awt.*;
import java.io.PrintWriter;

public class BurpExtender implements IBurpExtender, ITab {

    private JPanel tab = null;
    private SendToContextMenu sendToContextMenu;
    private SendToTable sendToTable;

    private static IBurpExtenderCallbacks callbacks;
    private static Config config;
    private static SendToTab sendToTab = null;

    private static PrintWriter stdout;
    private static PrintWriter stderr;

    @Override
    public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
        BurpExtender.callbacks = callbacks;
        initLogHandler(callbacks);
        BurpExtender.printOut("Initializing Send to Extension...");
        BurpExtender.callbacks.setExtensionName("Send to");
        BurpExtender.printOut("Initializing config...");
        BurpExtender.config = new Config(this);
        BurpExtender.printOut("Initializing tab...");
        BurpExtender.sendToTab = new SendToTab(this);
        BurpExtender.printOut("Registering context menu...");
        this.sendToContextMenu = new SendToContextMenu(this, sendToTab.getSendToTableListener());
        BurpExtender.callbacks.registerContextMenuFactory(sendToContextMenu);
        this.tab = sendToTab.getRootPanel();
        BurpExtender.printOut("Loading table data...");
        this.sendToTable = sendToTab.getSendToTable();
        this.sendToTable.addCommandObjects(config.getSendToTableData());
        callbacks.addSuiteTab(this);
        BurpExtender.printOut("----------------------------------------------------------------------");
    }

    private void initLogHandler(IBurpExtenderCallbacks callbacks) {
        stderr = new PrintWriter(callbacks.getStderr(), true);
        stdout = new PrintWriter(callbacks.getStdout(), true);
    }

    @Override
    public String getTabCaption() {
        return "Send to";
    }

    @Override
    public Component getUiComponent() {
        return this.tab;
    }

    public ImageIcon createImageIcon(String path, String description, int width, int height) {
        java.net.URL imgURL = getClass().getResource(path);
        if (imgURL != null) {
            ImageIcon icon = new ImageIcon(imgURL);
            Image image = icon.getImage().getScaledInstance(width, height,  Image.SCALE_SMOOTH);
            return new ImageIcon(image, description);
        } else {
            BurpExtender.printErr("Couldn't find file: " + path);
            return null;
        }
    }

    public static JFrame getParent() {
        return sendToTab.getParent();
    }

    public static IBurpExtenderCallbacks getCallbacks() {
        return callbacks;
    }

    public static Config getConfig() {
        return config;
    }

    public static void printOut(String s) {
        stdout.println(s);
    }

    public static void printErr(String s) {
        stderr.println(s);
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/burp/Cookie.java
================================================
package burp;

import com.google.common.collect.Lists;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Implements the ICookie interface which holds details about an HTTP cookie.
 * @author Thomas Engel
 * @author August Detlefsen [augustd at codemagi dot com]
 */
public class Cookie implements ICookie {

    private String name;
    private String value;
    private String domain;
    private String path;
    private Date expiration;
    private Long maxAge;
    private Boolean secure = false;
    private Boolean httpOnly = false;

    public Cookie(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public Cookie(ICookie cookie) {
        this.name = cookie.getName();
        this.value = cookie.getValue();
        this.domain = cookie.getDomain();
        this.path = cookie.getPath();
        this.expiration = cookie.getExpiration();
    }

    /**
     * Parses a list of HTTP response header fields containing the raw cookie
     * _value_ (Minus "Set-Cookie:").
     *
     * @param rawCookies A list of string containing the raw cookie
     * @return A list of ICookie objects parsed from a list of raw cookie strings
     */
    public static List<ICookie> parseResponseCookies(List<String> rawCookies) {
        return rawCookies.stream().map(Cookie::parseResponseCookie).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
    }

    /**
     * Parses a cookie from a String containing the raw HTTP response header
     * _value_ (Minus "Set-Cookie:").
     *
     * @param rawCookie A String containing the raw cookie
     * @return A Cookie object parsed from the raw cookie string
     */
    private static Optional<ICookie> parseResponseCookie(String rawCookie) {
        String[] rawCookieParams = rawCookie.split(";");

        //get the cookie name, check for valid cookie
        String[] rawCookieNameAndValue = rawCookieParams[0].split("=");
        String cookieName = rawCookieNameAndValue[0].trim();
        if (cookieName.isEmpty()) {
            BurpExtender.printErr("Invalid cookie: missing name");
            return Optional.empty();
        }

        //get the cookie value
        String cookieValue = rawCookieNameAndValue[1].trim();

        //construct output
        Cookie output = new Cookie(cookieName, cookieValue);

        //parse other cookie params
        for (int i = 1; i < rawCookieParams.length; i++) {
            String[] rawCookieParam = rawCookieParams[i].trim().split("=");

            String paramName = rawCookieParam[0].trim();

            if ("secure".equalsIgnoreCase(paramName)) {
                output.setSecure(true);

            } else if ("HttpOnly".equalsIgnoreCase(paramName)) {
                output.setHttpOnly(true);

            } else {
                if (rawCookieParam.length != 2) {
                    //attribute not a flag or missing value
                    continue;
                }
                String paramValue = rawCookieParam[1].trim();

                if ("expires".equalsIgnoreCase(paramName)) {
                    try {
                        SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss zzz");
                        Date expiryDate = format.parse(paramValue);
                        output.setExpiration(expiryDate);
                    } catch (Exception e) {
                        //couldn't parse date, ignore
                        BurpExtender.printErr("WARNING: unable to parse cookie expiration: " + paramValue);
                    }
                } else if ("max-age".equalsIgnoreCase(paramName)) {
                    long maxAge = Long.parseLong(paramValue);
                    output.setMaxAge(maxAge);
                } else if ("domain".equalsIgnoreCase(paramName)) {
                    output.setDomain(paramValue);
                } else if ("path".equalsIgnoreCase(paramName)) {
                    output.setPath(paramValue);
                }
            }
        }

        return Optional.of(output);
    }

    /**
     * Parses cookies from a list of raw HTTP request headers
     * _value_ (Minus "Cookie:").
     *
     * @param rawCookies A list of strings containing the raw cookie
     * @return A list of ICookie objects parsed from a list of raw cookie strings
     */
    public static List<ICookie> parseRequestCookies(List<String> rawCookies) {
        return rawCookies.stream().map(Cookie::parseRequestCookies).flatMap(Collection::stream).collect(Collectors.toList());
    }

    /**
     * Parses a cookie from a String containing the raw HTTP request header
     * _value_ (Minus "Cookie:").
     *
     * @param rawCookie A String containing the raw cookie
     * @return A list of Cookie objects parsed from the raw cookie string
     */
    public static List<ICookie> parseRequestCookies(String rawCookie) {
        List<ICookie> cookies = Lists.newArrayList();
        String[] rawCookieParams = rawCookie.split(";");
        for (String rawCookieParam : rawCookieParams) {
            //get the cookie name, check for valid cookie
            String[] rawCookieNameAndValue = rawCookieParam.split("=");
            String cookieName = rawCookieNameAndValue[0].trim();
            if (cookieName.isEmpty() || !rawCookieParam.contains("=")) {
                BurpExtender.printErr("Invalid cookie: missing name");
                continue;
            }

            //get the cookie value
            String cookieValue = "";
            if (rawCookieNameAndValue.length != 1) {
                cookieValue = rawCookieNameAndValue[1].trim();
            }

            //construct output
            cookies.add(new Cookie(cookieName, cookieValue));
        }

        return cookies;
    }

    @Override
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String getDomain() {
        return domain;
    }

    public void setDomain(String domain) {
        this.domain = domain;
    }

    @Override
    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    @Override
    public Date getExpiration() {
        return expiration;
    }

    public void setExpiration(Date expiration) {
        this.expiration = expiration;
    }

    public Long getMaxAge() {
        return maxAge;
    }

    public void setMaxAge(Long maxAge) {
        this.maxAge = maxAge;
    }

    public Boolean getSecure() {
        return secure;
    }

    public void setSecure(Boolean secure) {
        this.secure = secure;
    }

    public Boolean getHttpOnly() {
        return httpOnly;
    }

    public void setHttpOnly(Boolean httpOnly) {
        this.httpOnly = httpOnly;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Cookie cookie = (Cookie) o;
        return Objects.equals(name, cookie.name) &&
                Objects.equals(value, cookie.value) &&
                Objects.equals(domain, cookie.domain) &&
                Objects.equals(path, cookie.path) &&
                Objects.equals(expiration, cookie.expiration) &&
                Objects.equals(maxAge, cookie.maxAge) &&
                Objects.equals(secure, cookie.secure) &&
                Objects.equals(httpOnly, cookie.httpOnly);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, value, domain, path, expiration, maxAge, secure, httpOnly);
    }
}

================================================
FILE: burp-send-to-extension/src/main/java/burp/IRequestInfoWrapper.java
================================================
package burp;

import java.util.List;

public interface IRequestInfoWrapper extends IRequestInfo {

    List<ICookie> getCookies();
    String getBody();

}


================================================
FILE: burp-send-to-extension/src/main/java/burp/IRequestResponseHolder.java
================================================
package burp;

public interface IRequestResponseHolder {
    IRequestInfo getRequestInfo();

    IResponseInfo getResponseInfo();

    IBurpExtenderCallbacks getBurpExtenderCallbacks();

    IHttpRequestResponse getHttpRequestResponse();
}


================================================
FILE: burp-send-to-extension/src/main/java/burp/IResponseInfoWrapper.java
================================================
package burp;

import java.util.List;

public interface IResponseInfoWrapper extends IResponseInfo {

    List<ICookie> getCookies();
    String getBody();

}


================================================
FILE: burp-send-to-extension/src/main/java/burp/RequestInfoWrapper.java
================================================
package burp;

import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class RequestInfoWrapper implements IRequestInfoWrapper {

    private IHttpRequestResponse httpRequestResponse;
    private IRequestInfo requestInfo;
    private List<ICookie> cookies;
    private String requestBody;

    public RequestInfoWrapper(IHttpRequestResponse httpRequestResponse, IRequestInfo requestInfo) {
        this.httpRequestResponse = httpRequestResponse;
        this.requestInfo = requestInfo;
    }

    @Override
    public List<ICookie> getCookies() {
        if (cookies == null) {
            String cookieHeaderPrefix = "cookie: ";
            cookies = Cookie.parseRequestCookies(requestInfo.getHeaders().stream().filter(s -> s.toLowerCase().startsWith(cookieHeaderPrefix)).map(s -> s.substring(cookieHeaderPrefix.length() - 1)).collect(Collectors.toList()));
        }
        return cookies;
    }

    @Override
    public String getBody() {
        if (requestBody == null) {
            byte[] request = httpRequestResponse.getRequest();
            int bodyOffset = this.getBodyOffset();
            requestBody = new String(Arrays.copyOfRange(request, bodyOffset, request.length));
        }
        return requestBody;
    }

    @Override
    public String getMethod() {
        return requestInfo.getMethod();
    }

    @Override
    public URL getUrl() {
        return requestInfo.getUrl();
    }

    @Override
    public List<String> getHeaders() {
        return requestInfo.getHeaders();
    }

    @Override
    public List<IParameter> getParameters() {
        return requestInfo.getParameters();
    }

    @Override
    public int getBodyOffset() {
        return requestInfo.getBodyOffset();
    }

    @Override
    public byte getContentType() {
        return requestInfo.getContentType();
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/burp/RequestResponseHolder.java
================================================
package burp;

public class RequestResponseHolder implements IRequestResponseHolder {

    private final IBurpExtenderCallbacks burpExtenderCallbacks;
    private final IHttpRequestResponse httpRequestResponse;
    private IRequestInfoWrapper requestInfo;
    private IResponseInfoWrapper responseInfo;

    public RequestResponseHolder(IBurpExtenderCallbacks burpExtenderCallbacks, IHttpRequestResponse httpRequestResponse) {
        this.burpExtenderCallbacks = burpExtenderCallbacks;
        this.httpRequestResponse = httpRequestResponse;
    }

    @Override
    public IRequestInfoWrapper getRequestInfo() {
        if (requestInfo == null) {
            requestInfo = new RequestInfoWrapper(httpRequestResponse, burpExtenderCallbacks.getHelpers().analyzeRequest(httpRequestResponse.getHttpService(), httpRequestResponse.getRequest()));
        }
        return requestInfo;
    }

    @Override
    public IResponseInfoWrapper getResponseInfo() {
        if (responseInfo == null) {
            responseInfo = new ResponseInfoWrapper(httpRequestResponse, burpExtenderCallbacks.getHelpers().analyzeResponse(httpRequestResponse.getResponse()));
        }
        return responseInfo;
    }

    @Override
    public IBurpExtenderCallbacks getBurpExtenderCallbacks() {
        return burpExtenderCallbacks;
    }

    @Override
    public IHttpRequestResponse getHttpRequestResponse() {
        return httpRequestResponse;
    }

}


================================================
FILE: burp-send-to-extension/src/main/java/burp/ResponseInfoWrapper.java
================================================
package burp;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ResponseInfoWrapper implements IResponseInfoWrapper {

    private IHttpRequestResponse httpRequestResponse;
    private IResponseInfo responseInfo;
    private List<ICookie> cookies;
    private String responseBody;

    public ResponseInfoWrapper(IHttpRequestResponse httpRequestResponse, IResponseInfo responseInfo) {
        this.httpRequestResponse = httpRequestResponse;
        this.responseInfo = responseInfo;
    }

    @Override
    public List<String> getHeaders() {
        return responseInfo.getHeaders();
    }

    @Override
    public int getBodyOffset() {
        return responseInfo.getBodyOffset();
    }

    @Override
    public short getStatusCode() {
        return responseInfo.getStatusCode();
    }

    @Override
    public List<ICookie> getCookies() {
        if (cookies == null) {
            String cookieHeaderPrefix = "set-cookie: ";
            cookies = Cookie.parseResponseCookies(responseInfo.getHeaders().stream().filter(s -> s.toLowerCase().startsWith(cookieHeaderPrefix)).map(s -> s.substring(cookieHeaderPrefix.length() - 1)).collect(Collectors.toList()));
        }
        return cookies;
    }

    @Override
    public String getStatedMimeType() {
        return responseInfo.getStatedMimeType();
    }

    @Override
    public String getInferredMimeType() {
        return responseInfo.getInferredMimeType();
    }

    @Override
    public String getBody() {
        if (responseBody == null) {
            byte[] response = httpRequestResponse.getResponse();
            int bodyOffset = this.getBodyOffset();
            responseBody = new String(Arrays.copyOfRange(response, bodyOffset, response.length));
        }
        return responseBody;
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java
================================================
/*
 * Copyright (C) 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.gson.typeadapters;

import com.google.gson.*;
import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Adapts values whose runtime type may differ from their declaration type. This
 * is necessary when a field's type is not the same type that GSON should create
 * when deserializing that field. For example, consider these types:
 * <pre>   {@code
 *   abstract class Shape {
 *     int x;
 *     int y;
 *   }
 *   class Circle extends Shape {
 *     int radius;
 *   }
 *   class Rectangle extends Shape {
 *     int width;
 *     int height;
 *   }
 *   class Diamond extends Shape {
 *     int width;
 *     int height;
 *   }
 *   class Drawing {
 *     Shape bottomShape;
 *     Shape topShape;
 *   }
 * }</pre>
 * <p>Without additional type information, the serialized JSON is ambiguous. Is
 * the bottom shape in this drawing a rectangle or a diamond? <pre>   {@code
 *   {
 *     "bottomShape": {
 *       "width": 10,
 *       "height": 5,
 *       "x": 0,
 *       "y": 0
 *     },
 *     "topShape": {
 *       "radius": 2,
 *       "x": 4,
 *       "y": 1
 *     }
 *   }}</pre>
 * This class addresses this problem by adding type information to the
 * serialized JSON and honoring that type information when the JSON is
 * deserialized: <pre>   {@code
 *   {
 *     "bottomShape": {
 *       "type": "Diamond",
 *       "width": 10,
 *       "height": 5,
 *       "x": 0,
 *       "y": 0
 *     },
 *     "topShape": {
 *       "type": "Circle",
 *       "radius": 2,
 *       "x": 4,
 *       "y": 1
 *     }
 *   }}</pre>
 * Both the type field name ({@code "type"}) and the type labels ({@code
 * "Rectangle"}) are configurable.
 *
 * <h3>Registering Types</h3>
 * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field
 * name to the {@link #of} factory method. If you don't supply an explicit type
 * field name, {@code "type"} will be used. <pre>   {@code
 *   RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory
 *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
 * }</pre>
 * Next register all of your subtypes. Every subtype must be explicitly
 * registered. This protects your application from injection attacks. If you
 * don't supply an explicit type label, the type's simple name will be used.
 * <pre>   {@code
 *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
 *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
 *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
 * }</pre>
 * Finally, register the type adapter factory in your application's GSON builder:
 * <pre>   {@code
 *   Gson gson = new GsonBuilder()
 *       .registerTypeAdapterFactory(shapeAdapterFactory)
 *       .create();
 * }</pre>
 * Like {@code GsonBuilder}, this API supports chaining: <pre>   {@code
 *   RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
 *       .registerSubtype(Rectangle.class)
 *       .registerSubtype(Circle.class)
 *       .registerSubtype(Diamond.class);
 * }</pre>
 *
 * <h3>Serialization and deserialization</h3>
 * In order to serialize and deserialize a polymorphic object,
 * you must specify the base type explicitly.
 * <pre>   {@code
 *   Diamond diamond = new Diamond();
 *   String json = gson.toJson(diamond, Shape.class);
 * }</pre>
 * And then:
 * <pre>   {@code
 *   Shape shape = gson.fromJson(json, Shape.class);
 * }</pre>
 */
public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory {
  private final Class<?> baseType;
  private final String typeFieldName;
  private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<String, Class<?>>();
  private final Map<Class<?>, String> subtypeToLabel = new LinkedHashMap<Class<?>, String>();
  private final boolean maintainType;

  private RuntimeTypeAdapterFactory(Class<?> baseType, String typeFieldName, boolean maintainType) {
    if (typeFieldName == null || baseType == null) {
      throw new NullPointerException();
    }
    this.baseType = baseType;
    this.typeFieldName = typeFieldName;
    this.maintainType = maintainType;
  }

  /**
   * Creates a new runtime type adapter using for {@code baseType} using {@code
   * typeFieldName} as the type field name. Type field names are case sensitive.
   * {@code maintainType} flag decide if the type will be stored in pojo or not.
   */
  public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName, boolean maintainType) {
    return new RuntimeTypeAdapterFactory<T>(baseType, typeFieldName, maintainType);
  }
  
  /**
   * Creates a new runtime type adapter using for {@code baseType} using {@code
   * typeFieldName} as the type field name. Type field names are case sensitive.
   */
  public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, String typeFieldName) {
    return new RuntimeTypeAdapterFactory<T>(baseType, typeFieldName, false);
  }

  /**
   * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as
   * the type field name.
   */
  public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType) {
    return new RuntimeTypeAdapterFactory<T>(baseType, "type", false);
  }

  /**
   * Registers {@code type} identified by {@code label}. Labels are case
   * sensitive.
   *
   * @throws IllegalArgumentException if either {@code type} or {@code label}
   *     have already been registered on this type adapter.
   */
  public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type, String label) {
    if (type == null || label == null) {
      throw new NullPointerException();
    }
    if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) {
      throw new IllegalArgumentException("types and labels must be unique");
    }
    labelToSubtype.put(label, type);
    subtypeToLabel.put(type, label);
    return this;
  }

  /**
   * Registers {@code type} identified by its {@link Class#getSimpleName simple
   * name}. Labels are case sensitive.
   *
   * @throws IllegalArgumentException if either {@code type} or its simple name
   *     have already been registered on this type adapter.
   */
  public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) {
    return registerSubtype(type, type.getSimpleName());
  }

  public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {
    if (type.getRawType() != baseType) {
      return null;
    }

    final Map<String, TypeAdapter<?>> labelToDelegate
        = new LinkedHashMap<String, TypeAdapter<?>>();
    final Map<Class<?>, TypeAdapter<?>> subtypeToDelegate
        = new LinkedHashMap<Class<?>, TypeAdapter<?>>();
    for (Map.Entry<String, Class<?>> entry : labelToSubtype.entrySet()) {
      TypeAdapter<?> delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue()));
      labelToDelegate.put(entry.getKey(), delegate);
      subtypeToDelegate.put(entry.getValue(), delegate);
    }

    return new TypeAdapter<R>() {
      @Override public R read(JsonReader in) throws IOException {
        JsonElement jsonElement = Streams.parse(in);
        JsonElement labelJsonElement;
        if (maintainType) {
            labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName);
        } else {
            labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName);
        }
        
        if (labelJsonElement == null) {
          throw new JsonParseException("cannot deserialize " + baseType
              + " because it does not define a field named " + typeFieldName);
        }
        String label = labelJsonElement.getAsString();
        @SuppressWarnings("unchecked") // registration requires that subtype extends T
        TypeAdapter<R> delegate = (TypeAdapter<R>) labelToDelegate.get(label);
        if (delegate == null) {
          throw new JsonParseException("cannot deserialize " + baseType + " subtype named "
              + label + "; did you forget to register a subtype?");
        }
        return delegate.fromJsonTree(jsonElement);
      }

      @Override public void write(JsonWriter out, R value) throws IOException {
        Class<?> srcType = value.getClass();
        String label = subtypeToLabel.get(srcType);
        @SuppressWarnings("unchecked") // registration requires that subtype extends T
        TypeAdapter<R> delegate = (TypeAdapter<R>) subtypeToDelegate.get(srcType);
        if (delegate == null) {
          throw new JsonParseException("cannot serialize " + srcType.getName()
              + "; did you forget to register a subtype?");
        }
        JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();

        if (maintainType) {
          Streams.write(jsonObject, out);
          return;
        }

        JsonObject clone = new JsonObject();

        if (jsonObject.has(typeFieldName)) {
          throw new JsonParseException("cannot serialize " + srcType.getName()
              + " because it already defines a field named " + typeFieldName);
        }
        clone.add(typeFieldName, new JsonPrimitive(label));
        
        for (Map.Entry<String, JsonElement> e : jsonObject.entrySet()) {
          clone.add(e.getKey(), e.getValue());
        }
        Streams.write(clone, out);
      }
    }.nullSafe();
  }
}

================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/builder/CommandBuilder.java
================================================
package net.bytebutcher.burpsendtoextension.builder;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.bytebutcher.burpsendtoextension.models.CommandObject;
import net.bytebutcher.burpsendtoextension.models.Context;
import net.bytebutcher.burpsendtoextension.models.placeholder.IPlaceholderParser;
import net.bytebutcher.burpsendtoextension.models.placeholder.behaviour.CommandSeparatedPlaceholderBehaviour;
import net.bytebutcher.burpsendtoextension.models.placeholder.behaviour.FileSeparatedPlaceholderBehaviour;
import net.bytebutcher.burpsendtoextension.models.placeholder.behaviour.IPlaceholderBehaviour;
import net.bytebutcher.burpsendtoextension.models.placeholder.behaviour.StringSeparatedPlaceholderBehaviour;

import java.io.File;
import java.io.PrintWriter;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class CommandBuilder {

    // The model of the context menu entry with the format string and various options.
    private final CommandObject commandObject;

    // List of selected messages containing the placeholders and their values.
    private final List<Map<String, IPlaceholderParser>> placeholderMap;

    // List of placeholders and merged values.
    private final Map<Placeholder, String> placeholderValues;

    private final Context context;

    private static class Placeholder {

        private final String name;
        private final IPlaceholderBehaviour behaviour;

        public Placeholder(CommandObject.Placeholder placeholder) {
            this.name = placeholder.getName();
            this.behaviour = placeholder.getBehaviour();
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Placeholder that = (Placeholder) o;
            return Objects.equals(name, that.name) && Objects.equals(behaviour, that.behaviour);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, behaviour);
        }
    }

    public CommandBuilder(CommandObject commandObject, List<Map<String, IPlaceholderParser>> placeholderMap, Context context) throws Exception {
        this.commandObject = commandObject;
        this.placeholderMap = placeholderMap;
        this.context = context;
        this.placeholderValues = initPlaceholderValues();
    }

    public Map<Placeholder, String> initPlaceholderValues() throws Exception {
        Map<Placeholder, String> placeholderValues = Maps.newHashMap();
        for (CommandObject.Placeholder coPlaceholder : commandObject.getPlaceholders()) {
            Placeholder cbPlaceholder = new Placeholder(coPlaceholder);
            if (!placeholderValues.containsKey(cbPlaceholder)) {
                if (coPlaceholder.getBehaviour() instanceof StringSeparatedPlaceholderBehaviour){
                    // combine the values of all messages using the defined placeholder separator
                    placeholderValues.put(cbPlaceholder, commandObject.getValid(placeholderMap, context).stream()
                            .map(m -> m.get(coPlaceholder.getName()))
                            .map(iPlaceholder -> iPlaceholder.getValue(context))
                            .collect(Collectors.joining(((StringSeparatedPlaceholderBehaviour) coPlaceholder.getBehaviour()).getSeparator())));
                } else if (coPlaceholder.getBehaviour() instanceof FileSeparatedPlaceholderBehaviour){
                    // combine the values of all messages and write them into a file.
                    placeholderValues.put(cbPlaceholder, writeToFile(commandObject.getValid(placeholderMap, context).stream()
                            .map(m -> m.get(coPlaceholder.getName()))
                            .map(iPlaceholder -> iPlaceholder.getValue(context))
                            .collect(Collectors.joining("\n"))));
                }
            }
        }
        return placeholderValues;
    }

    /**
     * Returns the command while all placeholders are replaced with their associated value as String.
     * @throws Exception when retrieving/replacing a placeholder failed.
     */
    public String build() throws Exception {
        try {
            List<String> result = Lists.newArrayList();
            boolean containsCommandSeparatedPlaceholderBehaviour = commandObject.getPlaceholders().stream()
                    .map(CommandObject.Placeholder::getBehaviour)
                    .anyMatch(c -> c instanceof CommandSeparatedPlaceholderBehaviour);
            if (containsCommandSeparatedPlaceholderBehaviour) {
                for (int messageIndex = 0; messageIndex < placeholderMap.size(); messageIndex++) {
                    result.add(buildByMessage(messageIndex));
                }
            } else {
                result.add(buildByMessage(0));
            }
            return String.join("\n", result);
        } catch (RuntimeException e) {
            // Rethrow from unchecked to checked exception. We only deal with RuntimeException here, since streams
            // (here: placeholderMap.stream()) does not handle checked exceptions well.
            throw new Exception(e);
        }
    }

    private String buildByMessage(int messageIndex) throws Exception {
        StringBuffer format = new StringBuffer(commandObject.getFormat());
        // For each placeholder, starting from the placeholder at the very end, replace it with the value from the message.
        List<CommandObject.Placeholder> placeholders = commandObject.getPlaceholders().stream().sorted(
                Comparator.comparing(CommandObject.Placeholder::getEnd).reversed()
        ).collect(Collectors.toList());
        for (CommandObject.Placeholder placeholder : placeholders) {
            replaceCommandPlaceholder(placeholder, placeholderMap, messageIndex, format, context);
        }
        return format.toString();
    }

    private void replaceCommandPlaceholder(CommandObject.Placeholder placeholder, List<Map<String, IPlaceholderParser>> placeholderMap, int messageIndex, StringBuffer command, Context context) throws Exception {
        String value;
        if (placeholderValues.containsKey(new Placeholder(placeholder))) {
            // merged values
            value = placeholderValues.get(new Placeholder(placeholder));
        } else {
            // command separated - use the value from the actual message
            value = placeholderMap.get(messageIndex).get(placeholder.getName()).getValue(context);
        }
        command.replace(placeholder.getStart(), placeholder.getEnd(), value);
    }

    private String writeToFile(String value) throws Exception {
        try {
            File tmp = File.createTempFile("burp_", ".snd");
            PrintWriter out = new PrintWriter(tmp.getPath());
            out.write(value);
            out.flush();
            return tmp.getAbsolutePath();
        } catch (RuntimeException e) {
            throw new Exception(this.getClass().getSimpleName() + ": Error writing to temporary file!", e);
        }
    }
}

================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/executioner/CommandExecutioner.java
================================================
package net.bytebutcher.burpsendtoextension.executioner;

import burp.BurpExtender;
import burp.IHttpRequestResponse;
import com.google.common.collect.Lists;
import net.bytebutcher.burpsendtoextension.gui.util.SelectionUtil;
import net.bytebutcher.burpsendtoextension.models.Context;
import net.bytebutcher.burpsendtoextension.models.ERunInTerminalBehaviour;
import net.bytebutcher.burpsendtoextension.utils.OsUtils;
import net.bytebutcher.burpsendtoextension.utils.StringUtils;

import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CommandExecutioner {

    private final ERunInTerminalBehaviour runInTerminalBehaviour;
    private final boolean shouldOutputReplaceSelection;
    private final Context context;

    public CommandExecutioner(boolean shouldOutputReplaceSelection, Context context) {
        this.runInTerminalBehaviour = null;
        this.shouldOutputReplaceSelection = shouldOutputReplaceSelection;
        this.context = context;
    }

    public CommandExecutioner(ERunInTerminalBehaviour runInTerminalBehaviour, boolean shouldOutputReplaceSelection, Context context) {
        this.runInTerminalBehaviour = runInTerminalBehaviour;
        this.shouldOutputReplaceSelection = shouldOutputReplaceSelection;
        this.context = context;
    }

    public void execute(String commands) throws Exception {
        if (commands != null) {
            List<String> commandOutput = Lists.newArrayList();
            if (runInTerminalBehaviour != null && runInTerminalBehaviour == ERunInTerminalBehaviour.RUN_IN_SINGLE_TERMINAL) {
                // Run commands sequential within terminal
                String command = Arrays.stream(commands.split("\n")).collect(Collectors.joining(" ; "));
                execute(command, commandOutput);
            } else {
                // Run commands in parallel (within separate terminals or in background)
                for (String command : commands.split("\n")) {
                    execute(command, commandOutput);
                }
            }
            if (!commandOutput.isEmpty()) {
                replaceSelectedText(context, commandOutput.stream().collect(Collectors.joining("\n")));
            }
        }
    }

    private void execute(String command, List<String> commandOutput) throws IOException {
        ProcessBuilder commandProcessBuilder = getProcessBuilder(command);
        logCommandToBeExecuted(commandProcessBuilder.command().toArray(new String[commandProcessBuilder.command().size()]));
        Process process = commandProcessBuilder.start();
        if (shouldOutputReplaceSelection) {
            commandOutput.add(StringUtils.fromInputStream(process.getInputStream()));
        }
    }

    private ProcessBuilder getProcessBuilder(String command) {
        if (runInTerminalBehaviour != null) {
            return new ProcessBuilder(formatCommandForRunningInTerminal(command));
        } else {
            return new ProcessBuilder(formatCommandForRunningOnOperatingSystem(command));
        }
    }

    private String[] formatCommandForRunningOnOperatingSystem(String command) {
        String[] commandToBeExecuted;
        if (OsUtils.isWindows()) {
            commandToBeExecuted = new String[]{"cmd", "/c", command};
        } else {
            commandToBeExecuted = new String[]{"/bin/bash", "-c", command};
        }
        return commandToBeExecuted;
    }

    private String[] formatCommandForRunningInTerminal(String command) {
        String[] commandToBeExecuted = BurpExtender.getConfig().getRunInTerminalCommand().split(" ");
        for (int i = 0; i < commandToBeExecuted.length; i++) {
            String commandPart = commandToBeExecuted[i];
            if ("%C".equals(commandPart)) {
                commandToBeExecuted[i] = command;
            }
        }
        return commandToBeExecuted;
    }

    private void replaceSelectedText(Context context, String replaceText) throws Exception {
        if (context.getSelectedMessages() != null && context.getSelectedMessages().length > 0) {
            IHttpRequestResponse message = context.getSelectedMessages()[0];
            switch (context.getOrigin()) {
                case HTTP_REQUEST:
                    message.setRequest(SelectionUtil.replaceSelectedText(message.getRequest(), context.getSelectionBounds(), replaceText));
                    break;
                case HTTP_RESPONSE:
                    message.setResponse(SelectionUtil.replaceSelectedText(message.getResponse(), context.getSelectionBounds(), replaceText));
                    break;
            }
        }
    }

    private void logCommandToBeExecuted(String[] commandToBeExecuted) {
        String commandToBeExecutedWithoutControlCharacters = String.join(" ", commandToBeExecuted).replaceAll("[\u0000-\u001f]", "");
        String dateTime = ZonedDateTime.now().format(DateTimeFormatter.ofPattern("uuuu/MM/dd HH:mm:ss"));
        BurpExtender.printOut("[" + dateTime + "] " + commandToBeExecutedWithoutControlCharacters);
        BurpExtender.printOut("----------------------------------------------------------------------");
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/CommandsChangeListener.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import net.bytebutcher.burpsendtoextension.models.CommandObject;

import java.util.List;

public interface CommandsChangeListener {

    void commandsChanged(List<CommandObject> commandObjects);
}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedDialog.form
================================================
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.bytebutcher.burpsendtoextension.gui.SendToAddAdvancedDialog">
  <grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
    <margin top="10" left="10" bottom="10" right="10"/>
    <constraints>
      <xy x="48" y="54" width="635" height="297"/>
    </constraints>
    <properties/>
    <border type="none"/>
    <children>
      <grid id="94766" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
        <margin top="0" left="0" bottom="0" right="0"/>
        <constraints>
          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <hspacer id="98af6">
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
          </hspacer>
          <grid id="9538f" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="true" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="0" left="0" bottom="0" right="0"/>
            <constraints>
              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <component id="e7465" class="javax.swing.JButton" binding="buttonOK">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value="OK"/>
                </properties>
              </component>
              <component id="5723f" class="javax.swing.JButton" binding="buttonCancel">
                <constraints>
                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value="Cancel"/>
                </properties>
              </component>
            </children>
          </grid>
        </children>
      </grid>
      <grid id="e3588" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
        <margin top="0" left="0" bottom="0" right="0"/>
        <constraints>
          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <component id="57e4a" class="javax.swing.JLabel">
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Customize the behaviour of each placeholder when multiple HTTP messages are selected:"/>
            </properties>
          </component>
          <grid id="4c127" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="0" left="0" bottom="0" right="0"/>
            <constraints>
              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <vspacer id="b4d73">
                <constraints>
                  <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
                </constraints>
              </vspacer>
              <grid id="8d102" binding="pnlPlaceholderBehaviour" custom-create="true" layout-manager="BorderLayout" hgap="0" vgap="0">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties/>
                <border type="none"/>
                <children/>
              </grid>
            </children>
          </grid>
        </children>
      </grid>
    </children>
  </grid>
</form>


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedDialog.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import com.google.common.collect.Lists;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import net.bytebutcher.burpsendtoextension.gui.util.DialogUtil;
import net.bytebutcher.burpsendtoextension.models.CommandObject;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.List;

public class SendToAddAdvancedDialog extends JDialog {
    private final Component parent;
    private final List<CommandObject.Placeholder> placeholders;
    private JPanel contentPane;
    private JButton buttonOK;
    private JButton buttonCancel;
    private JPanel pnlPlaceholderBehaviour;

    private boolean success = false;

    public SendToAddAdvancedDialog(Component parent, List<CommandObject.Placeholder> placeholders) {
        this.parent = parent;
        this.placeholders = placeholders;
        $$$setupUI$$$();

        setContentPane(contentPane);
        setTitle("Customize Placeholder Behaviour");
        setModal(true);
        getRootPane().setDefaultButton(buttonOK);

        buttonOK.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onOK();
            }
        });

        buttonCancel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onCancel();
            }
        });

        // call onCancel() when cross is clicked
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                onCancel();
            }
        });

        // call onCancel() on ESCAPE
        contentPane.registerKeyboardAction(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onCancel();
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    }

    public List<CommandObject.Placeholder> getPlaceholders() {
        List<CommandObject.Placeholder> placeholders = Lists.newArrayList();
        for (Component component : pnlPlaceholderBehaviour.getComponents()) {
            placeholders.add(((SendToAddAdvancedPlaceholderBehaviourPanel) component).getPlaceholder());
        }
        return placeholders;
    }

    private void onOK() {
        success = true;
        dispose();
    }

    private void onCancel() {
        success = false;
        dispose();
    }

    public boolean run() {
        for (CommandObject.Placeholder placeholder : placeholders) {
            pnlPlaceholderBehaviour.add(new SendToAddAdvancedPlaceholderBehaviourPanel(placeholder));
        }
        this.setSize(450, 250);
        int x = DialogUtil.getX(parent, this);
        int y = DialogUtil.getY(parent, this);
        this.setLocation(x, y);
        this.pack();
        this.setVisible(true);
        return success;
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        createUIComponents();
        contentPane = new JPanel();
        contentPane.setLayout(new GridLayoutManager(2, 1, new Insets(10, 10, 10, 10), -1, -1));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
        contentPane.add(panel1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        panel1.add(spacer1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1, true, false));
        panel1.add(panel2, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        buttonOK = new JButton();
        buttonOK.setText("OK");
        panel2.add(buttonOK, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        buttonCancel = new JButton();
        buttonCancel.setText("Cancel");
        panel2.add(buttonCancel, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel3 = new JPanel();
        panel3.setLayout(new GridLayoutManager(2, 1, new Insets(0, 0, 0, 0), -1, -1));
        contentPane.add(panel3, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JLabel label1 = new JLabel();
        label1.setText("Customize the behaviour of each placeholder when multiple HTTP messages are selected:");
        panel3.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel4 = new JPanel();
        panel4.setLayout(new GridLayoutManager(2, 1, new Insets(0, 0, 0, 0), -1, -1));
        panel3.add(panel4, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final Spacer spacer2 = new Spacer();
        panel4.add(spacer2, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        panel4.add(pnlPlaceholderBehaviour, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return contentPane;
    }

    private void createUIComponents() {
        pnlPlaceholderBehaviour = new JPanel();
        pnlPlaceholderBehaviour.setLayout(new BoxLayout(this.pnlPlaceholderBehaviour, BoxLayout.Y_AXIS));
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedPlaceholderBehaviourPanel.form
================================================
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.bytebutcher.burpsendtoextension.gui.SendToAddAdvancedPlaceholderBehaviourPanel">
  <grid id="27dc6" binding="pnlMain" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
    <margin top="0" left="0" bottom="0" right="0"/>
    <constraints>
      <xy x="20" y="20" width="461" height="59"/>
    </constraints>
    <properties/>
    <border type="none"/>
    <children>
      <component id="7ee4a" class="javax.swing.JTextField" binding="txtSeparator">
        <constraints>
          <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
            <preferred-size width="150" height="-1"/>
          </grid>
        </constraints>
        <properties/>
      </component>
      <component id="e079c" class="javax.swing.JComboBox" binding="cmbSeperator">
        <constraints>
          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <model>
            <item value="split into separate commands"/>
            <item value="separate by string"/>
            <item value="merge into file"/>
          </model>
        </properties>
      </component>
      <component id="c94a2" class="javax.swing.JLabel" binding="lblPlaceholder">
        <constraints>
          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <text value="..."/>
        </properties>
      </component>
    </children>
  </grid>
</form>


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedPlaceholderBehaviourPanel.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import burp.BurpExtender;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import net.bytebutcher.burpsendtoextension.models.CommandObject;
import net.bytebutcher.burpsendtoextension.models.placeholder.behaviour.CommandSeparatedPlaceholderBehaviour;
import net.bytebutcher.burpsendtoextension.models.placeholder.behaviour.FileSeparatedPlaceholderBehaviour;
import net.bytebutcher.burpsendtoextension.models.placeholder.behaviour.IPlaceholderBehaviour;
import net.bytebutcher.burpsendtoextension.models.placeholder.behaviour.StringSeparatedPlaceholderBehaviour;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SendToAddAdvancedPlaceholderBehaviourPanel extends JPanel {

    private final CommandObject.Placeholder placeholder;

    private JTextField txtSeparator;
    private JPanel pnlMain;
    private JComboBox cmbSeperator;
    private JLabel lblPlaceholder;

    public SendToAddAdvancedPlaceholderBehaviourPanel(CommandObject.Placeholder placeholder) {
        this.placeholder = placeholder;
        this.add(pnlMain);
        this.lblPlaceholder.setText(placeholder.getName());
        initFields();
        initEventListener();
    }

    private void initFields() {
        IPlaceholderBehaviour placeholderBehaviour = placeholder.getBehaviour();
        if (placeholderBehaviour instanceof StringSeparatedPlaceholderBehaviour) {
            this.txtSeparator.setText(((StringSeparatedPlaceholderBehaviour) placeholderBehaviour).getSeparator());
            this.txtSeparator.setEnabled(true);
            this.cmbSeperator.setSelectedIndex(1);
        } else if (placeholderBehaviour instanceof FileSeparatedPlaceholderBehaviour) {
            this.txtSeparator.setText("");
            this.txtSeparator.setEnabled(false);
            this.cmbSeperator.setSelectedIndex(2);
        } else {
            this.txtSeparator.setText("");
            this.txtSeparator.setEnabled(false);
            this.cmbSeperator.setSelectedIndex(0);
        }
    }

    private void initEventListener() {
        this.cmbSeperator.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (cmbSeperator.getSelectedIndex() == 1) {
                    txtSeparator.setEnabled(true);
                    txtSeparator.setText("");
                } else {
                    txtSeparator.setEnabled(false);
                    txtSeparator.setText("");
                }
            }
        });
    }

    public CommandObject.Placeholder getPlaceholder() {
        switch (cmbSeperator.getSelectedIndex()) {
            case 1:
                placeholder.setBehaviour(new StringSeparatedPlaceholderBehaviour(txtSeparator.getText()));
                break;
            case 2:
                placeholder.setBehaviour(new FileSeparatedPlaceholderBehaviour());
                break;
            default:
                placeholder.setBehaviour(new CommandSeparatedPlaceholderBehaviour());
                break;
        }
        return placeholder;
    }

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        pnlMain = new JPanel();
        pnlMain.setLayout(new GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1));
        txtSeparator = new JTextField();
        pnlMain.add(txtSeparator, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
        cmbSeperator = new JComboBox();
        final DefaultComboBoxModel defaultComboBoxModel1 = new DefaultComboBoxModel();
        defaultComboBoxModel1.addElement("split into separate commands");
        defaultComboBoxModel1.addElement("separate by string");
        defaultComboBoxModel1.addElement("merge into file");
        cmbSeperator.setModel(defaultComboBoxModel1);
        pnlMain.add(cmbSeperator, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        lblPlaceholder = new JLabel();
        lblPlaceholder.setText("...");
        pnlMain.add(lblPlaceholder, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return pnlMain;
    }

}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddDialog.form
================================================
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.bytebutcher.burpsendtoextension.gui.SendToAddDialog">
  <grid id="27dc6" binding="formPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
    <margin top="10" left="10" bottom="10" right="10"/>
    <constraints>
      <xy x="20" y="20" width="623" height="306"/>
    </constraints>
    <properties/>
    <border type="none"/>
    <children>
      <component id="fb1e8" class="javax.swing.JLabel">
        <constraints>
          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <text value="Enter the details for the &quot;Send to...&quot; context menu entry."/>
        </properties>
      </component>
      <grid id="8234f" layout-manager="GridBagLayout">
        <constraints>
          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <component id="e14c7" class="javax.swing.JLabel">
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
              <gridbag top="2" left="2" bottom="2" right="10" weightx="0.0" weighty="0.0"/>
            </constraints>
            <properties>
              <labelFor value="ab56a"/>
              <text value="&amp;Name:"/>
            </properties>
          </component>
          <component id="8cad7" class="javax.swing.JLabel">
            <constraints>
              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
              <gridbag top="2" left="2" bottom="2" right="10" weightx="0.0" weighty="0.0"/>
            </constraints>
            <properties>
              <labelFor value="476e7"/>
              <text value="Co&amp;mmand:"/>
            </properties>
          </component>
          <grid id="5d0aa" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="0" left="0" bottom="0" right="0"/>
            <constraints>
              <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
              <gridbag weightx="0.0" weighty="0.0"/>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <component id="476e7" class="javax.swing.JTextField" binding="txtCommand">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
                    <preferred-size width="150" height="-1"/>
                  </grid>
                </constraints>
                <properties>
                  <text value=""/>
                </properties>
              </component>
              <component id="9f55b" class="javax.swing.JButton" binding="btnCommandHelp">
                <constraints>
                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value="?"/>
                </properties>
              </component>
            </children>
          </grid>
          <component id="c7d44" class="javax.swing.JLabel">
            <constraints>
              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
              <gridbag top="2" left="2" bottom="2" right="10" weightx="0.0" weighty="0.0"/>
            </constraints>
            <properties>
              <labelFor value="532e8"/>
              <text value="&amp;Group:"/>
            </properties>
          </component>
          <component id="938ed" class="javax.swing.JRadioButton" binding="chkRunInTerminal">
            <constraints>
              <grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
              <gridbag weightx="0.0" weighty="0.0"/>
            </constraints>
            <properties>
              <text value="Run in &amp;terminal"/>
            </properties>
          </component>
          <component id="579d8" class="javax.swing.JRadioButton" binding="chkOutputShouldReplaceSelection">
            <constraints>
              <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
              <gridbag weightx="0.0" weighty="0.0"/>
            </constraints>
            <properties>
              <text value="Output should &amp;replace selection"/>
            </properties>
          </component>
          <component id="1d8bf" class="javax.swing.JCheckBox" binding="chkShowPreviewPriorToExecution">
            <constraints>
              <grid row="6" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
              <gridbag top="5" left="2" bottom="2" right="2" weightx="0.0" weighty="0.0"/>
            </constraints>
            <properties>
              <selected value="true"/>
              <text value="Show &amp;preview prior to execution"/>
            </properties>
          </component>
          <component id="532e8" class="javax.swing.JTextField" binding="txtGroup">
            <constraints>
              <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
                <preferred-size width="150" height="-1"/>
              </grid>
              <gridbag top="2" left="2" bottom="2" right="2" weightx="1.0" weighty="0.0"/>
            </constraints>
            <properties/>
          </component>
          <component id="ab56a" class="javax.swing.JTextField" binding="txtName">
            <constraints>
              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
                <preferred-size width="150" height="-1"/>
              </grid>
              <gridbag top="2" left="2" bottom="2" right="2" weightx="1.0" weighty="0.0"/>
            </constraints>
            <properties/>
          </component>
          <component id="29c23" class="javax.swing.JRadioButton" binding="chkRunInBackground">
            <constraints>
              <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
              <gridbag weightx="0.0" weighty="0.0"/>
            </constraints>
            <properties>
              <selected value="true"/>
              <text value="Run in &amp;background"/>
            </properties>
          </component>
        </children>
      </grid>
      <grid id="86a29" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
        <margin top="0" left="0" bottom="0" right="0"/>
        <constraints>
          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <component id="6cbe" class="javax.swing.JButton" binding="btnCancel">
            <constraints>
              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="&amp;Cancel"/>
            </properties>
          </component>
          <component id="816b1" class="javax.swing.JButton" binding="btnOk">
            <constraints>
              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="&amp;Ok"/>
            </properties>
          </component>
          <hspacer id="d81ad">
            <constraints>
              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
          </hspacer>
          <component id="6e292" class="javax.swing.JButton" binding="btnAdvanced">
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="&amp;Advanced"/>
            </properties>
          </component>
        </children>
      </grid>
    </children>
  </grid>
  <buttonGroups>
    <group name="groupOutput">
      <member id="938ed"/>
      <member id="579d8"/>
      <member id="29c23"/>
    </group>
  </buttonGroups>
</form>


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddDialog.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import burp.BurpExtender;
import com.google.common.collect.Lists;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import net.bytebutcher.burpsendtoextension.gui.listener.ToolTipActionListener;
import net.bytebutcher.burpsendtoextension.gui.util.DialogUtil;
import net.bytebutcher.burpsendtoextension.models.CommandObject;
import net.bytebutcher.burpsendtoextension.models.ERuntimeBehaviour;
import net.bytebutcher.burpsendtoextension.models.Placeholders;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.List;

public class SendToAddDialog {
    private JTextField txtName;
    private JTextField txtCommand;
    private JButton btnCancel;
    private JButton btnOk;
    private JPanel formPanel;
    private JButton btnCommandHelp;
    private JCheckBox chkShowPreviewPriorToExecution;
    private JTextField txtGroup;
    private JRadioButton chkRunInTerminal;
    private JRadioButton chkOutputShouldReplaceSelection;
    private JRadioButton chkRunInBackground;
    private JButton btnAdvanced;
    private final JDialog dialog;

    private boolean success = false;
    private AbstractAction onOkActionListener;
    private AbstractAction onCancelActionListener;

    // This list is used to check whether the currently entered command object already exists (duplicate-check).
    private List<CommandObject> commandObjects;
    private List<CommandObject.Placeholder> placeholders = Lists.newArrayList();

    public SendToAddDialog(JFrame parent, String title, List<CommandObject> commandObjects) {
        this.commandObjects = commandObjects;
        this.dialog = initDialog(parent, title);
        initEventListener();
        initKeyboardShortcuts();
        initButtonState();
    }

    public SendToAddDialog(JFrame parent, String title, List<CommandObject> commandObjects, CommandObject commandObject) {
        this(parent, title, commandObjects);
        commandObjects.remove(commandObject);
        txtName.setText(commandObject.getName());
        txtCommand.setText(commandObject.getFormat());
        txtGroup.setText(commandObject.getGroup());
        chkShowPreviewPriorToExecution.setSelected(commandObject.shouldShowPreview());
        chkRunInBackground.setSelected(commandObject.shouldRunInBackground());
        chkRunInTerminal.setSelected(commandObject.shouldRunInTerminal());
        chkOutputShouldReplaceSelection.setSelected(commandObject.shouldOutputReplaceSelection());
        placeholders = Lists.newArrayList(commandObject.getPlaceholders());
    }

    private void initKeyboardShortcuts() {
        bindKeyStrokeToAction("ESCAPE", onCancelActionListener);
        bindKeyStrokeToAction("ENTER", onOkActionListener);
    }

    private void bindKeyStrokeToAction(String keyStroke, Action action) {
        KeyStroke stroke = KeyStroke.getKeyStroke(keyStroke);
        InputMap inputMap = formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(stroke, keyStroke);
        formPanel.getActionMap().put(keyStroke, action);
    }

    private void initEventListener() {
        txtCommand.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateAdvancedButton();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateAdvancedButton();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                updateAdvancedButton();
            }

            private void updateAdvancedButton() {
                btnAdvanced.setEnabled(!Placeholders.get(txtCommand.getText()).isEmpty());
            }
        });
        btnAdvanced.addActionListener((e) -> {
            placeholders = getCommandObject().getPlaceholders();
            SendToAddAdvancedDialog dialog = new SendToAddAdvancedDialog(this.dialog, placeholders);
            if (dialog.run()) {
                placeholders = dialog.getPlaceholders();
            }
        });
        onOkActionListener = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (getName().isEmpty()) {
                    DialogUtil.showErrorDialog(
                            dialog,
                            "Name should not be empty!",
                            "Name is empty!"
                    );
                    return;
                }
                if (!commandObjects.stream().noneMatch(commandObject -> getName().equals(commandObject.getName()) && getGroup().equals(commandObject.getGroup()))) {
                    DialogUtil.showErrorDialog(
                            dialog,
                            "Name already exists within the specified group!",
                            "Combination of name and group already exists!"
                    );
                    return;
                }
                if (getCommand().isEmpty()) {
                    DialogUtil.showErrorDialog(
                            dialog,
                            "Command should not be empty!",
                            "Command is empty!"
                    );
                    return;
                }
                success = true;
                dialog.dispose();
            }
        };
        btnOk.addActionListener(onOkActionListener);
        onCancelActionListener = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                success = false;
                dialog.dispose();
            }
        };
        btnCancel.addActionListener(onCancelActionListener);
        btnCommandHelp.addActionListener(new ToolTipActionListener(btnCommandHelp, "" +
                "<html>" +
                "<p>%H = Host</p>" +
                "<p>%P = Port</p>" +
                "<p>%T = Protocol</p>" +
                "<p>%U = URL</p>" +
                "<p>%A = URL-Path</p>" +
                "<p>%Q = URL-Query</p>" +
                "<p>%C = Cookies</p>" +
                "<p>%L = HTTP-Content-Length</p>" +
                "<p>%M = HTTP-Method</p>" +
                "<p>%O = HTTP-Status-Code</p>" +
                "<p>%S = Selected text</p>" +
                "<p>%F = Path to file containing selected text</p>" +
                "<p>%R = Path to file containing HTTP-request/-response</p>" +
                "<p>%B = Path to file containing body of HTTP-request/-response</p>" +
                "<p>%E = Path to file containing header of HTTP-request/-response</p>" +
                "</html>")
        );
    }

    private void initButtonState() {
        btnAdvanced.setEnabled(!Placeholders.get(txtCommand.getText()).isEmpty());
    }

    private JDialog initDialog(JFrame parent, String title) {
        JDialog dialog = new JDialog(parent, title, true);
        dialog.getContentPane().add(this.getRootPanel());
        dialog.setSize(450, 250);
        int x = DialogUtil.getX(parent, dialog);
        int y = DialogUtil.getY(parent, dialog);
        dialog.setLocation(x, y);
        dialog.pack();
        return dialog;
    }

    public boolean run() {
        this.dialog.setVisible(true);
        return this.success;
    }

    private JPanel getRootPanel() {
        return formPanel;
    }

    private String getName() {
        return txtName.getText();
    }

    private String getCommand() {
        return txtCommand.getText();
    }

    private String getGroup() {
        return txtGroup.getText();
    }

    private ERuntimeBehaviour getRuntimeBehaviour() {
        if (chkRunInTerminal.isSelected()) {
            return ERuntimeBehaviour.RUN_IN_TERMINAL;
        }
        if (chkOutputShouldReplaceSelection.isSelected()) {
            return ERuntimeBehaviour.OUTPUT_SHOULD_REPLACE_SELECTION;
        }
        if (chkRunInBackground.isSelected()) {
            return ERuntimeBehaviour.RUN_IN_BACKGROUND;
        }
        BurpExtender.printErr("Error parsing runtime behaviour. Please file a bug report if you encounter this error more often.");
        return ERuntimeBehaviour.RUN_IN_TERMINAL; // Return sane default
    }

    private boolean shouldShowPreview() {
        return chkShowPreviewPriorToExecution.isSelected();
    }

    private List<CommandObject.Placeholder> getPlaceholders() {
        return placeholders;
    }

    public CommandObject getCommandObject() {
        return new CommandObject(getName(), getCommand(), getGroup(), getRuntimeBehaviour(), shouldShowPreview(), getPlaceholders());
    }

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        formPanel = new JPanel();
        formPanel.setLayout(new GridLayoutManager(3, 1, new Insets(10, 10, 10, 10), -1, -1));
        final JLabel label1 = new JLabel();
        label1.setText("Enter the details for the \"Send to...\" context menu entry.");
        formPanel.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridBagLayout());
        formPanel.add(panel1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JLabel label2 = new JLabel();
        label2.setText("Name:");
        label2.setDisplayedMnemonic('N');
        label2.setDisplayedMnemonicIndex(0);
        GridBagConstraints gbc;
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(2, 2, 2, 10);
        panel1.add(label2, gbc);
        final JLabel label3 = new JLabel();
        label3.setText("Command:");
        label3.setDisplayedMnemonic('M');
        label3.setDisplayedMnemonicIndex(2);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(2, 2, 2, 10);
        panel1.add(label3, gbc);
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 1;
        gbc.fill = GridBagConstraints.BOTH;
        panel1.add(panel2, gbc);
        txtCommand = new JTextField();
        txtCommand.setText("");
        panel2.add(txtCommand, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
        btnCommandHelp = new JButton();
        btnCommandHelp.setText("?");
        panel2.add(btnCommandHelp, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label4 = new JLabel();
        label4.setText("Group:");
        label4.setDisplayedMnemonic('G');
        label4.setDisplayedMnemonicIndex(0);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(2, 2, 2, 10);
        panel1.add(label4, gbc);
        chkRunInTerminal = new JRadioButton();
        chkRunInTerminal.setText("Run in terminal");
        chkRunInTerminal.setMnemonic('T');
        chkRunInTerminal.setDisplayedMnemonicIndex(7);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 4;
        gbc.anchor = GridBagConstraints.WEST;
        panel1.add(chkRunInTerminal, gbc);
        chkOutputShouldReplaceSelection = new JRadioButton();
        chkOutputShouldReplaceSelection.setText("Output should replace selection");
        chkOutputShouldReplaceSelection.setMnemonic('R');
        chkOutputShouldReplaceSelection.setDisplayedMnemonicIndex(14);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 5;
        gbc.anchor = GridBagConstraints.WEST;
        panel1.add(chkOutputShouldReplaceSelection, gbc);
        chkShowPreviewPriorToExecution = new JCheckBox();
        chkShowPreviewPriorToExecution.setSelected(true);
        chkShowPreviewPriorToExecution.setText("Show preview prior to execution");
        chkShowPreviewPriorToExecution.setMnemonic('P');
        chkShowPreviewPriorToExecution.setDisplayedMnemonicIndex(5);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 6;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 2, 2, 2);
        panel1.add(chkShowPreviewPriorToExecution, gbc);
        txtGroup = new JTextField();
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(2, 2, 2, 2);
        panel1.add(txtGroup, gbc);
        txtName = new JTextField();
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(2, 2, 2, 2);
        panel1.add(txtName, gbc);
        chkRunInBackground = new JRadioButton();
        chkRunInBackground.setSelected(true);
        chkRunInBackground.setText("Run in background");
        chkRunInBackground.setMnemonic('B');
        chkRunInBackground.setDisplayedMnemonicIndex(7);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.anchor = GridBagConstraints.WEST;
        panel1.add(chkRunInBackground, gbc);
        final JPanel panel3 = new JPanel();
        panel3.setLayout(new GridLayoutManager(1, 4, new Insets(0, 0, 0, 0), -1, -1));
        formPanel.add(panel3, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        btnCancel = new JButton();
        btnCancel.setText("Cancel");
        btnCancel.setMnemonic('C');
        btnCancel.setDisplayedMnemonicIndex(0);
        panel3.add(btnCancel, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        btnOk = new JButton();
        btnOk.setText("Ok");
        btnOk.setMnemonic('O');
        btnOk.setDisplayedMnemonicIndex(0);
        panel3.add(btnOk, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        panel3.add(spacer1, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        btnAdvanced = new JButton();
        btnAdvanced.setText("Advanced");
        btnAdvanced.setMnemonic('A');
        btnAdvanced.setDisplayedMnemonicIndex(0);
        panel3.add(btnAdvanced, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        label2.setLabelFor(txtName);
        label3.setLabelFor(txtCommand);
        label4.setLabelFor(txtGroup);
        ButtonGroup buttonGroup;
        buttonGroup = new ButtonGroup();
        buttonGroup.add(chkRunInTerminal);
        buttonGroup.add(chkOutputShouldReplaceSelection);
        buttonGroup.add(chkRunInBackground);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return formPanel;
    }

}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToContextMenu.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import burp.BurpExtender;
import burp.IContextMenuFactory;
import burp.IContextMenuInvocation;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.bytebutcher.burpsendtoextension.models.CommandObject;
import net.bytebutcher.burpsendtoextension.models.Context;
import net.bytebutcher.burpsendtoextension.models.Placeholders;
import net.bytebutcher.burpsendtoextension.models.placeholder.IPlaceholderParser;

import javax.swing.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SendToContextMenu implements IContextMenuFactory {

    private BurpExtender burpExtender;
    private SendToTableListener sendToTableListener;

    public SendToContextMenu(BurpExtender burpExtender, SendToTableListener sendToTableListener) {
        this.burpExtender = burpExtender;
        this.sendToTableListener = sendToTableListener;
    }

    @Override
    public List<JMenuItem> createMenuItems(IContextMenuInvocation invocation) {
        List<Map<String, IPlaceholderParser>> placeholders = Placeholders.get(BurpExtender.getCallbacks(), invocation.getSelectedMessages());
        List<CommandObject> commandObjects = BurpExtender.getConfig().getSendToTableData();
        if (commandObjects.isEmpty()) {
            return Lists.newArrayList();
        }

        JMenu sendToMenu = new JMenu("Send to...");
        HashMap<String, List<CommandObject>> groupedCommandObjects = Maps.newLinkedHashMap();
        boolean hasEmptyGroup = false;
        for (final CommandObject commandObject : commandObjects) {
            String group = commandObject.getGroup();
            if (group.isEmpty()) {
                addMenuItem(sendToMenu, commandObject, placeholders, invocation);
                hasEmptyGroup = true;
                continue;
            }
            if (!groupedCommandObjects.containsKey(group)) {
                groupedCommandObjects.put(group, Lists.newArrayList());
            }
            groupedCommandObjects.get(group).add(commandObject);
        }
        if (hasEmptyGroup && !groupedCommandObjects.isEmpty()) {
            sendToMenu.addSeparator();
        }
        for (String group : groupedCommandObjects.keySet()) {
            JMenu menuItem = new JMenu(group);
            for (CommandObject commandObject : groupedCommandObjects.get(group)) {
                addMenuItem(menuItem, commandObject, placeholders, invocation);
            }
            sendToMenu.add(menuItem);
        }
        return  Lists.newArrayList(sendToMenu);
    }

    private void addMenuItem(JMenu menu, CommandObject commandObject, List<Map<String, IPlaceholderParser>> placeholders, IContextMenuInvocation invocation) {

        JMenuItem item;
        Context context = new Context(invocation);
        if (commandObject.doesRequireRequestResponse(placeholders.get(0)) && context.getOrigin() == Context.Origin.UNKNOWN) {
            item = new JMenu(commandObject.getName());
            SendToContextMenuItem request = new SendToContextMenuItem("request", commandObject, placeholders, new Context(Context.Origin.HTTP_REQUEST, invocation), sendToTableListener);
            SendToContextMenuItem response = new SendToContextMenuItem("response", commandObject, placeholders, new Context(Context.Origin.HTTP_RESPONSE, invocation), sendToTableListener);
            item.add(request);
            item.add(response);
            item.setEnabled(request.isEnabled() || response.isEnabled());
        } else {
            item = new SendToContextMenuItem(commandObject.getName(), commandObject, placeholders, context, sendToTableListener);
        }
        menu.add(item);
    }

}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToContextMenuItem.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import net.bytebutcher.burpsendtoextension.gui.action.SendToContextMenuItemAction;
import net.bytebutcher.burpsendtoextension.models.CommandObject;
import net.bytebutcher.burpsendtoextension.models.Context;
import net.bytebutcher.burpsendtoextension.models.placeholder.IPlaceholderParser;

import javax.swing.*;
import java.util.List;
import java.util.Map;

public class SendToContextMenuItem extends JMenuItem {

    public SendToContextMenuItem(String title, CommandObject commandObject, List<Map<String, IPlaceholderParser>> placeholders, Context context, SendToTableListener sendToTableListener) {
        String text = "";
        List<Map<String, IPlaceholderParser>> validEntries = commandObject.getValid(placeholders, context);
        if (placeholders.size() > 1) {
            text = title + " (" + validEntries.size() + "/" + placeholders.size() + ")";
        } else {
            text = title;
        }
        this.setAction(new SendToContextMenuItemAction(text, commandObject, placeholders, sendToTableListener, context));
        if (commandObject.shouldOutputReplaceSelection() && context.getSelectionBounds() == null) {
            // Always disable context menu item, when command should replace selection but no selection was made.
            this.setEnabled(false);
        } else {
            // Do only enable context menu item, when at least one HTTP-message can be used to construct the command.
            this.setEnabled(validEntries.size() > 0);
        }
    }

}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToPreviewDialog.form
================================================
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.bytebutcher.burpsendtoextension.gui.SendToPreviewDialog">
  <grid id="27dc6" binding="formPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
    <margin top="10" left="10" bottom="10" right="10"/>
    <constraints>
      <xy x="20" y="20" width="607" height="154"/>
    </constraints>
    <properties/>
    <border type="none"/>
    <children>
      <component id="6d061" class="javax.swing.JLabel">
        <constraints>
          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <text value="Do you really want to execute the following command(s)?"/>
        </properties>
      </component>
      <grid id="ffa03" layout-manager="GridLayoutManager" row-count="1" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
        <margin top="0" left="0" bottom="0" right="0"/>
        <constraints>
          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <hspacer id="3ca82">
            <constraints>
              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
          </hspacer>
          <component id="336c9" class="javax.swing.JButton" binding="cancelButton" default-binding="true">
            <constraints>
              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="&amp;Cancel"/>
            </properties>
          </component>
          <component id="d2f34" class="javax.swing.JButton" binding="okButton" default-binding="true">
            <constraints>
              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="&amp;Ok"/>
            </properties>
          </component>
          <component id="57542" class="javax.swing.JCheckBox" binding="alwaysShowThisDialogCheckBox" default-binding="true">
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <selected value="true"/>
              <text value="Always show this dialog"/>
              <visible value="false"/>
            </properties>
          </component>
        </children>
      </grid>
      <scrollpane id="5b762">
        <constraints>
          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <component id="95319" class="javax.swing.JTextArea" binding="txtCommandPreview">
            <constraints/>
            <properties/>
          </component>
        </children>
      </scrollpane>
    </children>
  </grid>
</form>


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToPreviewDialog.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import net.bytebutcher.burpsendtoextension.gui.util.DialogUtil;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SendToPreviewDialog {

    private JTextArea txtCommandPreview;
    private JButton cancelButton;
    private JButton okButton;
    private JCheckBox alwaysShowThisDialogCheckBox;
    private JPanel formPanel;

    private SendToTableListener sendToTableListener;
    private AbstractAction onOkAction;
    private AbstractAction onCancelAction;
    private final JDialog dialog;
    private boolean success = false;

    public SendToPreviewDialog(JFrame parent, String title, final String command) {
        this.dialog = initDialog(parent, title);
        this.txtCommandPreview.setText(command);
        initEventListener();
        initKeyboardShortcuts();
    }

    public SendToPreviewDialog(JFrame parent, String title, final String command, final String commandId, final SendToTableListener sendToTableListener) {
        this(parent, title, command);
        this.sendToTableListener = sendToTableListener;
        initEventListener(commandId, sendToTableListener);
    }

    private void initEventListener() {
        onOkAction = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                success = true;
                dialog.dispose();
            }
        };
        okButton.addActionListener(onOkAction);
        onCancelAction = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                success = false;
                dialog.dispose();
            }
        };
        cancelButton.addActionListener(onCancelAction);
    }

    private void initEventListener(final String commandId, final SendToTableListener sendToTableListener) {
        alwaysShowThisDialogCheckBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                sendToTableListener.onShowPreviewChange(e, commandId, alwaysShowThisDialogCheckBox.isSelected());
            }
        });
        alwaysShowThisDialogCheckBox.setVisible(true);
    }

    private JDialog initDialog(JFrame parent, String title) {
        JDialog dialog = new JDialog(parent, title, true);
        dialog.getContentPane().add(this.getRootPanel());
        dialog.pack();
        dialog.setSize(540, 200);
        int x = DialogUtil.getX(parent, dialog);
        int y = DialogUtil.getY(parent, dialog);
        dialog.setLocation(x, y);
        return dialog;
    }

    private void initKeyboardShortcuts() {
        bindKeyStrokeToAction("ESCAPE", onCancelAction);
        bindKeyStrokeToAction("ENTER", onOkAction);
    }

    private void bindKeyStrokeToAction(String keyStroke, Action action) {
        KeyStroke stroke = KeyStroke.getKeyStroke(keyStroke);
        InputMap inputMap = formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(stroke, keyStroke);
        formPanel.getActionMap().put(keyStroke, action);
    }

    public boolean run() {
        this.dialog.setVisible(true);
        return this.success;
    }

    public String getCommand() {
        return this.txtCommandPreview.getText().replace("\r", "");
    }

    private Component getRootPanel() {
        return formPanel;
    }

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        formPanel = new JPanel();
        formPanel.setLayout(new GridLayoutManager(3, 1, new Insets(10, 10, 10, 10), -1, -1));
        final JLabel label1 = new JLabel();
        label1.setText("Do you really want to execute the following command(s)?");
        formPanel.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayoutManager(1, 4, new Insets(0, 0, 0, 0), -1, -1));
        formPanel.add(panel1, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        panel1.add(spacer1, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        cancelButton = new JButton();
        cancelButton.setText("Cancel");
        cancelButton.setMnemonic('C');
        cancelButton.setDisplayedMnemonicIndex(0);
        panel1.add(cancelButton, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        okButton = new JButton();
        okButton.setText("Ok");
        okButton.setMnemonic('O');
        okButton.setDisplayedMnemonicIndex(0);
        panel1.add(okButton, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        alwaysShowThisDialogCheckBox = new JCheckBox();
        alwaysShowThisDialogCheckBox.setSelected(true);
        alwaysShowThisDialogCheckBox.setText("Always show this dialog");
        alwaysShowThisDialogCheckBox.setVisible(false);
        panel1.add(alwaysShowThisDialogCheckBox, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JScrollPane scrollPane1 = new JScrollPane();
        formPanel.add(scrollPane1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        txtCommandPreview = new JTextArea();
        scrollPane1.setViewportView(txtCommandPreview);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return formPanel;
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToRunInTerminalBehaviourChoiceDialog.form
================================================
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.bytebutcher.burpsendtoextension.gui.SendToRunInTerminalBehaviourChoiceDialog">
  <grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
    <margin top="10" left="10" bottom="10" right="10"/>
    <constraints>
      <xy x="48" y="264" width="728" height="112"/>
    </constraints>
    <properties/>
    <border type="none"/>
    <children>
      <grid id="94766" layout-manager="GridLayoutManager" row-count="1" column-count="6" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
        <margin top="0" left="0" bottom="0" right="0"/>
        <constraints>
          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <hspacer id="98af6">
            <constraints>
              <grid row="0" column="5" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
          </hspacer>
          <component id="9551d" class="javax.swing.JButton" binding="btnRunInSeparateTerminals">
            <constraints>
              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Run in &amp;separate terminals"/>
            </properties>
          </component>
          <component id="5723f" class="javax.swing.JButton" binding="btnCancel">
            <constraints>
              <grid row="0" column="4" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Cancel"/>
            </properties>
          </component>
          <hspacer id="ebf39">
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
          </hspacer>
          <component id="9f65a" class="javax.swing.JButton" binding="btnReviewCommands">
            <constraints>
              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Review c&amp;ommands"/>
            </properties>
          </component>
          <component id="e7465" class="javax.swing.JButton" binding="btnRunInSingleTerminal">
            <constraints>
              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Run in s&amp;ingle terminal"/>
            </properties>
          </component>
        </children>
      </grid>
      <grid id="e3588" layout-manager="GridLayoutManager" row-count="2" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
        <margin top="0" left="0" bottom="0" right="0"/>
        <constraints>
          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <component id="71538" class="javax.swing.JLabel">
            <constraints>
              <grid row="1" column="0" row-span="1" col-span="4" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Please select how the commands should be executed."/>
            </properties>
          </component>
          <component id="57df7" class="javax.swing.JLabel">
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="You are going to execute"/>
            </properties>
          </component>
          <component id="4e660" class="javax.swing.JLabel" binding="lblCommandCount">
            <constraints>
              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="0"/>
            </properties>
          </component>
          <component id="76f3c" class="javax.swing.JLabel">
            <constraints>
              <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="commands."/>
            </properties>
          </component>
          <hspacer id="48714">
            <constraints>
              <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
            </constraints>
          </hspacer>
        </children>
      </grid>
    </children>
  </grid>
</form>


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToRunInTerminalBehaviourChoiceDialog.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import net.bytebutcher.burpsendtoextension.gui.util.DialogUtil;
import net.bytebutcher.burpsendtoextension.models.ERunInTerminalBehaviour;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class SendToRunInTerminalBehaviourChoiceDialog extends JDialog {

    private EChoice choice;

    public enum EChoice {
        RUN_IN_SINGLE_TERMINAL,
        RUN_IN_SEPARATE_TERMINALS,
        REVIEW_COMMANDS,
        CANCEL
    }

    private final JFrame parent;
    private JPanel contentPane;
    private JButton btnRunInSingleTerminal;
    private JButton btnCancel;
    private JButton btnRunInSeparateTerminals;
    private JLabel lblCommandCount;
    private JButton btnReviewCommands;

    public SendToRunInTerminalBehaviourChoiceDialog(JFrame parent, ERunInTerminalBehaviour defaultChoice, int nrOfCommands) {
        this.parent = parent;
        this.choice = getDefaultChoice(defaultChoice);
        this.lblCommandCount.setText(String.valueOf(nrOfCommands));
        setContentPane(contentPane);
        setTitle("Select execution behaviour");
        setModal(true);

        btnRunInSeparateTerminals.addActionListener(e -> onButtonPress(EChoice.RUN_IN_SEPARATE_TERMINALS));
        btnRunInSingleTerminal.addActionListener(e -> onButtonPress(EChoice.RUN_IN_SINGLE_TERMINAL));
        btnReviewCommands.addActionListener(e -> onButtonPress(EChoice.REVIEW_COMMANDS));
        btnCancel.addActionListener(e -> onButtonPress(EChoice.CANCEL));

        // call onCancel() when cross is clicked
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                onCancel();
            }
        });

        // call onCancel() on ESCAPE
        contentPane.registerKeyboardAction(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onCancel();
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        this.pack();
        initButtonState(defaultChoice);
    }

    private void initButtonState(ERunInTerminalBehaviour defaultChoice) {
        switch (defaultChoice) {
            case RUN_IN_SEPARATE_TERMINALS:
                SwingUtilities.getRootPane(btnRunInSeparateTerminals).setDefaultButton(btnRunInSeparateTerminals);
                btnRunInSeparateTerminals.grabFocus();
                break;
            case RUN_IN_SINGLE_TERMINAL:
                // fall through
            default:
                SwingUtilities.getRootPane(btnRunInSingleTerminal).setDefaultButton(btnRunInSingleTerminal);
                btnRunInSingleTerminal.grabFocus();
        }
    }

    private EChoice getDefaultChoice(ERunInTerminalBehaviour defaultChoice) {
        switch (defaultChoice) {
            case RUN_IN_SEPARATE_TERMINALS:
                return EChoice.RUN_IN_SEPARATE_TERMINALS;
            case RUN_IN_SINGLE_TERMINAL:
                // fall through
            default:
                return EChoice.RUN_IN_SINGLE_TERMINAL;
        }
    }

    public EChoice run() {
        int x = DialogUtil.getX(parent, this);
        int y = DialogUtil.getY(parent, this);
        this.setLocation(x, y);
        this.setVisible(true);
        return choice;
    }

    private void onButtonPress(EChoice choice) {
        this.choice = choice;
        dispose();
    }

    private void onCancel() {
        this.choice = EChoice.CANCEL;
        dispose();
    }

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        contentPane = new JPanel();
        contentPane.setLayout(new GridLayoutManager(2, 1, new Insets(10, 10, 10, 10), -1, -1));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayoutManager(1, 6, new Insets(0, 0, 0, 0), -1, -1));
        contentPane.add(panel1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        panel1.add(spacer1, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        btnRunInSeparateTerminals = new JButton();
        btnRunInSeparateTerminals.setText("Run in separate terminals");
        btnRunInSeparateTerminals.setMnemonic('S');
        btnRunInSeparateTerminals.setDisplayedMnemonicIndex(7);
        panel1.add(btnRunInSeparateTerminals, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        btnCancel = new JButton();
        btnCancel.setText("Cancel");
        panel1.add(btnCancel, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer2 = new Spacer();
        panel1.add(spacer2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        btnReviewCommands = new JButton();
        btnReviewCommands.setText("Review commands");
        btnReviewCommands.setMnemonic('O');
        btnReviewCommands.setDisplayedMnemonicIndex(8);
        panel1.add(btnReviewCommands, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        btnRunInSingleTerminal = new JButton();
        btnRunInSingleTerminal.setText("Run in single terminal");
        btnRunInSingleTerminal.setMnemonic('I');
        btnRunInSingleTerminal.setDisplayedMnemonicIndex(8);
        panel1.add(btnRunInSingleTerminal, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayoutManager(2, 4, new Insets(0, 0, 0, 0), -1, -1));
        contentPane.add(panel2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JLabel label1 = new JLabel();
        label1.setText("Please select how the commands should be executed.");
        panel2.add(label1, new GridConstraints(1, 0, 1, 4, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label2 = new JLabel();
        label2.setText("You are going to execute");
        panel2.add(label2, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        lblCommandCount = new JLabel();
        lblCommandCount.setText("0");
        panel2.add(lblCommandCount, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label3 = new JLabel();
        label3.setText("commands.");
        panel2.add(label3, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer3 = new Spacer();
        panel2.add(spacer3, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return contentPane;
    }

}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTab.form
================================================
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.bytebutcher.burpsendtoextension.gui.SendToTab">
  <grid id="27dc6" binding="formPanel" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
    <margin top="10" left="10" bottom="10" right="10"/>
    <constraints>
      <xy x="20" y="20" width="729" height="556"/>
    </constraints>
    <properties/>
    <border type="none"/>
    <children>
      <grid id="f2af0" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
        <margin top="0" left="0" bottom="0" right="0"/>
        <constraints>
          <grid row="0" column="0" row-span="3" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <grid id="cba21" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="0" left="0" bottom="0" right="0"/>
            <constraints>
              <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <grid id="df57f" layout-manager="GridLayoutManager" row-count="6" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
                <margin top="0" left="0" bottom="0" right="0"/>
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties/>
                <border type="none"/>
                <children>
                  <component id="ace94" class="javax.swing.JButton" binding="btnRemove">
                    <constraints>
                      <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                    </constraints>
                    <properties>
                      <text value="Remove"/>
                    </properties>
                  </component>
                  <component id="cae4c" class="javax.swing.JButton" binding="btnEdit">
                    <constraints>
                      <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                    </constraints>
                    <properties>
                      <text value="Edit"/>
                    </properties>
                  </component>
                  <component id="3e059" class="javax.swing.JButton" binding="btnAdd">
                    <constraints>
                      <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                    </constraints>
                    <properties>
                      <text value="Add"/>
                    </properties>
                  </component>
                  <vspacer id="6bab6">
                    <constraints>
                      <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
                    </constraints>
                  </vspacer>
                  <component id="25cb2" class="javax.swing.JButton" binding="btnUp">
                    <constraints>
                      <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                    </constraints>
                    <properties>
                      <text value="Up"/>
                    </properties>
                  </component>
                  <component id="921f5" class="javax.swing.JButton" binding="btnDown">
                    <constraints>
                      <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                    </constraints>
                    <properties>
                      <text value="Down"/>
                    </properties>
                  </component>
                </children>
              </grid>
              <scrollpane id="84f17">
                <constraints>
                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties/>
                <border type="none"/>
                <children>
                  <component id="b4a94" class="javax.swing.JTable" binding="tblSendTo" custom-create="true">
                    <constraints/>
                    <properties/>
                  </component>
                </children>
              </scrollpane>
            </children>
          </grid>
          <component id="aa82c" class="javax.swing.JLabel">
            <constraints>
              <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Manage entries of the &quot;Send to...&quot; context menu."/>
            </properties>
          </component>
          <component id="b8d92" class="javax.swing.JLabel">
            <constraints>
              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <font name="Tahoma" size="14" style="1"/>
              <foreground color="-1341440"/>
              <text value="Context Menu Entries"/>
            </properties>
          </component>
          <grid id="a5939" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="2" left="2" bottom="2" right="2"/>
            <constraints>
              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false">
                <maximum-size width="26" height="26"/>
              </grid>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <component id="fc873" class="javax.swing.JLabel" binding="lblSettings">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value=""/>
                </properties>
              </component>
            </children>
          </grid>
          <grid id="4b9ac" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="2" left="2" bottom="2" right="2"/>
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false">
                <maximum-size width="26" height="26"/>
              </grid>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <component id="6b01d" class="javax.swing.JLabel" binding="lblHelp">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value=""/>
                </properties>
              </component>
            </children>
          </grid>
        </children>
      </grid>
      <grid id="1886c" layout-manager="GridLayoutManager" row-count="8" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
        <margin top="0" left="0" bottom="0" right="0"/>
        <constraints>
          <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties/>
        <border type="none"/>
        <children>
          <component id="9692c" class="javax.swing.JLabel">
            <constraints>
              <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <font name="Tahoma" size="14" style="1"/>
              <foreground color="-1341440"/>
              <text value="Terminal Options"/>
            </properties>
          </component>
          <grid id="659d" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="2" left="2" bottom="2" right="2"/>
            <constraints>
              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="3" indent="0" use-parent-layout="false">
                <minimum-size width="26" height="26"/>
                <maximum-size width="26" height="26"/>
              </grid>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <component id="d0ebd" class="javax.swing.JLabel">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value=""/>
                </properties>
              </component>
            </children>
          </grid>
          <component id="48258" class="javax.swing.JLabel">
            <constraints>
              <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="When multiple commands are going to be executed at once"/>
            </properties>
          </component>
          <component id="dc65d" class="javax.swing.JLabel">
            <constraints>
              <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Specify how to run commands in terminal:"/>
            </properties>
          </component>
          <grid id="f9cb9" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="0" left="0" bottom="0" right="0"/>
            <constraints>
              <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <component id="be92" class="javax.swing.JTextField" binding="txtRunInTerminal">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
                    <preferred-size width="150" height="-1"/>
                  </grid>
                </constraints>
                <properties>
                  <text value="/bin/bash -c {CMD}"/>
                </properties>
              </component>
              <component id="11e77" class="javax.swing.JButton" binding="btnRunInTerminalHelp">
                <constraints>
                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value="?"/>
                </properties>
              </component>
            </children>
          </grid>
          <component id="cb82a" class="javax.swing.JCheckBox" binding="chkShowRunInTerminalBehaviourChoiceDialog">
            <constraints>
              <grid row="6" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <text value="Show dialog to select execution behaviour when multiple commands are going to be executed"/>
            </properties>
          </component>
          <grid id="b191c" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="0" left="0" bottom="0" right="0"/>
            <constraints>
              <grid row="4" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <component id="f8f83" class="javax.swing.JRadioButton" binding="chkRunInSingleTerminal">
                <constraints>
                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value="execute commands sequential in single terminal"/>
                </properties>
              </component>
              <component id="9cac8" class="javax.swing.JLabel">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value="  "/>
                </properties>
              </component>
            </children>
          </grid>
          <grid id="fad08" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
            <margin top="0" left="0" bottom="0" right="0"/>
            <constraints>
              <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties/>
            <border type="none"/>
            <children>
              <component id="17ad9" class="javax.swing.JRadioButton" binding="chkRunInSeparateTerminals">
                <constraints>
                  <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value="execute commands in parallel in separate terminals"/>
                </properties>
              </component>
              <component id="a17fb" class="javax.swing.JLabel">
                <constraints>
                  <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
                </constraints>
                <properties>
                  <text value="  "/>
                </properties>
              </component>
            </children>
          </grid>
          <component id="6f3d4" class="javax.swing.JCheckBox" binding="chkSafeMode">
            <constraints>
              <grid row="7" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
            </constraints>
            <properties>
              <selected value="true"/>
              <text value="Surround placeholders with single quotes automatically (safe mode)"/>
            </properties>
          </component>
        </children>
      </grid>
      <vspacer id="39bff">
        <constraints>
          <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
        </constraints>
      </vspacer>
    </children>
  </grid>
  <buttonGroups>
    <group name="multi_command_handling">
      <member id="17ad9"/>
      <member id="17ad9"/>
      <member id="f8f83"/>
    </group>
  </buttonGroups>
</form>


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTab.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import burp.BurpExtender;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import net.bytebutcher.burpsendtoextension.gui.listener.ToolTipActionListener;
import net.bytebutcher.burpsendtoextension.gui.util.DialogUtil;
import net.bytebutcher.burpsendtoextension.gui.util.WebUtil;
import net.bytebutcher.burpsendtoextension.models.CommandObject;
import net.bytebutcher.burpsendtoextension.models.ERunInTerminalBehaviour;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.FontUIResource;
import javax.swing.text.StyleContext;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;

public class SendToTab {
    private BurpExtender burpExtender;
    private JButton btnRemove;
    private JButton btnEdit;
    private JButton btnAdd;
    private JTable tblSendTo;

    private SendToTable sendToTable;
    private JPanel formPanel;
    private JButton btnUp;
    private JButton btnDown;
    private JLabel lblSettings;
    private JLabel lblHelp;
    private JTextField txtRunInTerminal;
    private JButton btnRunInTerminalHelp;
    private JRadioButton chkRunInSingleTerminal;
    private JRadioButton chkRunInSeparateTerminals;
    private JCheckBox chkShowRunInTerminalBehaviourChoiceDialog;
    private JCheckBox chkSafeMode;
    private SendToTableListener sendToTableListener;
    private final SendToTabSettingsContextMenu sendToTabSettingsContextMenu;


    public SendToTab(final BurpExtender burpExtender) {
        this.burpExtender = burpExtender;
        $$$setupUI$$$();
        this.lblHelp.setIcon(this.burpExtender.createImageIcon("/panel_help.png", "", 24, 24));
        this.lblSettings.setIcon(this.burpExtender.createImageIcon("/panel_settings.png", "", 24, 24));
        this.sendToTableListener = new SendToTableListener(this.sendToTable);
        this.tblSendTo.getModel().addTableModelListener(sendToTableListener);
        btnAdd.addActionListener(e -> new Thread(() -> {
            SendToAddDialog addDialog = new SendToAddDialog(getParent(), "Add context menu entry", sendToTable.getCommandObjects());
            if (addDialog.run()) {
                sendToTableListener.onAddButtonClick(e, addDialog.getCommandObject());
            }
        }).start());
        btnEdit.addActionListener(e -> {
            CommandObject selectedCommandObject = sendToTable.getSelectedCommandObject();
            SendToAddDialog editDialog = new SendToAddDialog(getParent(), "Edit context menu entry", sendToTable.getCommandObjects(), selectedCommandObject);
            if (editDialog.run()) {
                sendToTableListener.onEditButtonClick(e, editDialog.getCommandObject());
            }
        });
        btnRemove.addActionListener(e -> {
            boolean result = DialogUtil.showConfirmationDialog(getParent(), "Delete context menu entries",
                    "Do you really want to delete the selected context menu entries?");
            if (result) {
                sendToTableListener.onRemoveButtonClick(e);
            }
        });
        btnUp.addActionListener(e -> sendToTableListener.onUpButtonClick(e));
        btnDown.addActionListener(e -> sendToTableListener.onDownButtonClick(e));
        lblHelp.addMouseListener(new LabelIconImageHoverAdapter(lblHelp, "/panel_help.png", "/panel_help_highlighted.png"));
        lblSettings.addMouseListener(new LabelIconImageHoverAdapter(lblSettings, "/panel_settings.png", "/panel_settings_highlighted.png"));
        lblHelp.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                try {
                    WebUtil.openWebpage(new URL("https://github.com/bytebutcher/burp-send-to"));
                } catch (MalformedURLException e1) {
                    // Nothing to do here...
                }
            }
        });
        sendToTabSettingsContextMenu = new SendToTabSettingsContextMenu(burpExtender, this);
        lblSettings.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                sendToTabSettingsContextMenu.show(lblSettings, lblSettings.getX() + lblSettings.getWidth(), lblSettings.getY());
            }
        });
        txtRunInTerminal.setText(BurpExtender.getConfig().getRunInTerminalCommand());
        txtRunInTerminal.getDocument().addDocumentListener(new DocumentListener() {
            public void changedUpdate(DocumentEvent e) {
                save();
            }

            public void removeUpdate(DocumentEvent e) {
                save();
            }

            public void insertUpdate(DocumentEvent e) {
                save();
            }

            public void save() {
                BurpExtender.getConfig().setRunInTerminalCommand(txtRunInTerminal.getText());
            }
        });
        btnRunInTerminalHelp.addActionListener(new ToolTipActionListener(btnRunInTerminalHelp, "" +
                "<html>" +
                "<p>%C = Command</p>" +
                "</html>")
        );
        chkRunInSingleTerminal.setSelected(BurpExtender.getConfig().getRunInTerminalBehaviour() == ERunInTerminalBehaviour.RUN_IN_SINGLE_TERMINAL);
        chkRunInSingleTerminal.addChangeListener(e -> {
            BurpExtender.getConfig().setRunInTerminalBehaviour(chkRunInSingleTerminal.isSelected() ? ERunInTerminalBehaviour.RUN_IN_SINGLE_TERMINAL : ERunInTerminalBehaviour.RUN_IN_SEPARATE_TERMINALS);
        });
        chkRunInSeparateTerminals.setSelected(BurpExtender.getConfig().getRunInTerminalBehaviour() == ERunInTerminalBehaviour.RUN_IN_SEPARATE_TERMINALS);
        chkRunInSeparateTerminals.addChangeListener(e -> {
            BurpExtender.getConfig().setRunInTerminalBehaviour(chkRunInSeparateTerminals.isSelected() ? ERunInTerminalBehaviour.RUN_IN_SEPARATE_TERMINALS : ERunInTerminalBehaviour.RUN_IN_SINGLE_TERMINAL);
        });
        chkShowRunInTerminalBehaviourChoiceDialog.setSelected(BurpExtender.getConfig().shouldShowRunInTerminalBehaviourChoiceDialog());
        chkShowRunInTerminalBehaviourChoiceDialog.addChangeListener(e -> BurpExtender.getConfig().shouldShowRunInTerminalBehaviourChoiceDialog(chkShowRunInTerminalBehaviourChoiceDialog.isSelected()));
        this.chkSafeMode.setSelected(BurpExtender.getConfig().isSafeModeActivated());
        this.chkSafeMode.addChangeListener(e -> BurpExtender.getConfig().setSafeMode(this.chkSafeMode.isSelected()));
    }

    public void resetOptions() {
        resetSendToTableData();
        resetRunInTerminalOption();
    }

    private void resetSendToTableData() {
        sendToTable.clearTable();
        sendToTable.addCommandObjects(BurpExtender.getConfig().getDefaultSendToTableData());
    }

    private void resetRunInTerminalOption() {
        BurpExtender.getConfig().resetRunInTerminalCommand();
        txtRunInTerminal.setText(BurpExtender.getConfig().getRunInTerminalCommand());
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        createUIComponents();
        formPanel = new JPanel();
        formPanel.setLayout(new GridLayoutManager(5, 1, new Insets(10, 10, 10, 10), -1, -1));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayoutManager(3, 2, new Insets(0, 0, 0, 0), -1, -1));
        formPanel.add(panel1, new GridConstraints(0, 0, 3, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
        panel1.add(panel2, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JPanel panel3 = new JPanel();
        panel3.setLayout(new GridLayoutManager(6, 1, new Insets(0, 0, 0, 0), -1, -1));
        panel2.add(panel3, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        btnRemove = new JButton();
        btnRemove.setText("Remove");
        panel3.add(btnRemove, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        btnEdit = new JButton();
        btnEdit.setText("Edit");
        panel3.add(btnEdit, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        btnAdd = new JButton();
        btnAdd.setText("Add");
        panel3.add(btnAdd, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        panel3.add(spacer1, new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        btnUp = new JButton();
        btnUp.setText("Up");
        panel3.add(btnUp, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        btnDown = new JButton();
        btnDown.setText("Down");
        panel3.add(btnDown, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JScrollPane scrollPane1 = new JScrollPane();
        panel2.add(scrollPane1, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        scrollPane1.setViewportView(tblSendTo);
        final JLabel label1 = new JLabel();
        label1.setText("Manage entries of the \"Send to...\" context menu.");
        panel1.add(label1, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label2 = new JLabel();
        Font label2Font = this.$$$getFont$$$("Tahoma", Font.BOLD, 14, label2.getFont());
        if (label2Font != null) label2.setFont(label2Font);
        label2.setForeground(new Color(-1341440));
        label2.setText("Context Menu Entries");
        panel1.add(label2, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel4 = new JPanel();
        panel4.setLayout(new GridLayoutManager(1, 1, new Insets(2, 2, 2, 2), -1, -1));
        panel1.add(panel4, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, new Dimension(26, 26), 0, false));
        lblSettings = new JLabel();
        lblSettings.setText("");
        panel4.add(lblSettings, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel5 = new JPanel();
        panel5.setLayout(new GridLayoutManager(1, 1, new Insets(2, 2, 2, 2), -1, -1));
        panel1.add(panel5, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, new Dimension(26, 26), 0, false));
        lblHelp = new JLabel();
        lblHelp.setText("");
        panel5.add(lblHelp, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel6 = new JPanel();
        panel6.setLayout(new GridLayoutManager(8, 2, new Insets(0, 0, 0, 0), -1, -1));
        formPanel.add(panel6, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JLabel label3 = new JLabel();
        Font label3Font = this.$$$getFont$$$("Tahoma", Font.BOLD, 14, label3.getFont());
        if (label3Font != null) label3.setFont(label3Font);
        label3.setForeground(new Color(-1341440));
        label3.setText("Terminal Options");
        panel6.add(label3, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel7 = new JPanel();
        panel7.setLayout(new GridLayoutManager(1, 1, new Insets(2, 2, 2, 2), -1, -1));
        panel6.add(panel7, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(26, 26), null, new Dimension(26, 26), 0, false));
        final JLabel label4 = new JLabel();
        label4.setText("");
        panel7.add(label4, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label5 = new JLabel();
        label5.setText("When multiple commands are going to be executed at once");
        panel6.add(label5, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label6 = new JLabel();
        label6.setText("Specify how to run commands in terminal:");
        panel6.add(label6, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel8 = new JPanel();
        panel8.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
        panel6.add(panel8, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        txtRunInTerminal = new JTextField();
        txtRunInTerminal.setText("/bin/bash -c {CMD}");
        panel8.add(txtRunInTerminal, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
        btnRunInTerminalHelp = new JButton();
        btnRunInTerminalHelp.setText("?");
        panel8.add(btnRunInTerminalHelp, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        chkShowRunInTerminalBehaviourChoiceDialog = new JCheckBox();
        chkShowRunInTerminalBehaviourChoiceDialog.setText("Show dialog to select execution behaviour when multiple commands are going to be executed");
        panel6.add(chkShowRunInTerminalBehaviourChoiceDialog, new GridConstraints(6, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel9 = new JPanel();
        panel9.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
        panel6.add(panel9, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        chkRunInSingleTerminal = new JRadioButton();
        chkRunInSingleTerminal.setText("execute commands sequential in single terminal");
        panel9.add(chkRunInSingleTerminal, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label7 = new JLabel();
        label7.setText("  ");
        panel9.add(label7, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel10 = new JPanel();
        panel10.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
        panel6.add(panel10, new GridConstraints(5, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        chkRunInSeparateTerminals = new JRadioButton();
        chkRunInSeparateTerminals.setText("execute commands in parallel in separate terminals");
        panel10.add(chkRunInSeparateTerminals, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label8 = new JLabel();
        label8.setText("  ");
        panel10.add(label8, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        chkSafeMode = new JCheckBox();
        chkSafeMode.setSelected(true);
        chkSafeMode.setText("Surround placeholders with single quotes automatically (safe mode)");
        panel6.add(chkSafeMode, new GridConstraints(7, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer2 = new Spacer();
        formPanel.add(spacer2, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        ButtonGroup buttonGroup;
        buttonGroup = new ButtonGroup();
        buttonGroup.add(chkRunInSeparateTerminals);
        buttonGroup.add(chkRunInSeparateTerminals);
        buttonGroup.add(chkRunInSingleTerminal);
    }

    /**
     * @noinspection ALL
     */
    private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) {
        if (currentFont == null) return null;
        String resultName;
        if (fontName == null) {
            resultName = currentFont.getName();
        } else {
            Font testFont = new Font(fontName, Font.PLAIN, 10);
            if (testFont.canDisplay('a') && testFont.canDisplay('1')) {
                resultName = fontName;
            } else {
                resultName = currentFont.getName();
            }
        }
        Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize());
        boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac");
        Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize());
        return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return formPanel;
    }

    class LabelIconImageHoverAdapter extends MouseAdapter {

        private String resource;
        private String resourceHovered;
        private JLabel label;

        public LabelIconImageHoverAdapter(JLabel label, String resource, String resourceHovered) {
            this.label = label;
            this.resource = resource;
            this.resourceHovered = resourceHovered;
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            label.setIcon(SendToTab.this.burpExtender.createImageIcon(resourceHovered, "", 24, 24));
        }

        @Override
        public void mouseExited(MouseEvent e) {
            label.setIcon(SendToTab.this.burpExtender.createImageIcon(resource, "", 24, 24));
        }
    }

    public JPanel getRootPanel() {
        return formPanel;
    }

    public JFrame getParent() {
        return (JFrame) SwingUtilities.getRootPane(this.getRootPanel()).getParent();
    }

    public SendToTable getSendToTable() {
        return sendToTable;
    }

    /**
     * Creates Custom GUI forms
     */
    private void createUIComponents() {
        this.tblSendTo = this.sendToTable = new SendToTable(this.burpExtender);
    }

    public SendToTableListener getSendToTableListener() {
        return this.sendToTableListener;
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTabSettingsContextMenu.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import burp.BurpExtender;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import net.bytebutcher.burpsendtoextension.gui.util.DialogUtil;
import net.bytebutcher.burpsendtoextension.models.CommandObject;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

class SendToTabSettingsContextMenu extends JPopupMenu {

    private BurpExtender burpExtender;
    private final JMenuItem restoreDefaults;
    private final JMenuItem loadOptions;
    private final JMenuItem saveOptions;

    private SendToTable sendToTable;
    private SendToTab sendToTab;

    public SendToTabSettingsContextMenu(final BurpExtender burpExtender, final SendToTab sendToTab) {
        this.burpExtender = burpExtender;
        this.sendToTab = sendToTab;
        this.sendToTable = sendToTab.getSendToTable();
        restoreDefaults = new JMenuItem("Restore defaults");
        restoreDefaults.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                boolean result = DialogUtil.showConfirmationDialog(sendToTab.getParent(), "Reset \"Send to\"-options",
                        "Do you really want to reset the \"Send to\"-options?");
                if (result) {
                    sendToTab.resetOptions();
                }
            }
        });
        add(restoreDefaults);
        loadOptions = new JMenuItem("Load options");
        loadOptions.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                burpExtender.getCallbacks().printOutput("Loading options...");
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setDialogTitle("Load \"Send to\" options from file...");
                fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
                int result = fileChooser.showOpenDialog(getParent());
                if (result == JFileChooser.APPROVE_OPTION) {
                    File selectedFile = fileChooser.getSelectedFile();
                    try {
                        burpExtender.getCallbacks().printOutput("Reading selected file: " + selectedFile.getAbsolutePath());
                        List<CommandObject> commandObjectList = new Gson().fromJson(new FileReader(selectedFile), new TypeToken<List<CommandObject>>(){}.getType());
                        burpExtender.getCallbacks().printOutput("Adding " + commandObjectList.size() + " items to table...");
                        sendToTable.removeAll();
                        sendToTable.addCommandObjects(commandObjectList);
                        burpExtender.getCallbacks().printOutput("Successfully loaded options into table!");
                    } catch (FileNotFoundException e1) {
                        DialogUtil.showErrorDialog(
                                sendToTab.getParent(),
                                "Error while loading options!",
                                "<html><p>There was an unknown error while loading the options!</p>" +
                                        "<p>For more information check out the \"Send to\" extension error log!</p></html>"
                        );
                        burpExtender.getCallbacks().printError("Error while loading options: " + e1);
                        return;
                    } catch (Exception e2) {
                        burpExtender.getCallbacks().printError("Error while loading options: " + e2);
                        return;
                    }
                }
            }
        });
        add(loadOptions);
        saveOptions = new JMenuItem("Save options");
        saveOptions.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JFileChooser fileChooser = new JFileChooser();
                fileChooser.setDialogTitle("Save \"Send to\" options to file...");

                int userSelection = fileChooser.showSaveDialog(getParent());
                if (userSelection == JFileChooser.APPROVE_OPTION) {
                    File fileToSave = fileChooser.getSelectedFile();
                    String json = new Gson().toJson(sendToTable.getCommandObjects());
                    try (PrintWriter out = new PrintWriter(fileToSave)) {
                        out.write(json);
                    } catch (FileNotFoundException e1) {
                        DialogUtil.showErrorDialog(
                                sendToTab.getParent(),
                                "Error while saving options!",
                                "<html><p>There was an unknown error while saving the options!</p>" +
                                        "<p>For more information check out the \"Send to\" extension error log!</p></html>"
                        );
                        burpExtender.getCallbacks().printError("Error while saving options: " + e1);
                        return;
                    }
                    burpExtender.getCallbacks().printOutput("Successfully saved options in '" + fileToSave.getAbsolutePath() + "'!");
                }
            }
        });
        add(saveOptions);
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTable.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import burp.BurpExtender;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import net.bytebutcher.burpsendtoextension.models.CommandObject;
import net.bytebutcher.burpsendtoextension.models.ERuntimeBehaviour;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
import java.util.*;
import java.util.stream.Collectors;

public class SendToTable extends JTable {

    private final DefaultTableModel defaultModel;
    private BurpExtender burpExtender;

    private enum Column {
        ID(0),
        NAME(1),
        COMMAND(2),
        GROUP(3),
        RUNTIME_BEHAVIOUR(4),
        SHOW_PREVIEW(5),
        PLACEHOLDERS(6);

        private final int index;

        Column(int id) {
            this.index = id;
        }

        public int getIndex() {
            return index;
        }
    }

    private class SendToTableModel extends DefaultTableModel {

        private boolean areEventsBlocked;

        @Override
        public boolean isCellEditable(int row, int column) {
            return false;
        }

        @Override
        public void fireTableChanged(TableModelEvent e) {
            if (!areEventsBlocked) {
                super.fireTableChanged(e);
            }
        }

        public void setBlockEvents(boolean areEventsBlocked) {
            this.areEventsBlocked = areEventsBlocked;
        }
    }

    public SendToTable(BurpExtender burpExtender) {
        this.burpExtender = burpExtender;
        this.defaultModel = new SendToTableModel();
        this.defaultModel.addColumn("Id");
        this.defaultModel.addColumn("Name");
        this.defaultModel.addColumn("Command");
        this.defaultModel.addColumn("Group name");
        this.defaultModel.addColumn("Runtime behaviour");
        this.defaultModel.addColumn("Show preview");
        this.defaultModel.addColumn("Placeholder behaviour");
        setModel(this.defaultModel);
        hideColumns(Column.ID, Column.COMMAND, Column.PLACEHOLDERS);
    }

    private void hideColumns(Column ... c) {
        List<Column> collect = Arrays.stream(c).sorted(Comparator.comparingInt(Column::getIndex).reversed()).collect(Collectors.toList());
        for (Column column : collect) {
            this.removeColumn(this.getColumnModel().getColumn(column.getIndex()));
        }
    }

    public CommandObject getSelectedCommandObject() {
        int[] selectedRows = this.getSelectedRows();
        if (selectedRows.length > 0) {
            int selectedRow = selectedRows[0];
            return getCommandObjectByRowIndex(selectedRow);
        }
        throw new IllegalStateException("No row selected!");
    }

    public DefaultTableModel getDefaultModel() {
        return defaultModel;
    }

    public String getSelectedNames() {
        int[] selectedRows = this.getSelectedRows();
        if (selectedRows.length > 0) {
            int selectedRow = selectedRows[0];
            return getNameByRowIndex(selectedRow);
        }
        throw new IllegalStateException("No row selected!");
    }

    private String getNameByRowIndex(int rowIndex) {
        return Optional.ofNullable(this.getModel().getValueAt(rowIndex, Column.NAME.getIndex())).orElse("").toString();
    }

    private boolean getShowPreviewByRowIndex(int rowIndex) {
        return Boolean.parseBoolean(Optional.ofNullable(this.getModel().getValueAt(rowIndex, Column.SHOW_PREVIEW.getIndex())).orElse("").toString());
    }

    private ERuntimeBehaviour getRuntimeBehaviourByRowIndex(int rowIndex) {
        return ERuntimeBehaviour.getEnum(Optional.ofNullable(this.getModel().getValueAt(rowIndex, Column.RUNTIME_BEHAVIOUR.getIndex())).orElse("").toString());
    }

    private String getGroupByRowIndex(int rowIndex) {
        return Optional.ofNullable(this.getModel().getValueAt(rowIndex, Column.GROUP.getIndex())).orElse("").toString();
    }

    private String getCommandByRowIndex(int rowIndex) {
        return Optional.ofNullable(this.getModel().getValueAt(rowIndex, Column.COMMAND.getIndex())).orElse("").toString();
    }

    private List<CommandObject.Placeholder> getPlaceholders(int rowIndex) {
        try {
            return Lists.newArrayList((List<CommandObject.Placeholder>) this.getModel().getValueAt(rowIndex, Column.PLACEHOLDERS.getIndex()));
        } catch (Exception e) {
            BurpExtender.printErr("Casting of placeholder behaviour failed for row " + rowIndex);
            return Lists.newArrayList();
        }
    }

    public List<CommandObject> getCommandObjects() {
        List<CommandObject> commandObjects = Lists.newArrayList();
        for (int i = 0; i < this.getDefaultModel().getRowCount(); i++) {
            commandObjects.add(getCommandObjectByRowIndex(i));
        }
        return commandObjects;
    }

    private CommandObject getCommandObjectByRowIndex(int rowIndex) {
        String id = this.getModel().getValueAt(rowIndex, Column.ID.getIndex()).toString();
        String name = getNameByRowIndex(rowIndex);
        String command = getCommandByRowIndex(rowIndex);
        String group = getGroupByRowIndex(rowIndex);
        ERuntimeBehaviour runtimeBehaviour = getRuntimeBehaviourByRowIndex(rowIndex);
        boolean showPreview = getShowPreviewByRowIndex(rowIndex);
        List<CommandObject.Placeholder> placeholders = getPlaceholders(rowIndex);
        return new CommandObject(id, name, command, group, runtimeBehaviour, showPreview, placeholders);
    }

    public CommandObject getCommandObjectById(String commandId) {
        if (commandId == null) {
            BurpExtender.printErr("CommandObject id should not be null!");
            throw new IllegalArgumentException("CommandObject id should not be null!");
        }
        for (int i = 0; i < this.getDefaultModel().getRowCount(); i++) {
            CommandObject commandObject = getCommandObjectByRowIndex(i);
            if (commandId.equals(commandObject.getId())) {
                return commandObject;
            }
        }
        BurpExtender.printErr("No command found with the specified id!");
        throw new IllegalStateException("No command found with the specified id!");
    }

    public void addCommandObjects(List<CommandObject> commandObjectList) {
        for (CommandObject commandObject : commandObjectList) {
            addCommandObject(commandObject);
        }
    }

    public void addCommandObject(CommandObject commandObject) {
        getDefaultModel().addRow(new Object[]{
                commandObject.getId(),
                commandObject.getName(),
                commandObject.getFormat(),
                commandObject.getGroup(),
                commandObject.getRuntimeBehaviour().alternateName(),
                commandObject.shouldShowPreview(),
                commandObject.getPlaceholders()
        });
    }

    public void editSelectedCommandObject(CommandObject commandObject) {
        int selectedRowIndex = this.getSelectedRow();
        if (selectedRowIndex >= 0) {
            editRow(selectedRowIndex, commandObject);
        }
    }

    private void editRow(int rowIndex, CommandObject commandObject) {
        DefaultTableModel model = getDefaultModel();
        ((SendToTableModel) getDefaultModel()).setBlockEvents(true);
        model.setValueAt(commandObject.getId(), rowIndex, Column.ID.getIndex());
        model.setValueAt(commandObject.getName(), rowIndex, Column.NAME.getIndex());
        model.setValueAt(commandObject.getGroup(), rowIndex, Column.GROUP.getIndex());
        model.setValueAt(commandObject.getFormat(), rowIndex, Column.COMMAND.getIndex());
        model.setValueAt(commandObject.getRuntimeBehaviour().alternateName(), rowIndex, Column.RUNTIME_BEHAVIOUR.getIndex());
        model.setValueAt(commandObject.shouldShowPreview(), rowIndex, Column.SHOW_PREVIEW.getIndex());
        model.setValueAt(commandObject.getPlaceholders(), rowIndex, Column.PLACEHOLDERS.getIndex());
        ((SendToTableModel) getDefaultModel()).setBlockEvents(false);
        getDefaultModel().fireTableDataChanged();
    }

    public void editCommandObject(CommandObject commandObject) {
        for (int i = 0; i < this.getDefaultModel().getRowCount(); i++) {
            CommandObject commandObjectFromRow = getCommandObjectByRowIndex(i);
            if (commandObjectFromRow.getId().equals(commandObject.getId())) {
                editRow(i, commandObject);
                return;
            }
        }
    }

    public void removeSelectedRow() {
        List<Integer> rows = Ints.asList(this.getSelectedRows());
        Collections.sort(rows, Collections.reverseOrder());
        for (Integer row : rows) {
            getDefaultModel().removeRow(row);
        }
    }

    public void clearTable() {
        for (int row = this.getRowCount() - 1; row >= 0; row--) {
            getDefaultModel().removeRow(row);
        }
    }

    public void moveSelectedRowUp() {
        moveRowBy(-1);
    }

    public void moveSelectedRowDown() {
        moveRowBy(1);
    }

    private void moveRowBy(int index) {
        DefaultTableModel model = (DefaultTableModel) this.getModel();
        int[] rows = this.getSelectedRows();
        int destination = rows[0] + index;
        int rowCount = model.getRowCount();

        if (destination < 0 || destination >= rowCount) {
            return;
        }

        model.moveRow(rows[0], rows[rows.length - 1], destination);
        this.setRowSelectionInterval(rows[0] + index, rows[rows.length - 1] + index);
    }

    @Override
    public void removeAll() {
        DefaultTableModel model = (DefaultTableModel) this.getModel();
        for (int i = 0; i < model.getRowCount(); i++) {
            model.removeRow(i);
        }
    }
}


================================================
FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTableListener.java
================================================
package net.bytebutcher.burpsendtoextension.gui;

import burp.BurpExtender;
import net.bytebutcher.burpsendtoextension.models.CommandObject;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

public class SendToTableListener implements TableModelListener {

    private SendToTable sendToTable;

    public SendToTableListener(SendToTable sendToTable) {
        this.sendToTable = sendToTable;
    }

    @Override
    public void tableChanged(TableModelEvent e) {
        BurpExtender.getConfig().saveSendToTableData(sendToTable.getCommandObjects());
    }

    public void onAddButtonClick(ActionEvent e, CommandObject commandObject) {
        sendToTable.addCommandObject(commandObject);
    }

    public void onEditButtonClick(ActionEvent e, CommandObject commandObject) {
        sendToTable.editSelectedCommandObject(commandObject);
    }

    public void onRemoveButtonClick(ActionEvent e) {
        sendToTable.removeSelectedRow();
    }

    public void onUpButtonClick(ActionEvent e) {
        sendToTable.moveSelectedRowUp();
    }

    public void onDownButtonClick(ActionEvent e) {
        sendToTable.moveSelectedRowDown();
    }

    public void onShowPreviewChange(ActionEvent e, String commandId, boolean showPreview) {
        CommandObject commandObject = sendToTable.getCommandObjectById(commandId);
        commandObject.setShowPreview(showPreview);
    
Download .txt
gitextract_4gomkmw3/

├── .gitignore
├── BappDescription.html
├── BappManifest.bmf
├── README.md
└── burp-send-to-extension/
    ├── build.gradle
    ├── gradle/
    │   └── wrapper/
    │       ├── gradle-wrapper.jar
    │       └── gradle-wrapper.properties
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle
    └── src/
        └── main/
            └── java/
                ├── burp/
                │   ├── BurpExtender.java
                │   ├── Cookie.java
                │   ├── IRequestInfoWrapper.java
                │   ├── IRequestResponseHolder.java
                │   ├── IResponseInfoWrapper.java
                │   ├── RequestInfoWrapper.java
                │   ├── RequestResponseHolder.java
                │   └── ResponseInfoWrapper.java
                ├── com/
                │   └── google/
                │       └── gson/
                │           └── typeadapters/
                │               └── RuntimeTypeAdapterFactory.java
                └── net/
                    └── bytebutcher/
                        └── burpsendtoextension/
                            ├── builder/
                            │   └── CommandBuilder.java
                            ├── executioner/
                            │   └── CommandExecutioner.java
                            ├── gui/
                            │   ├── CommandsChangeListener.java
                            │   ├── SendToAddAdvancedDialog.form
                            │   ├── SendToAddAdvancedDialog.java
                            │   ├── SendToAddAdvancedPlaceholderBehaviourPanel.form
                            │   ├── SendToAddAdvancedPlaceholderBehaviourPanel.java
                            │   ├── SendToAddDialog.form
                            │   ├── SendToAddDialog.java
                            │   ├── SendToContextMenu.java
                            │   ├── SendToContextMenuItem.java
                            │   ├── SendToPreviewDialog.form
                            │   ├── SendToPreviewDialog.java
                            │   ├── SendToRunInTerminalBehaviourChoiceDialog.form
                            │   ├── SendToRunInTerminalBehaviourChoiceDialog.java
                            │   ├── SendToTab.form
                            │   ├── SendToTab.java
                            │   ├── SendToTabSettingsContextMenu.java
                            │   ├── SendToTable.java
                            │   ├── SendToTableListener.java
                            │   ├── action/
                            │   │   └── SendToContextMenuItemAction.java
                            │   ├── listener/
                            │   │   └── ToolTipActionListener.java
                            │   └── util/
                            │       ├── DialogUtil.java
                            │       ├── SelectionUtil.java
                            │       └── WebUtil.java
                            ├── models/
                            │   ├── CommandObject.java
                            │   ├── Config.java
                            │   ├── Context.java
                            │   ├── ERunInTerminalBehaviour.java
                            │   ├── ERuntimeBehaviour.java
                            │   ├── Placeholders.java
                            │   └── placeholder/
                            │       ├── AbstractPlaceholder.java
                            │       ├── AbstractRequestInfoPlaceholder.java
                            │       ├── AbstractRequestPlaceholder.java
                            │       ├── AbstractRequestResponseInfoPlaceholder.java
                            │       ├── AbstractRequestResponsePlaceholder.java
                            │       ├── AbstractRequestResponsePlaceholderBase.java
                            │       ├── CookiesPlaceholder.java
                            │       ├── HostPlaceholder.java
                            │       ├── HttpBodyToFilePlaceholder.java
                            │       ├── HttpContentLengthPlaceholder.java
                            │       ├── HttpHeadersToFilePlaceholder.java
                            │       ├── HttpMethodPlaceholder.java
                            │       ├── HttpRequestResponsePlaceholder.java
                            │       ├── HttpStatusCodePlaceholder.java
                            │       ├── IPlaceholder.java
                            │       ├── IPlaceholderParser.java
                            │       ├── IPlaceholderParserFactory.java
                            │       ├── PortPlaceholder.java
                            │       ├── ProtocolPlaceholder.java
                            │       ├── SelectedTextPlaceholder.java
                            │       ├── SelectedTextToFilePlaceholder.java
                            │       ├── UrlPathPlaceholder.java
                            │       ├── UrlPlaceholder.java
                            │       ├── UrlQueryPlaceholder.java
                            │       └── behaviour/
                            │           ├── CommandSeparatedPlaceholderBehaviour.java
                            │           ├── FileSeparatedPlaceholderBehaviour.java
                            │           ├── IPlaceholderBehaviour.java
                            │           └── StringSeparatedPlaceholderBehaviour.java
                            └── utils/
                                ├── OsUtils.java
                                └── StringUtils.java
Download .txt
SYMBOL INDEX (417 symbols across 64 files)

FILE: burp-send-to-extension/src/main/java/burp/BurpExtender.java
  class BurpExtender (line 12) | public class BurpExtender implements IBurpExtender, ITab {
    method registerExtenderCallbacks (line 25) | @Override
    method initLogHandler (line 46) | private void initLogHandler(IBurpExtenderCallbacks callbacks) {
    method getTabCaption (line 51) | @Override
    method getUiComponent (line 56) | @Override
    method createImageIcon (line 61) | public ImageIcon createImageIcon(String path, String description, int ...
    method getParent (line 73) | public static JFrame getParent() {
    method getCallbacks (line 77) | public static IBurpExtenderCallbacks getCallbacks() {
    method getConfig (line 81) | public static Config getConfig() {
    method printOut (line 85) | public static void printOut(String s) {
    method printErr (line 89) | public static void printErr(String s) {

FILE: burp-send-to-extension/src/main/java/burp/Cookie.java
  class Cookie (line 14) | public class Cookie implements ICookie {
    method Cookie (line 25) | public Cookie(String name, String value) {
    method Cookie (line 30) | public Cookie(ICookie cookie) {
    method parseResponseCookies (line 45) | public static List<ICookie> parseResponseCookies(List<String> rawCooki...
    method parseResponseCookie (line 56) | private static Optional<ICookie> parseResponseCookie(String rawCookie) {
    method parseRequestCookies (line 122) | public static List<ICookie> parseRequestCookies(List<String> rawCookie...
    method parseRequestCookies (line 133) | public static List<ICookie> parseRequestCookies(String rawCookie) {
    method getName (line 158) | @Override
    method setName (line 163) | public void setName(String name) {
    method getValue (line 167) | @Override
    method setValue (line 172) | public void setValue(String value) {
    method getDomain (line 176) | @Override
    method setDomain (line 181) | public void setDomain(String domain) {
    method getPath (line 185) | @Override
    method setPath (line 190) | public void setPath(String path) {
    method getExpiration (line 194) | @Override
    method setExpiration (line 199) | public void setExpiration(Date expiration) {
    method getMaxAge (line 203) | public Long getMaxAge() {
    method setMaxAge (line 207) | public void setMaxAge(Long maxAge) {
    method getSecure (line 211) | public Boolean getSecure() {
    method setSecure (line 215) | public void setSecure(Boolean secure) {
    method getHttpOnly (line 219) | public Boolean getHttpOnly() {
    method setHttpOnly (line 223) | public void setHttpOnly(Boolean httpOnly) {
    method equals (line 227) | @Override
    method hashCode (line 242) | @Override

FILE: burp-send-to-extension/src/main/java/burp/IRequestInfoWrapper.java
  type IRequestInfoWrapper (line 5) | public interface IRequestInfoWrapper extends IRequestInfo {
    method getCookies (line 7) | List<ICookie> getCookies();
    method getBody (line 8) | String getBody();

FILE: burp-send-to-extension/src/main/java/burp/IRequestResponseHolder.java
  type IRequestResponseHolder (line 3) | public interface IRequestResponseHolder {
    method getRequestInfo (line 4) | IRequestInfo getRequestInfo();
    method getResponseInfo (line 6) | IResponseInfo getResponseInfo();
    method getBurpExtenderCallbacks (line 8) | IBurpExtenderCallbacks getBurpExtenderCallbacks();
    method getHttpRequestResponse (line 10) | IHttpRequestResponse getHttpRequestResponse();

FILE: burp-send-to-extension/src/main/java/burp/IResponseInfoWrapper.java
  type IResponseInfoWrapper (line 5) | public interface IResponseInfoWrapper extends IResponseInfo {
    method getCookies (line 7) | List<ICookie> getCookies();
    method getBody (line 8) | String getBody();

FILE: burp-send-to-extension/src/main/java/burp/RequestInfoWrapper.java
  class RequestInfoWrapper (line 8) | public class RequestInfoWrapper implements IRequestInfoWrapper {
    method RequestInfoWrapper (line 15) | public RequestInfoWrapper(IHttpRequestResponse httpRequestResponse, IR...
    method getCookies (line 20) | @Override
    method getBody (line 29) | @Override
    method getMethod (line 39) | @Override
    method getUrl (line 44) | @Override
    method getHeaders (line 49) | @Override
    method getParameters (line 54) | @Override
    method getBodyOffset (line 59) | @Override
    method getContentType (line 64) | @Override

FILE: burp-send-to-extension/src/main/java/burp/RequestResponseHolder.java
  class RequestResponseHolder (line 3) | public class RequestResponseHolder implements IRequestResponseHolder {
    method RequestResponseHolder (line 10) | public RequestResponseHolder(IBurpExtenderCallbacks burpExtenderCallba...
    method getRequestInfo (line 15) | @Override
    method getResponseInfo (line 23) | @Override
    method getBurpExtenderCallbacks (line 31) | @Override
    method getHttpRequestResponse (line 36) | @Override

FILE: burp-send-to-extension/src/main/java/burp/ResponseInfoWrapper.java
  class ResponseInfoWrapper (line 7) | public class ResponseInfoWrapper implements IResponseInfoWrapper {
    method ResponseInfoWrapper (line 14) | public ResponseInfoWrapper(IHttpRequestResponse httpRequestResponse, I...
    method getHeaders (line 19) | @Override
    method getBodyOffset (line 24) | @Override
    method getStatusCode (line 29) | @Override
    method getCookies (line 34) | @Override
    method getStatedMimeType (line 43) | @Override
    method getInferredMimeType (line 48) | @Override
    method getBody (line 53) | @Override

FILE: burp-send-to-extension/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java
  class RuntimeTypeAdapterFactory (line 130) | public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFa...
    method RuntimeTypeAdapterFactory (line 137) | private RuntimeTypeAdapterFactory(Class<?> baseType, String typeFieldN...
    method of (line 151) | public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, S...
    method of (line 159) | public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType, S...
    method of (line 167) | public static <T> RuntimeTypeAdapterFactory<T> of(Class<T> baseType) {
    method registerSubtype (line 178) | public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T>...
    method registerSubtype (line 197) | public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T>...
    method create (line 201) | public <R> TypeAdapter<R> create(Gson gson, TypeToken<R> type) {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/builder/CommandBuilder.java
  class CommandBuilder (line 21) | public class CommandBuilder {
    class Placeholder (line 34) | private static class Placeholder {
      method Placeholder (line 39) | public Placeholder(CommandObject.Placeholder placeholder) {
      method equals (line 44) | @Override
      method hashCode (line 52) | @Override
    method CommandBuilder (line 58) | public CommandBuilder(CommandObject commandObject, List<Map<String, IP...
    method initPlaceholderValues (line 65) | public Map<Placeholder, String> initPlaceholderValues() throws Excepti...
    method build (line 92) | public String build() throws Exception {
    method buildByMessage (line 113) | private String buildByMessage(int messageIndex) throws Exception {
    method replaceCommandPlaceholder (line 125) | private void replaceCommandPlaceholder(CommandObject.Placeholder place...
    method writeToFile (line 137) | private String writeToFile(String value) throws Exception {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/executioner/CommandExecutioner.java
  class CommandExecutioner (line 19) | public class CommandExecutioner {
    method CommandExecutioner (line 25) | public CommandExecutioner(boolean shouldOutputReplaceSelection, Contex...
    method CommandExecutioner (line 31) | public CommandExecutioner(ERunInTerminalBehaviour runInTerminalBehavio...
    method execute (line 37) | public void execute(String commands) throws Exception {
    method execute (line 56) | private void execute(String command, List<String> commandOutput) throw...
    method getProcessBuilder (line 65) | private ProcessBuilder getProcessBuilder(String command) {
    method formatCommandForRunningOnOperatingSystem (line 73) | private String[] formatCommandForRunningOnOperatingSystem(String comma...
    method formatCommandForRunningInTerminal (line 83) | private String[] formatCommandForRunningInTerminal(String command) {
    method replaceSelectedText (line 94) | private void replaceSelectedText(Context context, String replaceText) ...
    method logCommandToBeExecuted (line 108) | private void logCommandToBeExecuted(String[] commandToBeExecuted) {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/CommandsChangeListener.java
  type CommandsChangeListener (line 7) | public interface CommandsChangeListener {
    method commandsChanged (line 9) | void commandsChanged(List<CommandObject> commandObjects);

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedDialog.java
  class SendToAddAdvancedDialog (line 15) | public class SendToAddAdvancedDialog extends JDialog {
    method SendToAddAdvancedDialog (line 25) | public SendToAddAdvancedDialog(Component parent, List<CommandObject.Pl...
    method getPlaceholders (line 63) | public List<CommandObject.Placeholder> getPlaceholders() {
    method onOK (line 71) | private void onOK() {
    method onCancel (line 76) | private void onCancel() {
    method run (line 81) | public boolean run() {
    method $$$setupUI$$$ (line 101) | private void $$$setupUI$$$() {
    method $$$getRootComponent$$$ (line 136) | public JComponent $$$getRootComponent$$$() {
    method createUIComponents (line 140) | private void createUIComponents() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedPlaceholderBehaviourPanel.java
  class SendToAddAdvancedPlaceholderBehaviourPanel (line 17) | public class SendToAddAdvancedPlaceholderBehaviourPanel extends JPanel {
    method SendToAddAdvancedPlaceholderBehaviourPanel (line 26) | public SendToAddAdvancedPlaceholderBehaviourPanel(CommandObject.Placeh...
    method initFields (line 34) | private void initFields() {
    method initEventListener (line 51) | private void initEventListener() {
    method getPlaceholder (line 65) | public CommandObject.Placeholder getPlaceholder() {
    method $$$setupUI$$$ (line 94) | private void $$$setupUI$$$() {
    method $$$getRootComponent$$$ (line 114) | public JComponent $$$getRootComponent$$$() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddDialog.java
  class SendToAddDialog (line 21) | public class SendToAddDialog {
    method SendToAddDialog (line 44) | public SendToAddDialog(JFrame parent, String title, List<CommandObject...
    method SendToAddDialog (line 52) | public SendToAddDialog(JFrame parent, String title, List<CommandObject...
    method initKeyboardShortcuts (line 65) | private void initKeyboardShortcuts() {
    method bindKeyStrokeToAction (line 70) | private void bindKeyStrokeToAction(String keyStroke, Action action) {
    method initEventListener (line 77) | private void initEventListener() {
    method initButtonState (line 166) | private void initButtonState() {
    method initDialog (line 170) | private JDialog initDialog(JFrame parent, String title) {
    method run (line 181) | public boolean run() {
    method getRootPanel (line 186) | private JPanel getRootPanel() {
    method getName (line 190) | private String getName() {
    method getCommand (line 194) | private String getCommand() {
    method getGroup (line 198) | private String getGroup() {
    method getRuntimeBehaviour (line 202) | private ERuntimeBehaviour getRuntimeBehaviour() {
    method shouldShowPreview (line 216) | private boolean shouldShowPreview() {
    method getPlaceholders (line 220) | private List<CommandObject.Placeholder> getPlaceholders() {
    method getCommandObject (line 224) | public CommandObject getCommandObject() {
    method $$$setupUI$$$ (line 242) | private void $$$setupUI$$$() {
    method $$$getRootComponent$$$ (line 385) | public JComponent $$$getRootComponent$$$() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToContextMenu.java
  class SendToContextMenu (line 18) | public class SendToContextMenu implements IContextMenuFactory {
    method SendToContextMenu (line 23) | public SendToContextMenu(BurpExtender burpExtender, SendToTableListene...
    method createMenuItems (line 28) | @Override
    method addMenuItem (line 64) | private void addMenuItem(JMenu menu, CommandObject commandObject, List...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToContextMenuItem.java
  class SendToContextMenuItem (line 12) | public class SendToContextMenuItem extends JMenuItem {
    method SendToContextMenuItem (line 14) | public SendToContextMenuItem(String title, CommandObject commandObject...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToPreviewDialog.java
  class SendToPreviewDialog (line 13) | public class SendToPreviewDialog {
    method SendToPreviewDialog (line 27) | public SendToPreviewDialog(JFrame parent, String title, final String c...
    method SendToPreviewDialog (line 34) | public SendToPreviewDialog(JFrame parent, String title, final String c...
    method initEventListener (line 40) | private void initEventListener() {
    method initEventListener (line 59) | private void initEventListener(final String commandId, final SendToTab...
    method initDialog (line 69) | private JDialog initDialog(JFrame parent, String title) {
    method initKeyboardShortcuts (line 80) | private void initKeyboardShortcuts() {
    method bindKeyStrokeToAction (line 85) | private void bindKeyStrokeToAction(String keyStroke, Action action) {
    method run (line 92) | public boolean run() {
    method getCommand (line 97) | public String getCommand() {
    method getRootPanel (line 101) | private Component getRootPanel() {
    method $$$setupUI$$$ (line 119) | private void $$$setupUI$$$() {
    method $$$getRootComponent$$$ (line 154) | public JComponent $$$getRootComponent$$$() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToRunInTerminalBehaviourChoiceDialog.java
  class SendToRunInTerminalBehaviourChoiceDialog (line 13) | public class SendToRunInTerminalBehaviourChoiceDialog extends JDialog {
    type EChoice (line 17) | public enum EChoice {
    method SendToRunInTerminalBehaviourChoiceDialog (line 32) | public SendToRunInTerminalBehaviourChoiceDialog(JFrame parent, ERunInT...
    method initButtonState (line 63) | private void initButtonState(ERunInTerminalBehaviour defaultChoice) {
    method getDefaultChoice (line 77) | private EChoice getDefaultChoice(ERunInTerminalBehaviour defaultChoice) {
    method run (line 88) | public EChoice run() {
    method onButtonPress (line 96) | private void onButtonPress(EChoice choice) {
    method onCancel (line 101) | private void onCancel() {
    method $$$setupUI$$$ (line 120) | private void $$$setupUI$$$() {
    method $$$getRootComponent$$$ (line 170) | public JComponent $$$getRootComponent$$$() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTab.java
  class SendToTab (line 25) | public class SendToTab {
    method SendToTab (line 48) | public SendToTab(final BurpExtender burpExtender) {
    method resetOptions (line 135) | public void resetOptions() {
    method resetSendToTableData (line 140) | private void resetSendToTableData() {
    method resetRunInTerminalOption (line 145) | private void resetRunInTerminalOption() {
    method $$$setupUI$$$ (line 157) | private void $$$setupUI$$$() {
    method $$$getFont$$$ (line 278) | private Font $$$getFont$$$(String fontName, int style, int size, Font ...
    method $$$getRootComponent$$$ (line 300) | public JComponent $$$getRootComponent$$$() {
    class LabelIconImageHoverAdapter (line 304) | class LabelIconImageHoverAdapter extends MouseAdapter {
      method LabelIconImageHoverAdapter (line 310) | public LabelIconImageHoverAdapter(JLabel label, String resource, Str...
      method mouseEntered (line 316) | @Override
      method mouseExited (line 321) | @Override
    method getRootPanel (line 327) | public JPanel getRootPanel() {
    method getParent (line 331) | public JFrame getParent() {
    method getSendToTable (line 335) | public SendToTable getSendToTable() {
    method createUIComponents (line 342) | private void createUIComponents() {
    method getSendToTableListener (line 346) | public SendToTableListener getSendToTableListener() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTabSettingsContextMenu.java
  class SendToTabSettingsContextMenu (line 19) | class SendToTabSettingsContextMenu extends JPopupMenu {
    method SendToTabSettingsContextMenu (line 29) | public SendToTabSettingsContextMenu(final BurpExtender burpExtender, f...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTable.java
  class SendToTable (line 15) | public class SendToTable extends JTable {
    type Column (line 20) | private enum Column {
      method Column (line 31) | Column(int id) {
      method getIndex (line 35) | public int getIndex() {
    class SendToTableModel (line 40) | private class SendToTableModel extends DefaultTableModel {
      method isCellEditable (line 44) | @Override
      method fireTableChanged (line 49) | @Override
      method setBlockEvents (line 56) | public void setBlockEvents(boolean areEventsBlocked) {
    method SendToTable (line 61) | public SendToTable(BurpExtender burpExtender) {
    method hideColumns (line 75) | private void hideColumns(Column ... c) {
    method getSelectedCommandObject (line 82) | public CommandObject getSelectedCommandObject() {
    method getDefaultModel (line 91) | public DefaultTableModel getDefaultModel() {
    method getSelectedNames (line 95) | public String getSelectedNames() {
    method getNameByRowIndex (line 104) | private String getNameByRowIndex(int rowIndex) {
    method getShowPreviewByRowIndex (line 108) | private boolean getShowPreviewByRowIndex(int rowIndex) {
    method getRuntimeBehaviourByRowIndex (line 112) | private ERuntimeBehaviour getRuntimeBehaviourByRowIndex(int rowIndex) {
    method getGroupByRowIndex (line 116) | private String getGroupByRowIndex(int rowIndex) {
    method getCommandByRowIndex (line 120) | private String getCommandByRowIndex(int rowIndex) {
    method getPlaceholders (line 124) | private List<CommandObject.Placeholder> getPlaceholders(int rowIndex) {
    method getCommandObjects (line 133) | public List<CommandObject> getCommandObjects() {
    method getCommandObjectByRowIndex (line 141) | private CommandObject getCommandObjectByRowIndex(int rowIndex) {
    method getCommandObjectById (line 152) | public CommandObject getCommandObjectById(String commandId) {
    method addCommandObjects (line 167) | public void addCommandObjects(List<CommandObject> commandObjectList) {
    method addCommandObject (line 173) | public void addCommandObject(CommandObject commandObject) {
    method editSelectedCommandObject (line 185) | public void editSelectedCommandObject(CommandObject commandObject) {
    method editRow (line 192) | private void editRow(int rowIndex, CommandObject commandObject) {
    method editCommandObject (line 206) | public void editCommandObject(CommandObject commandObject) {
    method removeSelectedRow (line 216) | public void removeSelectedRow() {
    method clearTable (line 224) | public void clearTable() {
    method moveSelectedRowUp (line 230) | public void moveSelectedRowUp() {
    method moveSelectedRowDown (line 234) | public void moveSelectedRowDown() {
    method moveRowBy (line 238) | private void moveRowBy(int index) {
    method removeAll (line 252) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTableListener.java
  class SendToTableListener (line 13) | public class SendToTableListener implements TableModelListener {
    method SendToTableListener (line 17) | public SendToTableListener(SendToTable sendToTable) {
    method tableChanged (line 21) | @Override
    method onAddButtonClick (line 26) | public void onAddButtonClick(ActionEvent e, CommandObject commandObjec...
    method onEditButtonClick (line 30) | public void onEditButtonClick(ActionEvent e, CommandObject commandObje...
    method onRemoveButtonClick (line 34) | public void onRemoveButtonClick(ActionEvent e) {
    method onUpButtonClick (line 38) | public void onUpButtonClick(ActionEvent e) {
    method onDownButtonClick (line 42) | public void onDownButtonClick(ActionEvent e) {
    method onShowPreviewChange (line 46) | public void onShowPreviewChange(ActionEvent e, String commandId, boole...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/action/SendToContextMenuItemAction.java
  class SendToContextMenuItemAction (line 22) | public class SendToContextMenuItemAction extends AbstractAction {
    method SendToContextMenuItemAction (line 29) | public SendToContextMenuItemAction(String title, CommandObject command...
    method actionPerformed (line 36) | @Override
    method runCommandInBackground (line 63) | private void runCommandInBackground(String command) throws Exception {
    method runCommandInTerminal (line 67) | private void runCommandInTerminal(String command) throws Exception {
    method showSendToPreviewDialog (line 94) | private String showSendToPreviewDialog(String command) {
    method showSendToPreviewDialog (line 99) | private String showSendToPreviewDialog(String id, String command) thro...
    method stackTraceToString (line 112) | private String stackTraceToString(Exception e) {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/listener/ToolTipActionListener.java
  class ToolTipActionListener (line 7) | public class ToolTipActionListener implements ActionListener {
    method ToolTipActionListener (line 12) | public ToolTipActionListener(JComponent component, String toolTipText) {
    method actionPerformed (line 17) | @Override
    method getToolTipText (line 41) | public String getToolTipText() {
    method setToolTipText (line 45) | public void setToolTipText(String toolTipText) {
    method getComponent (line 49) | public JComponent getComponent() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/util/DialogUtil.java
  class DialogUtil (line 6) | public final class DialogUtil {
    method showErrorDialog (line 8) | public static void showErrorDialog(Component parent, String title, Str...
    method showConfirmationDialog (line 14) | public static boolean showConfirmationDialog(Component parent, String ...
    method getX (line 22) | public static int getX(Component parent, Component child) {
    method getY (line 30) | public static int getY(Component parent, Component child) {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/util/SelectionUtil.java
  class SelectionUtil (line 7) | public class SelectionUtil {
    method replaceSelectedText (line 9) | public static byte[] replaceSelectedText(byte[] message, int[] bounds,...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/util/WebUtil.java
  class WebUtil (line 8) | public class WebUtil {
    method openWebpage (line 10) | public static boolean openWebpage(URI uri) {
    method openWebpage (line 23) | public static boolean openWebpage(URL url) {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/CommandObject.java
  class CommandObject (line 14) | public class CommandObject {
    class Placeholder (line 25) | public static class Placeholder {
      method Placeholder (line 37) | public Placeholder(String placeholder, IPlaceholderBehaviour behavio...
      method getName (line 44) | public String getName() {
      method getStart (line 48) | public int getStart() {
      method getEnd (line 52) | public int getEnd() {
      method toString (line 56) | @Override
      method equals (line 66) | @Override
      method hashCode (line 74) | @Override
      method getBehaviour (line 79) | public IPlaceholderBehaviour getBehaviour() {
      method setBehaviour (line 83) | public void setBehaviour(IPlaceholderBehaviour behaviour) {
    method CommandObject (line 89) | public CommandObject(String name, String format, String group, ERuntim...
    method CommandObject (line 98) | public CommandObject(String id, String name, String format, String gro...
    method CommandObject (line 103) | public CommandObject(String name, String format, String group, ERuntim...
    method initPlaceholders (line 122) | private List<CommandObject.Placeholder> initPlaceholders(List<CommandO...
    method getId (line 139) | public String getId() { return this.id; }
    method getName (line 141) | public String getName() {
    method getFormat (line 145) | public String getFormat() {
    method getGroup (line 149) | public String getGroup() {
    method getRuntimeBehaviour (line 153) | public ERuntimeBehaviour getRuntimeBehaviour() {
    method shouldRunInTerminal (line 157) | public boolean shouldRunInTerminal() {
    method shouldOutputReplaceSelection (line 161) | public boolean shouldOutputReplaceSelection() {
    method shouldRunInBackground (line 165) | public boolean shouldRunInBackground() {
    method setShowPreview (line 169) | public void setShowPreview(boolean showPreview) {
    method shouldShowPreview (line 173) | public boolean shouldShowPreview() {
    method equals (line 177) | @Override
    method hashCode (line 185) | @Override
    method getValid (line 190) | public List<Map<String, IPlaceholderParser>> getValid(List<Map<String,...
    method isValid (line 200) | private boolean isValid(Map<String, IPlaceholderParser> placeholderMap...
    method doesRequireRequestResponse (line 211) | public boolean doesRequireRequestResponse(Map<String, IPlaceholderPars...
    method getPlaceholders (line 222) | public List<CommandObject.Placeholder> getPlaceholders() {
    method toString (line 231) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/Config.java
  class Config (line 18) | public class Config {
    method Config (line 25) | public Config(BurpExtender burpExtender) {
    method initGson (line 32) | private Gson initGson() {
    method saveSendToTableData (line 40) | public void saveSendToTableData(List<CommandObject> sendToTableData) {
    method getSendToTableData (line 45) | public List<CommandObject> getSendToTableData() {
    method initializeDefaultSendToTableData (line 64) | private List<CommandObject> initializeDefaultSendToTableData() {
    method getDefaultSendToTableData (line 71) | public List<CommandObject> getDefaultSendToTableData() {
    method refreshVersion (line 111) | private void refreshVersion() {
    method isFirstStart (line 118) | private boolean isFirstStart() {
    method setFirstStart (line 123) | private void setFirstStart() {
    method unsetFirstStart (line 127) | private void unsetFirstStart() {
    method setRunInTerminalBehaviour (line 131) | public void setRunInTerminalBehaviour(ERunInTerminalBehaviour runInTer...
    method getRunInTerminalBehaviour (line 135) | public ERunInTerminalBehaviour getRunInTerminalBehaviour() {
    method shouldShowRunInTerminalBehaviourChoiceDialog (line 143) | public boolean shouldShowRunInTerminalBehaviourChoiceDialog() {
    method shouldShowRunInTerminalBehaviourChoiceDialog (line 151) | public void shouldShowRunInTerminalBehaviourChoiceDialog(boolean statu...
    method getRunInTerminalCommand (line 155) | public String getRunInTerminalCommand() {
    method getRunInTerminalCommand (line 163) | private String getRunInTerminalCommand(String label, String defaultVal...
    method setRunInTerminalCommand (line 172) | public void setRunInTerminalCommand(String command) {
    method resetRunInTerminalCommand (line 180) | public void resetRunInTerminalCommand() {
    method setSafeMode (line 186) | public void setSafeMode(boolean status) {
    method isSafeModeActivated (line 190) | public boolean isSafeModeActivated() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/Context.java
  class Context (line 9) | public class Context {
    type Origin (line 13) | public enum Origin {
      method getTarget (line 16) | public static Origin getTarget(IContextMenuInvocation contextMenuInv...
    method Context (line 30) | public Context(Origin origin, IContextMenuInvocation invocation) {
    method Context (line 35) | public Context(IContextMenuInvocation invocation) {
    method getOrigin (line 39) | public Origin getOrigin() {
    method getSelectedMessages (line 47) | public IHttpRequestResponse[] getSelectedMessages() {
    method getSelectionBounds (line 51) | public int[] getSelectionBounds() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/ERunInTerminalBehaviour.java
  type ERunInTerminalBehaviour (line 3) | public enum ERunInTerminalBehaviour {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/ERuntimeBehaviour.java
  type ERuntimeBehaviour (line 3) | public enum ERuntimeBehaviour {
    method ERuntimeBehaviour (line 11) | ERuntimeBehaviour(String alternateName) {
    method alternateName (line 15) | public String alternateName() {
    method getEnum (line 19) | public static ERuntimeBehaviour getEnum(String name) {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/Placeholders.java
  class Placeholders (line 16) | public class Placeholders {
    method get (line 18) | public static List<AbstractPlaceholder> get() {
    method get (line 40) | public static List<Map<String, IPlaceholderParser>> get(IBurpExtenderC...
    method get (line 57) | public static List<CommandObject.Placeholder> get(String format) {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractPlaceholder.java
  class AbstractPlaceholder (line 5) | public abstract class AbstractPlaceholder implements IPlaceholder, IPlac...
    method AbstractPlaceholder (line 11) | public AbstractPlaceholder(String placeholder, boolean doesRequireShel...
    method getPlaceholder (line 17) | public String getPlaceholder() {
    method doesRequireShellEscape (line 24) | public boolean doesRequireShellEscape() {
    method shouldWriteToFile (line 29) | public boolean shouldWriteToFile() {
    method createParser (line 33) | public abstract IPlaceholderParser createParser(RequestResponseHolder ...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestInfoPlaceholder.java
  class AbstractRequestInfoPlaceholder (line 9) | public abstract class AbstractRequestInfoPlaceholder extends AbstractReq...
    method AbstractRequestInfoPlaceholder (line 13) | public AbstractRequestInfoPlaceholder(IPlaceholder placeholder, Reques...
    method getRequestInfo (line 18) | protected IRequestInfoWrapper getRequestInfo() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestPlaceholder.java
  class AbstractRequestPlaceholder (line 6) | public abstract class AbstractRequestPlaceholder extends AbstractRequest...
    method AbstractRequestPlaceholder (line 10) | public AbstractRequestPlaceholder(IPlaceholder placeholder, RequestRes...
    method getHttpRequestResponse (line 15) | protected IHttpRequestResponse getHttpRequestResponse() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestResponseInfoPlaceholder.java
  class AbstractRequestResponseInfoPlaceholder (line 10) | public abstract class AbstractRequestResponseInfoPlaceholder extends Abs...
    method AbstractRequestResponseInfoPlaceholder (line 14) | public AbstractRequestResponseInfoPlaceholder(IPlaceholder placeholder...
    method getRequestInfo (line 19) | protected IRequestInfoWrapper getRequestInfo() {
    method getResponseInfo (line 23) | protected IResponseInfoWrapper getResponseInfo() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestResponsePlaceholder.java
  class AbstractRequestResponsePlaceholder (line 6) | public abstract class AbstractRequestResponsePlaceholder extends Abstrac...
    method AbstractRequestResponsePlaceholder (line 10) | public AbstractRequestResponsePlaceholder(IPlaceholder placeholder, Re...
    method getRequestResponseAsByteArray (line 15) | protected byte[] getRequestResponseAsByteArray(Context context) {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestResponsePlaceholderBase.java
  class AbstractRequestResponsePlaceholderBase (line 11) | public abstract class AbstractRequestResponsePlaceholderBase implements ...
    method AbstractRequestResponsePlaceholderBase (line 16) | public AbstractRequestResponsePlaceholderBase(IPlaceholder placeholder...
    method getPlaceholder (line 21) | public String getPlaceholder() {
    method doesRequireShellEscape (line 25) | public boolean doesRequireShellEscape() {
    method shouldWriteToFile (line 29) | public boolean shouldWriteToFile() { return placeholder.shouldWriteToF...
    method getInternalValue (line 36) | @Nullable
    method getValue (line 39) | @Override
    method writeToFile (line 56) | private String writeToFile(String value) throws Exception {
    method isValid (line 68) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/CookiesPlaceholder.java
  class CookiesPlaceholder (line 12) | public class CookiesPlaceholder extends AbstractPlaceholder {
    method CookiesPlaceholder (line 14) | public CookiesPlaceholder() {
    method createParser (line 18) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HostPlaceholder.java
  class HostPlaceholder (line 8) | public class HostPlaceholder extends AbstractPlaceholder {
    method HostPlaceholder (line 10) | public HostPlaceholder() {
    method createParser (line 14) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpBodyToFilePlaceholder.java
  class HttpBodyToFilePlaceholder (line 8) | public class HttpBodyToFilePlaceholder extends AbstractPlaceholder {
    method HttpBodyToFilePlaceholder (line 10) | public HttpBodyToFilePlaceholder() {
    method createParser (line 14) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpContentLengthPlaceholder.java
  class HttpContentLengthPlaceholder (line 8) | public class HttpContentLengthPlaceholder extends AbstractPlaceholder {
    method HttpContentLengthPlaceholder (line 10) | public HttpContentLengthPlaceholder() {
    method createParser (line 14) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpHeadersToFilePlaceholder.java
  class HttpHeadersToFilePlaceholder (line 10) | public class HttpHeadersToFilePlaceholder extends AbstractPlaceholder {
    method HttpHeadersToFilePlaceholder (line 12) | public HttpHeadersToFilePlaceholder() {
    method createParser (line 16) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpMethodPlaceholder.java
  class HttpMethodPlaceholder (line 8) | public class HttpMethodPlaceholder extends AbstractPlaceholder {
    method HttpMethodPlaceholder (line 10) | public HttpMethodPlaceholder() {
    method createParser (line 14) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpRequestResponsePlaceholder.java
  class HttpRequestResponsePlaceholder (line 8) | public class HttpRequestResponsePlaceholder extends AbstractPlaceholder {
    method HttpRequestResponsePlaceholder (line 10) | public HttpRequestResponsePlaceholder() {
    method createParser (line 14) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpStatusCodePlaceholder.java
  class HttpStatusCodePlaceholder (line 8) | public class HttpStatusCodePlaceholder extends AbstractPlaceholder {
    method HttpStatusCodePlaceholder (line 10) | public HttpStatusCodePlaceholder() {
    method createParser (line 14) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/IPlaceholder.java
  type IPlaceholder (line 3) | public interface IPlaceholder {
    method getPlaceholder (line 5) | String getPlaceholder();
    method doesRequireShellEscape (line 7) | boolean doesRequireShellEscape();
    method shouldWriteToFile (line 9) | boolean shouldWriteToFile();

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/IPlaceholderParser.java
  type IPlaceholderParser (line 5) | public interface IPlaceholderParser extends IPlaceholder {
    method getValue (line 7) | String getValue(Context context) throws RuntimeException;
    method isValid (line 9) | boolean isValid(Context context);

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/IPlaceholderParserFactory.java
  type IPlaceholderParserFactory (line 5) | public interface IPlaceholderParserFactory {
    method createParser (line 7) | IPlaceholderParser createParser(RequestResponseHolder requestResponseH...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/PortPlaceholder.java
  class PortPlaceholder (line 8) | public class PortPlaceholder extends AbstractPlaceholder {
    method PortPlaceholder (line 10) | public PortPlaceholder() {
    method createParser (line 14) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/ProtocolPlaceholder.java
  class ProtocolPlaceholder (line 8) | public class ProtocolPlaceholder extends AbstractPlaceholder {
    method ProtocolPlaceholder (line 10) | public ProtocolPlaceholder() {
    method createParser (line 14) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/SelectedTextPlaceholder.java
  class SelectedTextPlaceholder (line 8) | public class SelectedTextPlaceholder extends AbstractPlaceholder {
    method SelectedTextPlaceholder (line 10) | public SelectedTextPlaceholder() {
    method SelectedTextPlaceholder (line 14) | protected SelectedTextPlaceholder(String placeholder, boolean doShellE...
    method createParser (line 18) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/SelectedTextToFilePlaceholder.java
  class SelectedTextToFilePlaceholder (line 3) | public class SelectedTextToFilePlaceholder extends SelectedTextPlacehold...
    method SelectedTextToFilePlaceholder (line 5) | public SelectedTextToFilePlaceholder() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/UrlPathPlaceholder.java
  class UrlPathPlaceholder (line 10) | public class UrlPathPlaceholder extends AbstractPlaceholder {
    method UrlPathPlaceholder (line 12) | public UrlPathPlaceholder() {
    method createParser (line 16) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/UrlPlaceholder.java
  class UrlPlaceholder (line 9) | public class UrlPlaceholder extends AbstractPlaceholder {
    method UrlPlaceholder (line 11) | public UrlPlaceholder() {
    method createParser (line 15) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/UrlQueryPlaceholder.java
  class UrlQueryPlaceholder (line 10) | public class UrlQueryPlaceholder extends AbstractPlaceholder {
    method UrlQueryPlaceholder (line 12) | public UrlQueryPlaceholder() {
    method createParser (line 16) | @Override

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/behaviour/CommandSeparatedPlaceholderBehaviour.java
  class CommandSeparatedPlaceholderBehaviour (line 3) | public class CommandSeparatedPlaceholderBehaviour implements IPlaceholde...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/behaviour/FileSeparatedPlaceholderBehaviour.java
  class FileSeparatedPlaceholderBehaviour (line 3) | public class FileSeparatedPlaceholderBehaviour implements IPlaceholderBe...

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/behaviour/IPlaceholderBehaviour.java
  type IPlaceholderBehaviour (line 3) | public interface IPlaceholderBehaviour {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/behaviour/StringSeparatedPlaceholderBehaviour.java
  class StringSeparatedPlaceholderBehaviour (line 3) | public class StringSeparatedPlaceholderBehaviour implements IPlaceholder...
    method StringSeparatedPlaceholderBehaviour (line 7) | public StringSeparatedPlaceholderBehaviour(String separator) {
    method getSeparator (line 11) | public String getSeparator() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/utils/OsUtils.java
  class OsUtils (line 3) | public final class OsUtils {
    method getOsName (line 7) | public static String getOsName() {
    method isWindows (line 14) | public static boolean isWindows() {
    method isUnix (line 18) | public static boolean isUnix() {

FILE: burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/utils/StringUtils.java
  class StringUtils (line 11) | public class StringUtils {
    method shellEscape (line 20) | public static String shellEscape(String command) {
    method fromInputStream (line 24) | public static String fromInputStream(InputStream inputStream) throws I...
Condensed preview — 80 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (272K chars).
[
  {
    "path": ".gitignore",
    "chars": 116,
    "preview": "burp-send-to-extension/.idea\nburp-send-to-extension/.gradle\nburp-send-to-extension/build\nburp-send-to-extension/out\n"
  },
  {
    "path": "BappDescription.html",
    "chars": 4401,
    "preview": "<p>Adds a customizable \"Send to...\"-context-menu to your BurpSuite.</p>\n\n<p><b>Configuration</b></p>\n\n<p>After loading t"
  },
  {
    "path": "BappManifest.bmf",
    "chars": 406,
    "preview": "Uuid: f089f1ad056545489139cb9f32900f8e\nExtensionType: 1\nName: Custom Send To\nRepoName: custom-send-to\nScreenVersion: 1.4"
  },
  {
    "path": "README.md",
    "chars": 5687,
    "preview": "# Burp-Send-To-Extension\n\nAdds a customizable \"Send to...\"-context-menu to your BurpSuite.\n\n![Burp-Send-To-Extension Tab"
  },
  {
    "path": "burp-send-to-extension/build.gradle",
    "chars": 620,
    "preview": "apply plugin: 'java'\n\ngroup 'net.bytebutcher'\nversion '1.6'\n\nsourceCompatibility = 1.8\n\nrepositories {\n    mavenCentral("
  },
  {
    "path": "burp-send-to-extension/gradle/wrapper/gradle-wrapper.properties",
    "chars": 231,
    "preview": "#Sun Mar 17 11:46:47 CET 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "burp-send-to-extension/gradlew",
    "chars": 5296,
    "preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up"
  },
  {
    "path": "burp-send-to-extension/gradlew.bat",
    "chars": 2260,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
  },
  {
    "path": "burp-send-to-extension/settings.gradle",
    "chars": 45,
    "preview": "rootProject.name = 'burp-send-to-extension'\n\n"
  },
  {
    "path": "burp-send-to-extension/src/main/java/burp/BurpExtender.java",
    "chars": 3132,
    "preview": "package burp;\n\nimport net.bytebutcher.burpsendtoextension.gui.SendToContextMenu;\nimport net.bytebutcher.burpsendtoextens"
  },
  {
    "path": "burp-send-to-extension/src/main/java/burp/Cookie.java",
    "chars": 7811,
    "preview": "package burp;\n\nimport com.google.common.collect.Lists;\n\nimport java.text.SimpleDateFormat;\nimport java.util.*;\nimport ja"
  },
  {
    "path": "burp-send-to-extension/src/main/java/burp/IRequestInfoWrapper.java",
    "chars": 157,
    "preview": "package burp;\n\nimport java.util.List;\n\npublic interface IRequestInfoWrapper extends IRequestInfo {\n\n    List<ICookie> ge"
  },
  {
    "path": "burp-send-to-extension/src/main/java/burp/IRequestResponseHolder.java",
    "chars": 240,
    "preview": "package burp;\n\npublic interface IRequestResponseHolder {\n    IRequestInfo getRequestInfo();\n\n    IResponseInfo getRespon"
  },
  {
    "path": "burp-send-to-extension/src/main/java/burp/IResponseInfoWrapper.java",
    "chars": 159,
    "preview": "package burp;\n\nimport java.util.List;\n\npublic interface IResponseInfoWrapper extends IResponseInfo {\n\n    List<ICookie> "
  },
  {
    "path": "burp-send-to-extension/src/main/java/burp/RequestInfoWrapper.java",
    "chars": 1879,
    "preview": "package burp;\n\nimport java.net.URL;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Collectors;\n"
  },
  {
    "path": "burp-send-to-extension/src/main/java/burp/RequestResponseHolder.java",
    "chars": 1436,
    "preview": "package burp;\n\npublic class RequestResponseHolder implements IRequestResponseHolder {\n\n    private final IBurpExtenderCa"
  },
  {
    "path": "burp-send-to-extension/src/main/java/burp/ResponseInfoWrapper.java",
    "chars": 1819,
    "preview": "package burp;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\npublic class Respons"
  },
  {
    "path": "burp-send-to-extension/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java",
    "chars": 10090,
    "preview": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/builder/CommandBuilder.java",
    "chars": 7205,
    "preview": "package net.bytebutcher.burpsendtoextension.builder;\n\nimport com.google.common.collect.Lists;\nimport com.google.common.c"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/executioner/CommandExecutioner.java",
    "chars": 5253,
    "preview": "package net.bytebutcher.burpsendtoextension.executioner;\n\nimport burp.BurpExtender;\nimport burp.IHttpRequestResponse;\nim"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/CommandsChangeListener.java",
    "chars": 257,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\r\n\r\nimport net.bytebutcher.burpsendtoextension.models.CommandObject;\r\n\r\n"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedDialog.form",
    "chars": 5162,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<form xmlns=\"http://www.intellij.com/uidesigner/form/\" version=\"1\" bind-to-class="
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedDialog.java",
    "chars": 7291,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport com.google.common.collect.Lists;\nimport com.intellij.uiDesigner"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedPlaceholderBehaviourPanel.form",
    "chars": 1916,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<form xmlns=\"http://www.intellij.com/uidesigner/form/\" version=\"1\" bind-to-class="
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddAdvancedPlaceholderBehaviourPanel.java",
    "chars": 5031,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport burp.BurpExtender;\nimport com.intellij.uiDesigner.core.GridCons"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddDialog.form",
    "chars": 9812,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<form xmlns=\"http://www.intellij.com/uidesigner/form/\" version=\"1\" bind-to-class="
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToAddDialog.java",
    "chars": 17067,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport burp.BurpExtender;\nimport com.google.common.collect.Lists;\nimpo"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToContextMenu.java",
    "chars": 3714,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport burp.BurpExtender;\nimport burp.IContextMenuFactory;\nimport burp"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToContextMenuItem.java",
    "chars": 1547,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport net.bytebutcher.burpsendtoextension.gui.action.SendToContextMen"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToPreviewDialog.form",
    "chars": 3707,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<form xmlns=\"http://www.intellij.com/uidesigner/form/\" version=\"1\" bind-to-class="
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToPreviewDialog.java",
    "chars": 7089,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport com.intellij.uiDesigner.core.GridConstraints;\nimport com.intell"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToRunInTerminalBehaviourChoiceDialog.form",
    "chars": 5801,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<form xmlns=\"http://www.intellij.com/uidesigner/form/\" version=\"1\" bind-to-class="
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToRunInTerminalBehaviourChoiceDialog.java",
    "chars": 8961,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport com.intellij.uiDesigner.core.GridConstraints;\nimport com.intell"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTab.form",
    "chars": 17547,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<form xmlns=\"http://www.intellij.com/uidesigner/form/\" version=\"1\" bind-to-class="
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTab.java",
    "chars": 22998,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport burp.BurpExtender;\nimport com.intellij.uiDesigner.core.GridCons"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTabSettingsContextMenu.java",
    "chars": 5499,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport burp.BurpExtender;\nimport com.google.gson.Gson;\nimport com.goog"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTable.java",
    "chars": 9810,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport burp.BurpExtender;\nimport com.google.common.collect.Lists;\nimpo"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/SendToTableListener.java",
    "chars": 1580,
    "preview": "package net.bytebutcher.burpsendtoextension.gui;\n\nimport burp.BurpExtender;\nimport net.bytebutcher.burpsendtoextension.m"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/action/SendToContextMenuItemAction.java",
    "chars": 5494,
    "preview": "package net.bytebutcher.burpsendtoextension.gui.action;\n\nimport burp.BurpExtender;\nimport net.bytebutcher.burpsendtoexte"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/listener/ToolTipActionListener.java",
    "chars": 1581,
    "preview": "package net.bytebutcher.burpsendtoextension.gui.listener;\n\nimport javax.swing.*;\nimport java.awt.event.ActionEvent;\nimpo"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/util/DialogUtil.java",
    "chars": 1481,
    "preview": "package net.bytebutcher.burpsendtoextension.gui.util;\r\n\r\nimport javax.swing.*;\r\nimport java.awt.*;\r\n\r\npublic final class"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/util/SelectionUtil.java",
    "chars": 656,
    "preview": "package net.bytebutcher.burpsendtoextension.gui.util;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/gui/util/WebUtil.java",
    "chars": 862,
    "preview": "package net.bytebutcher.burpsendtoextension.gui.util;\r\n\r\nimport java.awt.*;\r\nimport java.net.URI;\r\nimport java.net.URISy"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/CommandObject.java",
    "chars": 9371,
    "preview": "package net.bytebutcher.burpsendtoextension.models;\n\nimport burp.BurpExtender;\nimport com.google.common.collect.Lists;\ni"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/Config.java",
    "chars": 10202,
    "preview": "package net.bytebutcher.burpsendtoextension.models;\n\nimport burp.BurpExtender;\nimport burp.IBurpExtenderCallbacks;\nimpor"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/Context.java",
    "chars": 1961,
    "preview": "package net.bytebutcher.burpsendtoextension.models;\n\nimport burp.IContextMenuInvocation;\nimport burp.IHttpRequestRespons"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/ERunInTerminalBehaviour.java",
    "chars": 151,
    "preview": "package net.bytebutcher.burpsendtoextension.models;\n\npublic enum ERunInTerminalBehaviour {\n    RUN_IN_SEPARATE_TERMINALS"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/ERuntimeBehaviour.java",
    "chars": 773,
    "preview": "package net.bytebutcher.burpsendtoextension.models;\n\npublic enum ERuntimeBehaviour {\n\n    RUN_IN_BACKGROUND(\"Run in Back"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/Placeholders.java",
    "chars": 3037,
    "preview": "package net.bytebutcher.burpsendtoextension.models;\n\nimport burp.IBurpExtenderCallbacks;\nimport burp.IHttpRequestRespons"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractPlaceholder.java",
    "chars": 1031,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\n\npublic abstract cla"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestInfoPlaceholder.java",
    "chars": 731,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.IRequestInfoWrapper;\nimport burp.RequestRes"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestPlaceholder.java",
    "chars": 660,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.IHttpRequestResponse;\nimport burp.RequestRe"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestResponseInfoPlaceholder.java",
    "chars": 898,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.IRequestInfoWrapper;\nimport burp.IResponseI"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestResponsePlaceholder.java",
    "chars": 947,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/AbstractRequestResponsePlaceholderBase.java",
    "chars": 2768,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/CookiesPlaceholder.java",
    "chars": 1350,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.ICookie;\nimport burp.RequestResponseHolder;"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HostPlaceholder.java",
    "chars": 728,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpBodyToFilePlaceholder.java",
    "chars": 973,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpContentLengthPlaceholder.java",
    "chars": 1114,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpHeadersToFilePlaceholder.java",
    "chars": 1244,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport com.google.co"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpMethodPlaceholder.java",
    "chars": 719,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpRequestResponsePlaceholder.java",
    "chars": 854,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/HttpStatusCodePlaceholder.java",
    "chars": 960,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/IPlaceholder.java",
    "chars": 202,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\npublic interface IPlaceholder {\n\n    String getPlacehol"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/IPlaceholderParser.java",
    "chars": 289,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport net.bytebutcher.burpsendtoextension.models.Conte"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/IPlaceholderParserFactory.java",
    "chars": 232,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\n\npublic interface IP"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/PortPlaceholder.java",
    "chars": 743,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/ProtocolPlaceholder.java",
    "chars": 738,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/SelectedTextPlaceholder.java",
    "chars": 1488,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/SelectedTextToFilePlaceholder.java",
    "chars": 231,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\npublic class SelectedTextToFilePlaceholder extends Sele"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/UrlPathPlaceholder.java",
    "chars": 810,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/UrlPlaceholder.java",
    "chars": 746,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/UrlQueryPlaceholder.java",
    "chars": 813,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder;\n\nimport burp.RequestResponseHolder;\nimport net.bytebutch"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/behaviour/CommandSeparatedPlaceholderBehaviour.java",
    "chars": 163,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder.behaviour;\n\npublic class CommandSeparatedPlaceholderBehav"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/behaviour/FileSeparatedPlaceholderBehaviour.java",
    "chars": 160,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder.behaviour;\n\npublic class FileSeparatedPlaceholderBehaviou"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/behaviour/IPlaceholderBehaviour.java",
    "chars": 119,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder.behaviour;\n\npublic interface IPlaceholderBehaviour {\n\n}\n"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/models/placeholder/behaviour/StringSeparatedPlaceholderBehaviour.java",
    "chars": 376,
    "preview": "package net.bytebutcher.burpsendtoextension.models.placeholder.behaviour;\n\npublic class StringSeparatedPlaceholderBehavi"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/utils/OsUtils.java",
    "chars": 460,
    "preview": "package net.bytebutcher.burpsendtoextension.utils;\r\n\r\npublic final class OsUtils {\r\n\r\n    private static String OS = nul"
  },
  {
    "path": "burp-send-to-extension/src/main/java/net/bytebutcher/burpsendtoextension/utils/StringUtils.java",
    "chars": 783,
    "preview": "package net.bytebutcher.burpsendtoextension.utils;\n\nimport com.google.common.escape.Escaper;\nimport com.google.common.es"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the bytebutcher/burp-send-to GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 80 files (246.0 KB), approximately 60.3k tokens, and a symbol index with 417 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!