# -*- coding: binary -*-
require 'rex/ui/text/bidirectional_pipe'
module Msf
module Ui
module Web

###
#
# This class implements a console instance for use by the web interface
#
###

class WebConsole
  attr_accessor :pipe
  attr_accessor :console
  attr_accessor :console_id
  attr_accessor :last_access
  attr_accessor :framework
  attr_accessor :thread

  # Wrapper class in case we need to extend the pipe
  class WebConsolePipe < Rex::Ui::Text::BidirectionalPipe
    def prompting?
      false
    end
  end

  #
  # Provides some overrides for web-based consoles
  #
  module WebConsoleShell

    def supports_color?
      false
    end
  end

  def initialize(framework, console_id, opts={})
    # Configure the framework
    self.framework = framework

    # Configure the ID
    self.console_id = console_id

    # Create a new pipe
    self.pipe = WebConsolePipe.new

    # Create a read subscriber
    self.pipe.create_subscriber('msfweb')

    # Skip database initialization if it is already configured
    if framework.db and framework.db.usable and framework.db.migrated
      opts['SkipDatabaseInit'] = true
    end

    # Initialize the console with our pipe
    self.console = Msf::Ui::Console::Driver.new(
      'msf',
      '>',
      opts.merge({
        'Framework'   => self.framework,
        'LocalInput'  => self.pipe,
        'LocalOutput' => self.pipe,
        'AllowCommandPassthru' => true,
        'Resource'    => [],
      })
    )

    self.console.extend(WebConsoleShell)
    self.console.block_command('irb')

    self.thread = framework.threads.spawn("WebConsoleShell", false) { self.console.run }

    update_access()
  end

  def update_access
    self.last_access = Time.now
  end

  def read
    update_access
    self.pipe.read_subscriber('msfweb')
  end

  def write(buf)
    update_access
    self.pipe.write_input(buf)
  end

  def execute(cmd)
    self.console.run_single(cmd)
  end

  def prompt
    self.pipe.prompt
  end

  def tab_complete(cmd)
    if(self.console.active_session)
      return self.console.active_session.console.tab_complete(cmd)
    end
    self.console.tab_complete(cmd)
  end

  def shutdown
    self.pipe.close
    self.thread.kill
  end

  def busy
    self.console.busy
  end

  def session_detach
    if(self.console.active_session)
      #background interactive meterpreter channel
      if(self.console.active_session.respond_to?('channels'))
        self.console.active_session.channels.each_value do |ch|
          if(ch.respond_to?('interacting') && ch.interacting)
            ch.detach()
            return
          end
        end
      end
      #background session
      self.console.active_session.completed = true
      self.console.active_session.detach()
    end
  end

  def session_kill
    self.thread.raise(Interrupt)
  end

  def active_module
    self.console.active_module
  end

  def active_module=(val)
    self.console.active_module = val
  end

end


end
end
end

