# -*- coding: binary -*-
require 'msf/ui/console/command_dispatcher'
require 'msf/ui/console/module_argument_parsing'

module Msf
module Ui
module Console

###
#
# A mixin to enable the ModuleCommandDispatcher to leverage module ACTIONs as commands.
#
###
module ModuleActionCommands
  include Msf::Ui::Console::ModuleArgumentParsing

  #
  # Returns the hash of commands specific to auxiliary modules.
  #
  def action_commands
    return {} unless mod.respond_to?(:actions)

    mod.actions.map { |action| [action.name.downcase, action.description] }.to_h
  end

  def commands
    super.merge(action_commands) { |k, old_val, new_val| old_val}
  end

  #
  # Allow modules to define their own commands
  # Note: A change to this method will most likely require a corresponding change to respond_to_missing?
  #
  def method_missing(meth, *args)
    if mod && mod.respond_to?(meth.to_s, true)

      # Initialize user interaction
      mod.init_ui(driver.input, driver.output)

      return mod.send(meth.to_s, *args)
    end

    action = meth.to_s.delete_prefix('cmd_').delete_suffix('_tabs')
    if mod && mod.kind_of?(Msf::Module::HasActions) && mod.actions.map(&:name).any? { |a| a.casecmp?(action) }
      return cmd_run_tabs(*args) if meth.end_with?('_tabs')
      return do_action(action, *args)
    end

    super
  end

  #
  # Note: A change to this method will most likely require a corresponding change to method_missing
  #
  def respond_to_missing?(meth, _include_private = true)
    if mod && mod.respond_to?(meth.to_s, true)
      return true
    end

    action = meth.to_s.delete_prefix('cmd_').delete_suffix('_tabs')
    if mod && mod.kind_of?(Msf::Module::HasActions) && mod.actions.map(&:name).any? { |a| a.casecmp?(action) }
      return true
    end

    super
  end

  #
  # Execute the module with a set action
  #
  def do_action(meth, *args)
    action = mod.actions.find { |action| action.name.casecmp?(meth) }
    raise Msf::MissingActionError.new(meth) if action.nil?

    cmd_run(*args, action: action.name)
  end

  def cmd_action_help(action)
    print_module_run_or_check_usage(command: action.downcase, description: 'Launches a specific module action')
  end

  #
  # Tab completion for the run command
  #
  # @param str [String] the string currently being typed before tab was hit
  # @param words [Array<String>] the previously completed words on the command line.  words is always
  # at least 1 when tab completion has reached this stage since the command itself has been completed
  #
  def cmd_run_tabs(str, words)
    flags = @@module_opts_with_action_support.option_keys
    options = tab_complete_option(active_module, str, words)
    flags + options
  end

end
end
end
end
