module Rex
module IO

require 'rex/ui/text/output'
require 'rex/ui/text/output/buffer'
require 'rex/ui/text/input/buffer'

class BidirectionalPipe < Rex::Ui::Text::Input

	def initialize
		@subscribers_out = {}
		@subscribers_ref = {}
		@subscribers_idx = 0
		@pipe_input = Rex::Ui::Text::Input::Buffer.new

		# We are the shell, the input, and the output
		self.output = self
		self.input  = self
	end

	def pipe_input
		@pipe_input
	end

	def close
		@pipe_input.close
	end

	def has_subscriber?(id)
		@subscribers_out.has_key?(id)
	end

	def create_subscriber(id=nil)
		id ||= (@subscribers_idx += 1).to_s
		@subscribers_out[id] = Rex::Ui::Text::Output::Buffer.new
		return id
	end

	def create_subscriber_proc(id=nil, &block)
		id = create_subscriber(id)
		@subscribers_ref[id] = block
	end

	def remove_subscriber(id)
		@subscribers_out.delete(id)
		@subscribers_ref.delete(id)
	end

	def write_input(buf)
		@pipe_input.put(buf)
	end

	def read_subscriber(id)
		output = @subscribers_out[id]

		return '' if output.nil?

		buf = output.buf

		output.reset

		buf
	end

	def print(msg='')
		@subscribers_out.each_pair { |id, buf|
			begin
				@subscribers_ref[id] ? @subscribers_ref[id].call(msg) : buf.print(msg)
			rescue ::Exception => e
				# $stderr.puts "Error handling subscriber #{id}: #{e} #{e.backtrace.inspect}"
				raise e
			end
		}
		msg
	end

	def print_error(msg='')
		print_line('[-] ' + msg)
	end

	def print_line(msg='')
		print(msg + "\n")
	end

	def print_good(msg='')
		print_line('[+] ' + msg)
	end

	def print_debug(msg='')
		print_line('[!] ' + msg)
	end

	def flush
	end

	def print_status(msg='')
		print_line('[*] ' + msg)
	end

	#
	# Wrappers for the pipe_input methods
	#

	def close
		@pipe_input.close
	end

	def sysread(len = 1)
		@pipe_input.sysread(len)
	end

	def put(msg)
		@pipe_input.put(msg)
	end

	def gets
		@pipe_input.gets
	end

	def eof?
		@pipe_input.eof?
	end

	def fd
		@pipe_input.fd
	end

	#
	# Wrappers for shell methods
	#

	attr_accessor :output, :prompt, :input

	def intrinsic_shell?
		true
	end

	def supports_readline
		false
	end

	def supports_color?
		false
	end

	def pgets
		gets
	end


protected

end

end
end

